mirror of
https://github.com/golang/go
synced 2024-11-02 09:28:34 +00:00
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:
parent
d4dda76b5f
commit
97920373fa
2 changed files with 58 additions and 21 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue