Skip to content

Commit

Permalink
debug/dwarf: more graceful handling of unsupported types
Browse files Browse the repository at this point in the history
Enhance the type decoder to do a better job handling unknown type
tags. DWARF has a number of type DIEs that this package doesn't handle
(things like "pointer to member" types in C++); avoid crashing for
such types, but instead return a placeholder "UnsupportedType" object
(this idea suggested by Austin). This provides a compromise between
implementing the entire kitchen sink and simply returning an error
outright on any unknown type DIE.

Fixes #29601.

Change-Id: I2eeffa094c86ef3a2c358ee42e8e629d74cec2ed
Reviewed-on: https://go-review.googlesource.com/c/go/+/158797
Reviewed-by: Brad Fitzpatrick <[email protected]>
Run-TryBot: Brad Fitzpatrick <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
  • Loading branch information
thanm committed Mar 15, 2019
1 parent 6e63b15 commit c135dfb
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 0 deletions.
34 changes: 34 additions & 0 deletions src/debug/dwarf/testdata/cppunsuptypes.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// cppunsuptypes.elf built with g++ 7.3
// g++ -g -c -o cppunsuptypes.elf cppunsuptypes.cc

int i = 3;
double d = 3;

// anonymous reference type
int &culprit = i;

// named reference type
typedef double &dref;
dref dr = d;

// incorporated into another type
typedef struct {
dref q;
int &r;
} hasrefs;

hasrefs hr = { d, i };

// This code is intended to trigger a DWARF "pointer to member" type DIE
struct CS { int dm; };

int foo()
{
int CS::* pdm = &CS::dm;
CS cs = {42};
return cs.*pdm;
}
Binary file added src/debug/dwarf/testdata/cppunsuptypes.elf
Binary file not shown.
24 changes: 24 additions & 0 deletions src/debug/dwarf/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,20 @@ func (t *TypedefType) String() string { return t.Name }

func (t *TypedefType) Size() int64 { return t.Type.Size() }

// An UnsupportedType is a placeholder returned in situations where we
// encounter a type that isn't supported.
type UnsupportedType struct {
CommonType
Tag Tag
}

func (t *UnsupportedType) String() string {
if t.Name != "" {
return t.Name
}
return t.Name + "(unsupported type " + t.Tag.String() + ")"
}

// typeReader is used to read from either the info section or the
// types section.
type typeReader interface {
Expand Down Expand Up @@ -680,6 +694,16 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
typ = t
typeCache[off] = t
t.Name, _ = e.Val(AttrName).(string)

default:
// This is some other type DIE that we're currently not
// equipped to handle. Return an abstract "unsupported type"
// object in such cases.
t := new(UnsupportedType)
typ = t
typeCache[off] = t
t.Tag = e.Tag
t.Name, _ = e.Val(AttrName).(string)
}

if err != nil {
Expand Down
60 changes: 60 additions & 0 deletions src/debug/dwarf/type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"debug/elf"
"debug/macho"
"debug/pe"
"fmt"
"strconv"
"testing"
)

Expand Down Expand Up @@ -168,3 +170,61 @@ func TestTypedefCycle(t *testing.T) {
}
}
}

var unsupportedTypeTests = []string{
// varname:typename:string:size
"culprit::(unsupported type ReferenceType):8",
"pdm::(unsupported type PtrToMemberType):-1",
}

func TestUnsupportedTypes(t *testing.T) {
// Issue 29601:
// When reading DWARF from C++ load modules, we can encounter
// oddball type DIEs. These will be returned as "UnsupportedType"
// objects; check to make sure this works properly.
d := elfData(t, "testdata/cppunsuptypes.elf")
r := d.Reader()
seen := make(map[string]bool)
for {
e, err := r.Next()
if err != nil {
t.Fatal("r.Next:", err)
}
if e == nil {
break
}
if e.Tag == TagVariable {
vname, _ := e.Val(AttrName).(string)
tAttr := e.Val(AttrType)
typOff, ok := tAttr.(Offset)
if !ok {
t.Errorf("variable at offset %v has no type", e.Offset)
continue
}
typ, err := d.Type(typOff)
if err != nil {
t.Errorf("err in type decode: %v\n", err)
continue
}
unsup, isok := typ.(*UnsupportedType)
if !isok {
continue
}
tag := vname + ":" + unsup.Name + ":" + unsup.String() +
":" + strconv.FormatInt(unsup.Size(), 10)
seen[tag] = true
}
}
dumpseen := false
for _, v := range unsupportedTypeTests {
if !seen[v] {
t.Errorf("missing %s", v)
dumpseen = true
}
}
if dumpseen {
for k, _ := range seen {
fmt.Printf("seen: %s\n", k)
}
}
}

0 comments on commit c135dfb

Please sign in to comment.