mirror of
https://github.com/golang/go
synced 2024-11-23 18:20:04 -07:00
cmd/link: fix DWARF refs so that they always point to the typedef entry
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>
This commit is contained in:
parent
19ac6a82d3
commit
a0f5d5f883
@ -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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user