cmd/link: fix contents of debug_pubnames/debug_pubtypes

The contents of debug_pubnames and debug_pubtypes have been wrong since
Go 1.12.
CL golang.org/cl/137235 moved global variables DIE to their respective
compilation unit, unfortunately writepub can't emit correct sections
for anything but the first compilation unit.

This commit moves the code generating debug_pubnames and debug_pubtypes
inside writeinfo and fixes it.
Gets rid of a number of unnecessary relocations as well as a hack that
writeinfo used to communicate to writepub the size of each compilation
unit.

Fixes #30573

Change-Id: Ibdaa80c02746ae81661c2cfe1d218092c5ae9236
Reviewed-on: https://go-review.googlesource.com/c/go/+/165337
Run-TryBot: Alessandro Arzilli <alessandro.arzilli@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
This commit is contained in:
Alessandro Arzilli 2019-03-05 09:58:58 +01:00 committed by Heschi Kreinick
parent 1a6c0c6baf
commit 4d8a37a6d9

View file

@ -264,15 +264,6 @@ func newrefattr(die *dwarf.DWDie, attr uint16, ref *sym.Symbol) *dwarf.DWAttr {
return newattr(die, attr, dwarf.DW_CLS_REFERENCE, 0, ref)
}
func putdies(linkctxt *Link, ctxt dwarf.Context, syms []*sym.Symbol, die *dwarf.DWDie) []*sym.Symbol {
for ; die != nil; die = die.Link {
syms = putdie(linkctxt, ctxt, syms, die)
}
syms[len(syms)-1].AddUint8(0)
return syms
}
func dtolsym(s dwarf.Sym) *sym.Symbol {
if s == nil {
return nil
@ -294,7 +285,10 @@ func putdie(linkctxt *Link, ctxt dwarf.Context, syms []*sym.Symbol, die *dwarf.D
dwarf.Uleb128put(ctxt, s, int64(die.Abbrev))
dwarf.PutAttrs(ctxt, s, die.Abbrev, die.Attr)
if dwarf.HasChildren(die) {
return putdies(linkctxt, ctxt, syms, die.Child)
for die := die.Child; die != nil; die = die.Link {
syms = putdie(linkctxt, ctxt, syms, die)
}
syms[len(syms)-1].AddUint8(0)
}
return syms
}
@ -1517,7 +1511,7 @@ const (
COMPUNITHEADERSIZE = 4 + 2 + 4 + 1
)
func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevsym *sym.Symbol) []*sym.Symbol {
func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevsym *sym.Symbol, pubNames, pubTypes *pubWriter) []*sym.Symbol {
infosec := ctxt.Syms.Lookup(".debug_info", 0)
infosec.Type = sym.SDWARFINFO
infosec.Attr |= sym.AttrReachable
@ -1533,6 +1527,9 @@ func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevs
continue
}
pubNames.beginCompUnit(compunit)
pubTypes.beginCompUnit(compunit)
// Write .debug_info Compilation Unit Header (sec 7.5.1)
// Fields marked with (*) must be changed for 64-bit dwarf
// This must match COMPUNITHEADERSIZE above.
@ -1553,11 +1550,32 @@ func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevs
if u.consts != nil {
cu = append(cu, u.consts)
}
cu = putdies(ctxt, dwarfctxt, cu, compunit.Child)
var cusize int64
for _, child := range cu {
cusize += child.Size
}
for die := compunit.Child; die != nil; die = die.Link {
l := len(cu)
lastSymSz := cu[l-1].Size
cu = putdie(ctxt, dwarfctxt, cu, die)
if ispubname(die) {
pubNames.add(die, cusize)
}
if ispubtype(die) {
pubTypes.add(die, cusize)
}
if lastSymSz != cu[l-1].Size {
// putdie will sometimes append directly to the last symbol of the list
cusize = cusize - lastSymSz + cu[l-1].Size
}
for _, child := range cu[l:] {
cusize += child.Size
}
}
cu[len(cu)-1].AddUint8(0) // closes compilation unit DIE
cusize++
// Save size for AIX symbol table.
if ctxt.HeadType == objabi.Haix {
saveDwsectCUSize(".debug_info", getPkgFromCUSym(s), uint64(cusize))
@ -1569,9 +1587,8 @@ func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevs
cusize -= 4 // exclude the length field.
s.SetUint32(ctxt.Arch, 0, uint32(cusize))
}
// Leave a breadcrumb for writepub. This does not
// appear in the DWARF output.
newattr(compunit, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, cusize, 0)
pubNames.endCompUnit(compunit, uint32(cusize)+4)
pubTypes.endCompUnit(compunit, uint32(cusize)+4)
syms = append(syms, cu...)
}
return syms
@ -1595,52 +1612,57 @@ func ispubtype(die *dwarf.DWDie) bool {
return die.Abbrev >= dwarf.DW_ABRV_NULLTYPE
}
func writepub(ctxt *Link, sname string, ispub func(*dwarf.DWDie) bool, syms []*sym.Symbol) []*sym.Symbol {
type pubWriter struct {
ctxt *Link
s *sym.Symbol
sname string
sectionstart int64
culengthOff int64
}
func newPubWriter(ctxt *Link, sname string) *pubWriter {
s := ctxt.Syms.Lookup(sname, 0)
s.Type = sym.SDWARFSECT
syms = append(syms, s)
return &pubWriter{ctxt: ctxt, s: s, sname: sname}
}
for _, u := range ctxt.compUnits {
if len(u.lib.Textp) == 0 && u.dwinfo.Child == nil {
continue
}
compunit := u.dwinfo
sectionstart := s.Size
culength := uint32(getattr(compunit, dwarf.DW_AT_byte_size).Value) + 4
func (pw *pubWriter) beginCompUnit(compunit *dwarf.DWDie) {
pw.sectionstart = pw.s.Size
// Write .debug_pubnames/types Header (sec 6.1.1)
createUnitLength(ctxt, s, 0) // unit_length (*), will be filled in later.
s.AddUint16(ctxt.Arch, 2) // dwarf version (appendix F)
addDwarfAddrRef(ctxt, s, dtolsym(compunit.Sym)) // debug_info_offset (of the Comp unit Header)
addDwarfAddrField(ctxt, s, uint64(culength)) // debug_info_length
// Write .debug_pubnames/types Header (sec 6.1.1)
createUnitLength(pw.ctxt, pw.s, 0) // unit_length (*), will be filled in later.
pw.s.AddUint16(pw.ctxt.Arch, 2) // dwarf version (appendix F)
addDwarfAddrRef(pw.ctxt, pw.s, dtolsym(compunit.Sym)) // debug_info_offset (of the Comp unit Header)
pw.culengthOff = pw.s.Size
addDwarfAddrField(pw.ctxt, pw.s, uint64(0)) // debug_info_length, will be filled in later.
for die := compunit.Child; die != nil; die = die.Link {
if !ispub(die) {
continue
}
dwa := getattr(die, dwarf.DW_AT_name)
name := dwa.Data.(string)
if die.Sym == nil {
fmt.Println("Missing sym for ", name)
}
addDwarfAddrRef(ctxt, s, dtolsym(die.Sym))
Addstring(s, name)
}
}
addDwarfAddrField(ctxt, s, 0) // Null offset
// On AIX, save the current size of this compilation unit.
if ctxt.HeadType == objabi.Haix {
saveDwsectCUSize(sname, getPkgFromCUSym(dtolsym(compunit.Sym)), uint64(s.Size-sectionstart))
}
if isDwarf64(ctxt) {
s.SetUint(ctxt.Arch, sectionstart+4, uint64(s.Size-sectionstart)-12) // exclude the length field.
} else {
s.SetUint32(ctxt.Arch, sectionstart, uint32(s.Size-sectionstart)-4) // exclude the length field.
}
func (pw *pubWriter) add(die *dwarf.DWDie, offset int64) {
dwa := getattr(die, dwarf.DW_AT_name)
name := dwa.Data.(string)
if die.Sym == nil {
fmt.Println("Missing sym for ", name)
}
addDwarfAddrField(pw.ctxt, pw.s, uint64(offset))
Addstring(pw.s, name)
}
return syms
func (pw *pubWriter) endCompUnit(compunit *dwarf.DWDie, culength uint32) {
addDwarfAddrField(pw.ctxt, pw.s, 0) // Null offset
// On AIX, save the current size of this compilation unit.
if pw.ctxt.HeadType == objabi.Haix {
saveDwsectCUSize(pw.sname, getPkgFromCUSym(dtolsym(compunit.Sym)), uint64(pw.s.Size-pw.sectionstart))
}
if isDwarf64(pw.ctxt) {
pw.s.SetUint(pw.ctxt.Arch, pw.sectionstart+4, uint64(pw.s.Size-pw.sectionstart)-12) // exclude the length field.
pw.s.SetUint(pw.ctxt.Arch, pw.culengthOff, uint64(culength))
} else {
pw.s.SetUint32(pw.ctxt.Arch, pw.sectionstart, uint32(pw.s.Size-pw.sectionstart)-4) // exclude the length field.
pw.s.SetUint32(pw.ctxt.Arch, pw.culengthOff, culength)
}
}
func writegdbscript(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
@ -1878,13 +1900,14 @@ func dwarfGenerateDebugSyms(ctxt *Link) {
reversetree(&dwtypes.Child)
movetomodule(ctxt, &dwtypes)
pubNames := newPubWriter(ctxt, ".debug_pubnames")
pubTypes := newPubWriter(ctxt, ".debug_pubtypes")
// Need to reorder symbols so sym.SDWARFINFO is after all sym.SDWARFSECT
// (but we need to generate dies before writepub)
infosyms := writeinfo(ctxt, nil, ctxt.compUnits, abbrev)
infosyms := writeinfo(ctxt, nil, ctxt.compUnits, abbrev, pubNames, pubTypes)
syms = writeframes(ctxt, syms)
syms = writepub(ctxt, ".debug_pubnames", ispubname, syms)
syms = writepub(ctxt, ".debug_pubtypes", ispubtype, syms)
syms = append(syms, pubNames.s, pubTypes.s)
syms = writegdbscript(ctxt, syms)
// Now we're done writing SDWARFSECT symbols, so we can write
// other SDWARF* symbols.