aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThan McIntosh <thanm@golang.org>2024-12-11 19:20:58 -0500
committerThan McIntosh <thanm@golang.org>2025-03-04 04:48:46 -0800
commit4c0a47a8ff74c5fe4366e1016250607943562569 (patch)
tree21cf106c0b3352ff5b0c58ab03910ee752869e57 /src
parent4f45b2b7e079fc03d3444642e8a33ce6f959c6a6 (diff)
downloadgo-4c0a47a8ff74c5fe4366e1016250607943562569.tar.xz
cmd/compile,cmd/link: move to DWARF5-style range lists
This patch updates the compiler to generate DWARF5-style range lists (e.g. entries that feed into .debug_rnglists) as opposed to DWARF4-style range lists (which wind up in .debug_ranges). The DWARF5 format is much more compact, and can make indirect references to text address via the .debug_addr section for further space savings. Updates #26379. Change-Id: I273a6283484b7fe33d79d5412e31c5155b22a7c0 Reviewed-on: https://go-review.googlesource.com/c/go/+/635345 Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: David Chase <drchase@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/cmd/internal/dwarf/dwarf.go29
-rw-r--r--src/cmd/internal/dwarf/dwarf_defs.go13
-rw-r--r--src/cmd/link/internal/ld/dwarf.go134
3 files changed, 138 insertions, 38 deletions
diff --git a/src/cmd/internal/dwarf/dwarf.go b/src/cmd/internal/dwarf/dwarf.go
index 44b0de7d7c..88dac10c1b 100644
--- a/src/cmd/internal/dwarf/dwarf.go
+++ b/src/cmd/internal/dwarf/dwarf.go
@@ -1059,12 +1059,41 @@ func PutBasedRanges(ctxt Context, sym Sym, ranges []Range) {
ctxt.AddInt(sym, ps, 0)
}
+// PutRngListRanges writes a DWARF5-style set of rangelist entries to sym,
+// using base as a starting/base address.
+func PutRngListRanges(ctxt Context, sym Sym, base Sym, ranges []Range) {
+ addULEB128 := func(v int64) {
+ b := sevenBitU(v)
+ if b == nil {
+ var encbuf [20]byte
+ b = AppendUleb128(encbuf[:0], uint64(v))
+ }
+ ctxt.AddBytes(sym, b)
+ }
+ // First entry is base address.
+ ctxt.AddInt(sym, 1, DW_RLE_base_addressx)
+ ctxt.AddIndirectTextRef(sym, base)
+ // Remaining entries are .debug_rnglist offset pairs
+ for _, r := range ranges {
+ ctxt.AddInt(sym, 1, DW_RLE_offset_pair)
+ addULEB128(r.Start)
+ addULEB128(r.End)
+ }
+ // Terminator to mark end of list
+ ctxt.AddInt(sym, 1, DW_RLE_end_of_list)
+}
+
// PutRanges writes a range table to s.Ranges.
// All addresses in ranges are relative to s.base.
func (s *FnState) PutRanges(ctxt Context, ranges []Range) {
ps := ctxt.PtrSize()
sym, base := s.Ranges, s.StartPC
+ if buildcfg.Experiment.Dwarf5 {
+ PutRngListRanges(ctxt, sym, base, ranges)
+ return
+ }
+
if s.UseBASEntries {
// Using a Base Address Selection Entry reduces the number of relocations, but
// this is not done on macOS because it is not supported by dsymutil/dwarfdump/lldb
diff --git a/src/cmd/internal/dwarf/dwarf_defs.go b/src/cmd/internal/dwarf/dwarf_defs.go
index 549a809bfb..db4245e95d 100644
--- a/src/cmd/internal/dwarf/dwarf_defs.go
+++ b/src/cmd/internal/dwarf/dwarf_defs.go
@@ -452,6 +452,19 @@ const (
DW_LNE_hi_user = 0xff
)
+// Table 7.25 (DWARF version 5), containing the encodings for the
+// .debug_rnglists entry formats.
+const (
+ DW_RLE_end_of_list = 0x0
+ DW_RLE_base_addressx = 0x1
+ DW_RLE_startx_endx = 0x2
+ DW_RLE_startx_length = 0x3
+ DW_RLE_offset_pair = 0x4
+ DW_RLE_base_address = 0x5
+ DW_RLE_start_end = 0x6
+ DW_RLE_start_length = 0x7
+)
+
// Table 7.27 (DWARF version 5), containing the encodings for the
// line number header entry formats.
const (
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index e6de8b5914..cabdedecf1 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -148,6 +148,13 @@ func (c dwctxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64)
dsu.AddSymRef(c.arch, tds, ofs, objabi.R_DWARFSECREF, size)
}
+func (c dwctxt) AddIndirectTextRef(s dwarf.Sym, t interface{}) {
+ ds := loader.Sym(s.(dwSym))
+ dsu := c.ldr.MakeSymbolUpdater(ds)
+ tds := loader.Sym(t.(dwSym))
+ dsu.AddSymRef(c.arch, tds, 0, objabi.R_DWTXTADDR_U4, 4)
+}
+
func (c dwctxt) Logf(format string, args ...interface{}) {
c.linkctxt.Logf(format, args...)
}
@@ -166,12 +173,6 @@ func (c dwctxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []
panic("should be used only in the compiler")
}
-func (c dwctxt) AddIndirectTextRef(s dwarf.Sym, t interface{}) {
- // NB: at the moment unused in the linker; will be needed
- // later on in a subsequent patch.
- panic("should be used only in the compiler")
-}
-
func isDwarf64(ctxt *Link) bool {
return ctxt.HeadType == objabi.Haix
}
@@ -1470,7 +1471,7 @@ func (d *dwctxt) writelines(unit *sym.CompilationUnit, lineProlog loader.Sym) []
// writepcranges generates the DW_AT_ranges table for compilation unit
// "unit", and returns a collection of ranges symbols (one for the
// compilation unit DIE itself and the remainder from functions in the unit).
-func (d *dwctxt) writepcranges(unit *sym.CompilationUnit, base loader.Sym, pcs []dwarf.Range, rangeProlog loader.Sym) []loader.Sym {
+func (d *dwctxt) writepcranges(unit *sym.CompilationUnit, base loader.Sym, pcs []dwarf.Range, rangeProlog loader.Sym, debugaddrsym loader.Sym) []loader.Sym {
syms := make([]loader.Sym, 0, len(unit.RangeSyms)+1)
syms = append(syms, rangeProlog)
@@ -1480,7 +1481,24 @@ func (d *dwctxt) writepcranges(unit *sym.CompilationUnit, base loader.Sym, pcs [
// Create PC ranges for the compilation unit DIE.
newattr(unit.DWInfo, dwarf.DW_AT_ranges, dwarf.DW_CLS_PTR, rsu.Size(), rDwSym)
newattr(unit.DWInfo, dwarf.DW_AT_low_pc, dwarf.DW_CLS_ADDRESS, 0, dwSym(base))
- dwarf.PutBasedRanges(d, rDwSym, pcs)
+ if buildcfg.Experiment.Dwarf5 && debugaddrsym != 0 {
+ debugaddr := d.ldr.MakeSymbolUpdater(debugaddrsym)
+ // Write DWARF5-based ranges for the unit. This will introduce
+ // a series of new R_DWTXTADDR_* relocs, which we'll process
+ // in the loop immediately following this call.
+ dwarf.PutRngListRanges(d, rDwSym, dwSym(base), pcs)
+ drelocs := d.ldr.Relocs(rangeProlog)
+ for ri := 0; ri < drelocs.Count(); ri++ {
+ r := drelocs.At(ri)
+ if !r.Type().IsDwTxtAddr() {
+ continue
+ }
+ cusym := d.dtolsym(unit.DWInfo.Sym)
+ d.assignDebugAddrSlot(unit, cusym, r, debugaddr)
+ }
+ } else {
+ dwarf.PutBasedRanges(d, rDwSym, pcs)
+ }
// Collect up the ranges for functions in the unit.
rsize := uint64(rsu.Size())
@@ -2221,10 +2239,10 @@ func (d *dwctxt) dwUnitPortion(u *sym.CompilationUnit, abbrevsym loader.Sym, us
if u.DWInfo.Abbrev != dwarf.DW_ABRV_COMPUNIT_TEXTLESS {
us.linesyms = d.writelines(u, us.lineProlog)
base := loader.Sym(u.Textp[0])
- us.rangessyms = d.writepcranges(u, base, u.PCs, us.rangeProlog)
if buildcfg.Experiment.Dwarf5 {
d.writedebugaddr(u, us.addrsym)
}
+ us.rangessyms = d.writepcranges(u, base, u.PCs, us.rangeProlog, us.addrsym)
us.locsyms = d.collectUnitLocs(u)
}
us.infosyms = d.writeUnitInfo(u, abbrevsym, us.addrsym, us.infoEpilog)
@@ -2238,33 +2256,42 @@ func (d *dwctxt) dwUnitPortion(u *sym.CompilationUnit, abbrevsym loader.Sym, us
func (d *dwctxt) writedebugaddr(unit *sym.CompilationUnit, debugaddr loader.Sym) {
dasu := d.ldr.MakeSymbolUpdater(debugaddr)
+ var dsyms []loader.Sym
for _, s := range unit.Textp {
fnSym := loader.Sym(s)
// NB: this looks at SDWARFFCN; it will need to also look
// at range and loc when they get there.
- infosym, _, _, _ := d.ldr.GetFuncDwarfAuxSyms(fnSym)
+ infosym, _, rangessym, _ := d.ldr.GetFuncDwarfAuxSyms(fnSym)
- // Walk the relocations of the subprogram DIE symbol to collect
- // relocations corresponding to indirect function references
- // via .debug_addr.
- drelocs := d.ldr.Relocs(infosym)
- for ri := 0; ri < drelocs.Count(); ri++ {
- r := drelocs.At(ri)
- if !r.Type().IsDwTxtAddr() {
- continue
- }
- rsym := r.Sym()
- rst := d.ldr.SymType(rsym)
- // Do some consistency checks.
- if !rst.IsText() {
- // R_DWTXTADDR_* relocation should only refer to text
- // symbols, so something apparently went wrong here.
- log.Fatalf("internal error: R_DWTXTADDR_* relocation on dwinfosym for %s against non-function %s type:%s", d.ldr.SymName(fnSym), d.ldr.SymName(rsym), rst.String())
- }
- if runit := d.ldr.SymUnit(rsym); runit != unit {
- log.Fatalf("internal error: R_DWTXTADDR_* relocation target text sym unit mismatch (want %q got %q)", unit.Lib.Pkg, runit.Lib.Pkg)
+ // Walk the relocations of the various DWARF symbols to
+ // collect relocations corresponding to indirect function
+ // references via .debug_addr.
+ dsyms = dsyms[:0]
+ dsyms = append(dsyms, infosym)
+ if rangessym != 0 {
+ dsyms = append(dsyms, rangessym)
+ }
+ for _, dsym := range dsyms {
+ drelocs := d.ldr.Relocs(dsym)
+ for ri := 0; ri < drelocs.Count(); ri++ {
+ r := drelocs.At(ri)
+ if !r.Type().IsDwTxtAddr() {
+ continue
+ }
+ rsym := r.Sym()
+ rst := d.ldr.SymType(rsym)
+ // Do some consistency checks.
+ if !rst.IsText() {
+ // R_DWTXTADDR_* relocation should only refer to
+ // text symbols, so something apparently went
+ // wrong here.
+ log.Fatalf("internal error: R_DWTXTADDR_* relocation on dwinfosym for %s against non-function %s type:%s", d.ldr.SymName(fnSym), d.ldr.SymName(rsym), rst.String())
+ }
+ if runit := d.ldr.SymUnit(rsym); runit != unit {
+ log.Fatalf("internal error: R_DWTXTADDR_* relocation target text sym unit mismatch (want %q got %q)", unit.Lib.Pkg, runit.Lib.Pkg)
+ }
+ d.assignDebugAddrSlot(unit, fnSym, r, dasu)
}
- d.assignDebugAddrSlot(unit, fnSym, r, dasu)
}
}
}
@@ -2302,7 +2329,12 @@ func (d *dwctxt) dwarfGenerateDebugSyms() {
frameSym := mkSecSym(".debug_frame")
locSym := mkSecSym(".debug_loc")
lineSym := mkSecSym(".debug_line")
- rangesSym := mkSecSym(".debug_ranges")
+ var rangesSym loader.Sym
+ if buildcfg.Experiment.Dwarf5 {
+ rangesSym = mkSecSym(".debug_rnglists")
+ } else {
+ rangesSym = mkSecSym(".debug_ranges")
+ }
infoSym := mkSecSym(".debug_info")
var addrSym loader.Sym
if buildcfg.Experiment.Dwarf5 {
@@ -2312,13 +2344,16 @@ func (d *dwctxt) dwarfGenerateDebugSyms() {
// Create the section objects
lineSec := dwarfSecInfo{syms: []loader.Sym{lineSym}}
locSec := dwarfSecInfo{syms: []loader.Sym{locSym}}
- rangesSec := dwarfSecInfo{syms: []loader.Sym{rangesSym}}
frameSec := dwarfSecInfo{syms: []loader.Sym{frameSym}}
infoSec := dwarfSecInfo{syms: []loader.Sym{infoSym}}
- var addrSec dwarfSecInfo
+ var addrSec, rangesSec dwarfSecInfo
if buildcfg.Experiment.Dwarf5 {
addrHdr := d.writeDebugAddrHdr()
addrSec.syms = []loader.Sym{addrSym, addrHdr}
+ rnglistsHdr := d.writeDebugRngListsHdr()
+ rangesSec.syms = []loader.Sym{rangesSym, rnglistsHdr}
+ } else {
+ rangesSec = dwarfSecInfo{syms: []loader.Sym{rangesSym}}
}
// Create any new symbols that will be needed during the
@@ -2386,13 +2421,19 @@ func (d *dwctxt) dwarfGenerateDebugSyms() {
}
if buildcfg.Experiment.Dwarf5 {
- // Compute total size of the .debug_addr unit syms.
- var addrtot uint64
+ // Compute total size of the DWARF5-specific .debug_* syms in
+ // each compilation unit.
+ var rltot, addrtot uint64
for i := 0; i < ncu; i++ {
addrtot += uint64(d.ldr.SymSize(unitSyms[i].addrsym))
+ rs := unitSyms[i].rangessyms
+ for _, s := range rs {
+ rltot += uint64(d.ldr.SymSize(s))
+ }
}
- // Call a helper to patch the length field in the header.
+ // Call a helper to patch the length field in the headers.
patchHdr(&addrSec, addrtot)
+ patchHdr(&rangesSec, rltot)
}
// Stitch together the results.
@@ -2462,10 +2503,13 @@ func dwarfaddshstrings(ctxt *Link, add func(string)) {
return
}
- secs := []string{"abbrev", "frame", "info", "loc", "line", "gdb_scripts", "ranges"}
+ secs := []string{"abbrev", "frame", "info", "loc", "line", "gdb_scripts"}
if buildcfg.Experiment.Dwarf5 {
- secs = append(secs, "addr")
+ secs = append(secs, "addr", "rnglists")
+ } else {
+ secs = append(secs, "ranges")
}
+
for _, sec := range secs {
add(".debug_" + sec)
if ctxt.IsExternal() {
@@ -2624,6 +2668,20 @@ func addDwsectCUSize(sname string, pkgname string, size uint64) {
}
// writeDebugAddrHdr creates a new symbol and writes the content
+// for the .debug_rnglists header payload to it, then returns the new sym.
+// Format of the header is described in DWARF5 spec section 7.28.
+func (d *dwctxt) writeDebugRngListsHdr() loader.Sym {
+ su := d.ldr.MakeSymbolUpdater(d.ldr.CreateExtSym("", 0))
+ su.SetType(sym.SDWARFRANGE)
+ su.SetReachable(true)
+ d.createUnitLength(su, 0) // will be filled in later.
+ su.AddUint16(d.arch, 5) // dwarf version (appendix F)
+ su.AddUint8(uint8(d.arch.PtrSize)) // address_size
+ su.AddUint8(0)
+ return su.Sym()
+}
+
+// writeDebugAddrHdr creates a new symbol and writes the content
// for the .debug_addr header payload to it, then returns the new sym.
// Format of the header is described in DWARF5 spec section 7.27.
func (d *dwctxt) writeDebugAddrHdr() loader.Sym {