{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},
},
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 {
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)
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
}
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
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
}
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)
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
*/
}
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 {
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
}
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)
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
}