Commit c135dfbf authored by Than McIntosh's avatar Than McIntosh

debug/dwarf: more graceful handling of unsupported types

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/+/158797Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 6e63b155
// 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;
}
...@@ -261,6 +261,20 @@ func (t *TypedefType) String() string { return t.Name } ...@@ -261,6 +261,20 @@ func (t *TypedefType) String() string { return t.Name }
func (t *TypedefType) Size() int64 { return t.Type.Size() } 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 // typeReader is used to read from either the info section or the
// types section. // types section.
type typeReader interface { type typeReader interface {
...@@ -680,6 +694,16 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off ...@@ -680,6 +694,16 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
typ = t typ = t
typeCache[off] = t typeCache[off] = t
t.Name, _ = e.Val(AttrName).(string) 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 { if err != nil {
......
...@@ -9,6 +9,8 @@ import ( ...@@ -9,6 +9,8 @@ import (
"debug/elf" "debug/elf"
"debug/macho" "debug/macho"
"debug/pe" "debug/pe"
"fmt"
"strconv"
"testing" "testing"
) )
...@@ -168,3 +170,61 @@ func TestTypedefCycle(t *testing.T) { ...@@ -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)
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment