]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: fix DWARF refs so that they always point to the typedef entry
authorAlessandro Arzilli <alessandro.arzilli@gmail.com>
Mon, 10 Sep 2018 13:36:59 +0000 (15:36 +0200)
committerThan McIntosh <thanm@google.com>
Tue, 18 Sep 2018 15:38:16 +0000 (15:38 +0000)
For types defined as:

type typename struct { ... }

the linker produces two DIEs: (1) a DW_TAG_structure_type DIE and (2) a
DW_TAG_typedef_type DIE having (1) as its type attribute.

All subsequent references to 'typename' should use the
DW_TAG_typedef_type DIE, not the DW_TAG_structure_type. Mostly this is
true but sometimes one reference will use the DW_TAG_structure_type
directly. In particular, this happens to the 'first' reference to the
type in question (where 'first' means whatever happens first in the way
the linker scans its symbols).

This isn't only true of struct types: pointer types, array types, etc.
can also be affected.

This fix solves the problem by always returning the typedef DIE in
newtype, when one is created.

Fixes #27614

Change-Id: Ia65b4a1d8c2b752e33a4ebdb74ccd92faa69526e
Reviewed-on: https://go-review.googlesource.com/134555
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
src/cmd/link/internal/ld/dwarf.go
src/cmd/link/internal/ld/dwarf_test.go

index 959fc8290c08d96cbc461009016601e94d68febd..2164fa80a0f2bbe15c3c3a99b568d461409a096e 100644 (file)
@@ -340,19 +340,19 @@ func lookupOrDiag(ctxt *Link, n string) *sym.Symbol {
        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")
@@ -370,6 +370,8 @@ func dotypedef(ctxt *Link, parent *dwarf.DWDie, name string, def *dwarf.DWDie) {
        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.
@@ -399,7 +401,7 @@ func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
        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)
@@ -439,7 +441,7 @@ func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
 
        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))
@@ -461,7 +463,7 @@ func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
        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)
@@ -481,7 +483,7 @@ func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
 
        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 {
@@ -503,13 +505,13 @@ func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
 
        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)
@@ -521,7 +523,7 @@ func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
 
        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++ {
@@ -557,6 +559,9 @@ func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
                prototypedies[gotype.Name] = die
        }
 
+       if typedefdie != nil {
+               return typedefdie
+       }
        return die
 }
 
index 157bebbb412567544675d7cd59abddab5c61a7d6..5d2aadf589970824ce7953396b745e69c73dd30e 100644 (file)
@@ -948,3 +948,117 @@ func main() {
                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)
+               }
+       }
+}