cmd/link: generate PC ranges for compilation unit DIEs

When we split separate packages into separate compilation units, we
lost PC range information because it was no longer contiguous. This
brings it back by constructing proper per-package PC range tables.

Change-Id: Id0ab5187e08ac5d13b3d3794977bfc857a56224f
Reviewed-on: https://go-review.googlesource.com/69974
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
Austin Clements 2017-10-10 16:19:49 -04:00
parent d4dda76b5f
commit 97920373fa
2 changed files with 58 additions and 21 deletions

View file

@ -282,6 +282,8 @@ var abbrevs = [DW_NABRV]dwAbbrev{
{DW_AT_name, DW_FORM_string},
{DW_AT_language, DW_FORM_data1},
{DW_AT_stmt_list, DW_FORM_sec_offset},
{DW_AT_low_pc, DW_FORM_addr},
{DW_AT_ranges, DW_FORM_sec_offset},
{DW_AT_comp_dir, DW_FORM_string},
{DW_AT_producer, DW_FORM_string},
},
@ -755,6 +757,28 @@ func PutIntConst(ctxt Context, info, typ Sym, name string, val int64) {
putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_sdata, DW_CLS_CONSTANT, val, nil)
}
// PutRanges writes a range table to sym. All addresses in ranges are
// relative to some base address. If base is not nil, then they're
// relative to the start of base. If base is nil, then the caller must
// arrange a base address some other way (such as a DW_AT_low_pc
// attribute).
func PutRanges(ctxt Context, sym Sym, base Sym, ranges []Range) {
ps := ctxt.PtrSize()
// Write base address entry.
if base != nil {
ctxt.AddInt(sym, ps, -1)
ctxt.AddAddress(sym, base, 0)
}
// Write ranges.
for _, r := range ranges {
ctxt.AddInt(sym, ps, r.Start)
ctxt.AddInt(sym, ps, r.End)
}
// Write trailer.
ctxt.AddInt(sym, ps, 0)
ctxt.AddInt(sym, ps, 0)
}
// PutFunc writes a DIE for a function to s.
// It also writes child DIEs for each variable in vars.
func PutFunc(ctxt Context, info, loc, ranges Sym, name string, external bool, startPC Sym, size int64, scopes []Scope) error {
@ -798,14 +822,7 @@ func putscope(ctxt Context, info, loc, ranges, startPC Sym, curscope int32, scop
Uleb128put(ctxt, info, DW_ABRV_LEXICAL_BLOCK_RANGES)
putattr(ctxt, info, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_sec_offset, DW_CLS_PTR, ranges.Len(), ranges)
ctxt.AddAddress(ranges, nil, -1)
ctxt.AddAddress(ranges, startPC, 0)
for _, r := range scope.Ranges {
ctxt.AddAddress(ranges, nil, r.Start)
ctxt.AddAddress(ranges, nil, r.End)
}
ctxt.AddAddress(ranges, nil, 0)
ctxt.AddAddress(ranges, nil, 0)
PutRanges(ctxt, ranges, startPC, scope.Ranges)
}
curscope = putscope(ctxt, info, loc, ranges, startPC, curscope, scopes, encbuf)

View file

@ -842,6 +842,7 @@ type compilationUnit struct {
lib *sym.Library
textp []*sym.Symbol // Function symbols in this package
consts *sym.Symbol // Package constants DIEs
pcs []dwarf.Range // PC ranges, relative to textp[0]
dwinfo *dwarf.DWDie // CU root DIE
funcDIEs []*sym.Symbol // Function DIE subtrees
}
@ -850,6 +851,7 @@ type compilationUnit struct {
func getCompilationUnits(ctxt *Link) []*compilationUnit {
units := []*compilationUnit{}
index := make(map[*sym.Library]*compilationUnit)
var prevUnit *compilationUnit
for _, s := range ctxt.Textp {
if s.FuncInfo == nil {
continue
@ -865,6 +867,19 @@ func getCompilationUnits(ctxt *Link) []*compilationUnit {
index[s.Lib] = unit
}
unit.textp = append(unit.textp, s)
// Update PC ranges.
//
// We don't simply compare the end of the previous
// symbol with the start of the next because there's
// often a little padding between them. Instead, we
// only create boundaries between symbols from
// different units.
if prevUnit != unit {
unit.pcs = append(unit.pcs, dwarf.Range{Start: s.Value - unit.textp[0].Value})
prevUnit = unit
}
unit.pcs[len(unit.pcs)-1].End = s.Value - unit.textp[0].Value + s.Size
}
return units
}
@ -1035,8 +1050,6 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo
lang := dwarf.DW_LANG_Go
// TODO: Generate DW_AT_ranges for dwinfo.
dwinfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, lib.Pkg, 0)
newattr(dwinfo, dwarf.DW_AT_language, dwarf.DW_CLS_CONSTANT, int64(lang), 0)
newattr(dwinfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, ls.Size, ls)
@ -1164,6 +1177,16 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo
return dwinfo, funcs
}
// writepcranges generates the DW_AT_ranges table for compilation unit cu.
func writepcranges(ctxt *Link, cu *dwarf.DWDie, base *sym.Symbol, pcs []dwarf.Range, ranges *sym.Symbol) {
var dwarfctxt dwarf.Context = dwctxt{ctxt}
// Create PC ranges for this CU.
newattr(cu, dwarf.DW_AT_ranges, dwarf.DW_CLS_PTR, ranges.Size, ranges)
newattr(cu, dwarf.DW_AT_low_pc, dwarf.DW_CLS_ADDRESS, base.Value, base)
dwarf.PutRanges(dwarfctxt, ranges, nil, pcs)
}
/*
* Emit .debug_frame
*/
@ -1304,7 +1327,6 @@ func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
}
func writeranges(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
empty := true
for _, s := range ctxt.Textp {
rangeSym := ctxt.Syms.ROLookup(dwarf.RangePrefix+s.Name, int(s.Version))
if rangeSym == nil || rangeSym.Size == 0 {
@ -1313,15 +1335,6 @@ func writeranges(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
rangeSym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable
rangeSym.Type = sym.SDWARFRANGE
syms = append(syms, rangeSym)
empty = false
}
if !empty {
// PE does not like empty sections
rangesec := ctxt.Syms.Lookup(".debug_ranges", 0)
rangesec.Type = sym.SDWARFRANGE
rangesec.Attr |= sym.AttrReachable
syms = append(syms, rangesec)
}
return syms
}
@ -1545,12 +1558,16 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
units := getCompilationUnits(ctxt)
// Write per-package line tables and start their CU DIEs.
// Write per-package line and range tables and start their CU DIEs.
debugLine := ctxt.Syms.Lookup(".debug_line", 0)
debugLine.Type = sym.SDWARFSECT
debugRanges := ctxt.Syms.Lookup(".debug_ranges", 0)
debugRanges.Type = sym.SDWARFRANGE
debugRanges.Attr |= sym.AttrReachable
syms = append(syms, debugLine)
for _, u := range units {
u.dwinfo, u.funcDIEs = writelines(ctxt, u.lib, u.textp, debugLine)
writepcranges(ctxt, u.dwinfo, u.textp[0], u.pcs, debugRanges)
}
synthesizestringtypes(ctxt, dwtypes.Child)
@ -1576,8 +1593,11 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
syms = writepub(ctxt, ".debug_pubnames", ispubname, syms)
syms = writepub(ctxt, ".debug_pubtypes", ispubtype, syms)
syms = writegdbscript(ctxt, syms)
// Now we're done writing SDWARFSECT symbols, so we can write
// other SDWARF* symbols.
syms = append(syms, infosyms...)
syms = collectlocs(ctxt, syms, units)
syms = append(syms, debugRanges)
syms = writeranges(ctxt, syms)
dwarfp = syms
}