return s
}
-func dotypedef(ctxt *Link, parent *dwarf.DWDie, name string, def *dwarf.DWDie) {
+func dotypedef(ctxt *Link, parent *dwarf.DWDie, name string, def *dwarf.DWDie) *dwarf.DWDie {
// Only emit typedefs for real names.
if strings.HasPrefix(name, "map[") {
- return
+ return nil
}
if strings.HasPrefix(name, "struct {") {
- return
+ return nil
}
if strings.HasPrefix(name, "chan ") {
- return
+ return nil
}
if name[0] == '[' || name[0] == '*' {
- return
+ return nil
}
if def == nil {
Errorf(nil, "dwarf: bad def in dotypedef")
die := newdie(ctxt, parent, dwarf.DW_ABRV_TYPEDECL, name, 0)
newrefattr(die, dwarf.DW_AT_type, s)
+
+ return die
}
// Define gotype, for composite ones recurse into constituents.
kind := decodetypeKind(ctxt.Arch, gotype)
bytesize := decodetypeSize(ctxt.Arch, gotype)
- var die *dwarf.DWDie
+ var die, typedefdie *dwarf.DWDie
switch kind {
case objabi.KindBool:
die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
case objabi.KindArray:
die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_ARRAYTYPE, name, 0)
- dotypedef(ctxt, &dwtypes, name, die)
+ typedefdie = dotypedef(ctxt, &dwtypes, name, die)
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
s := decodetypeArrayElem(ctxt.Arch, gotype)
newrefattr(die, dwarf.DW_AT_type, defgotype(ctxt, s))
case objabi.KindFunc:
die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_FUNCTYPE, name, 0)
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
- dotypedef(ctxt, &dwtypes, name, die)
+ typedefdie = dotypedef(ctxt, &dwtypes, name, die)
nfields := decodetypeFuncInCount(ctxt.Arch, gotype)
for i := 0; i < nfields; i++ {
s := decodetypeFuncInType(ctxt.Arch, gotype, i)
case objabi.KindInterface:
die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_IFACETYPE, name, 0)
- dotypedef(ctxt, &dwtypes, name, die)
+ typedefdie = dotypedef(ctxt, &dwtypes, name, die)
nfields := int(decodetypeIfaceMethodCount(ctxt.Arch, gotype))
var s *sym.Symbol
if nfields == 0 {
case objabi.KindPtr:
die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_PTRTYPE, name, 0)
- dotypedef(ctxt, &dwtypes, name, die)
+ typedefdie = dotypedef(ctxt, &dwtypes, name, die)
s := decodetypePtrElem(ctxt.Arch, gotype)
newrefattr(die, dwarf.DW_AT_type, defgotype(ctxt, s))
case objabi.KindSlice:
die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_SLICETYPE, name, 0)
- dotypedef(ctxt, &dwtypes, name, die)
+ typedefdie = dotypedef(ctxt, &dwtypes, name, die)
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
s := decodetypeArrayElem(ctxt.Arch, gotype)
elem := defgotype(ctxt, s)
case objabi.KindStruct:
die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_STRUCTTYPE, name, 0)
- dotypedef(ctxt, &dwtypes, name, die)
+ typedefdie = dotypedef(ctxt, &dwtypes, name, die)
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
nfields := decodetypeStructFieldCount(ctxt.Arch, gotype)
for i := 0; i < nfields; i++ {
prototypedies[gotype.Name] = die
}
+ if typedefdie != nil {
+ return typedefdie
+ }
return die
}
t.Errorf("DWARF type offset was %#x+%#x, but test program said %#x", rtAttr.(uint64), types.Addr, addr)
}
}
+
+func TestIssue27614(t *testing.T) {
+ // Type references in debug_info should always use the DW_TAG_typedef_type
+ // for the type, when that's generated.
+
+ testenv.MustHaveGoBuild(t)
+
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping on plan9; no DWARF symbol table in executables")
+ }
+
+ dir, err := ioutil.TempDir("", "go-build")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ const prog = `package main
+
+import "fmt"
+
+type astruct struct {
+ X int
+}
+
+type bstruct struct {
+ X float32
+}
+
+var globalptr *astruct
+var globalvar astruct
+var bvar0, bvar1, bvar2 bstruct
+
+func main() {
+ fmt.Println(globalptr, globalvar, bvar0, bvar1, bvar2)
+}
+`
+
+ f := gobuild(t, dir, prog, NoOpt)
+
+ defer f.Close()
+
+ data, err := f.DWARF()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rdr := data.Reader()
+
+ var astructTypeDIE, bstructTypeDIE, ptrastructTypeDIE *dwarf.Entry
+ var globalptrDIE, globalvarDIE *dwarf.Entry
+ var bvarDIE [3]*dwarf.Entry
+
+ for {
+ e, err := rdr.Next()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if e == nil {
+ break
+ }
+
+ name, _ := e.Val(dwarf.AttrName).(string)
+
+ switch e.Tag {
+ case dwarf.TagTypedef:
+ switch name {
+ case "main.astruct":
+ astructTypeDIE = e
+ case "main.bstruct":
+ bstructTypeDIE = e
+ }
+ case dwarf.TagPointerType:
+ if name == "*main.astruct" {
+ ptrastructTypeDIE = e
+ }
+ case dwarf.TagVariable:
+ switch name {
+ case "main.globalptr":
+ globalptrDIE = e
+ case "main.globalvar":
+ globalvarDIE = e
+ default:
+ const bvarprefix = "main.bvar"
+ if strings.HasPrefix(name, bvarprefix) {
+ i, _ := strconv.Atoi(name[len(bvarprefix):])
+ bvarDIE[i] = e
+ }
+ }
+ }
+ }
+
+ typedieof := func(e *dwarf.Entry) dwarf.Offset {
+ return e.Val(dwarf.AttrType).(dwarf.Offset)
+ }
+
+ if off := typedieof(ptrastructTypeDIE); off != astructTypeDIE.Offset {
+ t.Errorf("type attribute of *main.astruct references %#x, not main.astruct DIE at %#x\n", off, astructTypeDIE.Offset)
+ }
+
+ if off := typedieof(globalptrDIE); off != ptrastructTypeDIE.Offset {
+ t.Errorf("type attribute of main.globalptr references %#x, not *main.astruct DIE at %#x\n", off, ptrastructTypeDIE.Offset)
+ }
+
+ if off := typedieof(globalvarDIE); off != astructTypeDIE.Offset {
+ t.Errorf("type attribute of main.globalvar1 references %#x, not main.astruct DIE at %#x\n", off, astructTypeDIE.Offset)
+ }
+
+ for i := range bvarDIE {
+ if off := typedieof(bvarDIE[i]); off != bstructTypeDIE.Offset {
+ t.Errorf("type attribute of main.bvar%d references %#x, not main.bstruct DIE at %#x\n", i, off, bstructTypeDIE.Offset)
+ }
+ }
+}