Skip to content

Commit 4c0a47a

Browse files
committed
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 <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: David Chase <[email protected]>
1 parent 4f45b2b commit 4c0a47a

File tree

3 files changed

+139
-39
lines changed

3 files changed

+139
-39
lines changed

src/cmd/internal/dwarf/dwarf.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,12 +1059,41 @@ func PutBasedRanges(ctxt Context, sym Sym, ranges []Range) {
10591059
ctxt.AddInt(sym, ps, 0)
10601060
}
10611061

1062+
// PutRngListRanges writes a DWARF5-style set of rangelist entries to sym,
1063+
// using base as a starting/base address.
1064+
func PutRngListRanges(ctxt Context, sym Sym, base Sym, ranges []Range) {
1065+
addULEB128 := func(v int64) {
1066+
b := sevenBitU(v)
1067+
if b == nil {
1068+
var encbuf [20]byte
1069+
b = AppendUleb128(encbuf[:0], uint64(v))
1070+
}
1071+
ctxt.AddBytes(sym, b)
1072+
}
1073+
// First entry is base address.
1074+
ctxt.AddInt(sym, 1, DW_RLE_base_addressx)
1075+
ctxt.AddIndirectTextRef(sym, base)
1076+
// Remaining entries are .debug_rnglist offset pairs
1077+
for _, r := range ranges {
1078+
ctxt.AddInt(sym, 1, DW_RLE_offset_pair)
1079+
addULEB128(r.Start)
1080+
addULEB128(r.End)
1081+
}
1082+
// Terminator to mark end of list
1083+
ctxt.AddInt(sym, 1, DW_RLE_end_of_list)
1084+
}
1085+
10621086
// PutRanges writes a range table to s.Ranges.
10631087
// All addresses in ranges are relative to s.base.
10641088
func (s *FnState) PutRanges(ctxt Context, ranges []Range) {
10651089
ps := ctxt.PtrSize()
10661090
sym, base := s.Ranges, s.StartPC
10671091

1092+
if buildcfg.Experiment.Dwarf5 {
1093+
PutRngListRanges(ctxt, sym, base, ranges)
1094+
return
1095+
}
1096+
10681097
if s.UseBASEntries {
10691098
// Using a Base Address Selection Entry reduces the number of relocations, but
10701099
// this is not done on macOS because it is not supported by dsymutil/dwarfdump/lldb

src/cmd/internal/dwarf/dwarf_defs.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,19 @@ const (
452452
DW_LNE_hi_user = 0xff
453453
)
454454

455+
// Table 7.25 (DWARF version 5), containing the encodings for the
456+
// .debug_rnglists entry formats.
457+
const (
458+
DW_RLE_end_of_list = 0x0
459+
DW_RLE_base_addressx = 0x1
460+
DW_RLE_startx_endx = 0x2
461+
DW_RLE_startx_length = 0x3
462+
DW_RLE_offset_pair = 0x4
463+
DW_RLE_base_address = 0x5
464+
DW_RLE_start_end = 0x6
465+
DW_RLE_start_length = 0x7
466+
)
467+
455468
// Table 7.27 (DWARF version 5), containing the encodings for the
456469
// line number header entry formats.
457470
const (

src/cmd/link/internal/ld/dwarf.go

Lines changed: 97 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,13 @@ func (c dwctxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64)
148148
dsu.AddSymRef(c.arch, tds, ofs, objabi.R_DWARFSECREF, size)
149149
}
150150

151+
func (c dwctxt) AddIndirectTextRef(s dwarf.Sym, t interface{}) {
152+
ds := loader.Sym(s.(dwSym))
153+
dsu := c.ldr.MakeSymbolUpdater(ds)
154+
tds := loader.Sym(t.(dwSym))
155+
dsu.AddSymRef(c.arch, tds, 0, objabi.R_DWTXTADDR_U4, 4)
156+
}
157+
151158
func (c dwctxt) Logf(format string, args ...interface{}) {
152159
c.linkctxt.Logf(format, args...)
153160
}
@@ -166,12 +173,6 @@ func (c dwctxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []
166173
panic("should be used only in the compiler")
167174
}
168175

169-
func (c dwctxt) AddIndirectTextRef(s dwarf.Sym, t interface{}) {
170-
// NB: at the moment unused in the linker; will be needed
171-
// later on in a subsequent patch.
172-
panic("should be used only in the compiler")
173-
}
174-
175176
func isDwarf64(ctxt *Link) bool {
176177
return ctxt.HeadType == objabi.Haix
177178
}
@@ -1470,7 +1471,7 @@ func (d *dwctxt) writelines(unit *sym.CompilationUnit, lineProlog loader.Sym) []
14701471
// writepcranges generates the DW_AT_ranges table for compilation unit
14711472
// "unit", and returns a collection of ranges symbols (one for the
14721473
// compilation unit DIE itself and the remainder from functions in the unit).
1473-
func (d *dwctxt) writepcranges(unit *sym.CompilationUnit, base loader.Sym, pcs []dwarf.Range, rangeProlog loader.Sym) []loader.Sym {
1474+
func (d *dwctxt) writepcranges(unit *sym.CompilationUnit, base loader.Sym, pcs []dwarf.Range, rangeProlog loader.Sym, debugaddrsym loader.Sym) []loader.Sym {
14741475

14751476
syms := make([]loader.Sym, 0, len(unit.RangeSyms)+1)
14761477
syms = append(syms, rangeProlog)
@@ -1480,7 +1481,24 @@ func (d *dwctxt) writepcranges(unit *sym.CompilationUnit, base loader.Sym, pcs [
14801481
// Create PC ranges for the compilation unit DIE.
14811482
newattr(unit.DWInfo, dwarf.DW_AT_ranges, dwarf.DW_CLS_PTR, rsu.Size(), rDwSym)
14821483
newattr(unit.DWInfo, dwarf.DW_AT_low_pc, dwarf.DW_CLS_ADDRESS, 0, dwSym(base))
1483-
dwarf.PutBasedRanges(d, rDwSym, pcs)
1484+
if buildcfg.Experiment.Dwarf5 && debugaddrsym != 0 {
1485+
debugaddr := d.ldr.MakeSymbolUpdater(debugaddrsym)
1486+
// Write DWARF5-based ranges for the unit. This will introduce
1487+
// a series of new R_DWTXTADDR_* relocs, which we'll process
1488+
// in the loop immediately following this call.
1489+
dwarf.PutRngListRanges(d, rDwSym, dwSym(base), pcs)
1490+
drelocs := d.ldr.Relocs(rangeProlog)
1491+
for ri := 0; ri < drelocs.Count(); ri++ {
1492+
r := drelocs.At(ri)
1493+
if !r.Type().IsDwTxtAddr() {
1494+
continue
1495+
}
1496+
cusym := d.dtolsym(unit.DWInfo.Sym)
1497+
d.assignDebugAddrSlot(unit, cusym, r, debugaddr)
1498+
}
1499+
} else {
1500+
dwarf.PutBasedRanges(d, rDwSym, pcs)
1501+
}
14841502

14851503
// Collect up the ranges for functions in the unit.
14861504
rsize := uint64(rsu.Size())
@@ -2221,10 +2239,10 @@ func (d *dwctxt) dwUnitPortion(u *sym.CompilationUnit, abbrevsym loader.Sym, us
22212239
if u.DWInfo.Abbrev != dwarf.DW_ABRV_COMPUNIT_TEXTLESS {
22222240
us.linesyms = d.writelines(u, us.lineProlog)
22232241
base := loader.Sym(u.Textp[0])
2224-
us.rangessyms = d.writepcranges(u, base, u.PCs, us.rangeProlog)
22252242
if buildcfg.Experiment.Dwarf5 {
22262243
d.writedebugaddr(u, us.addrsym)
22272244
}
2245+
us.rangessyms = d.writepcranges(u, base, u.PCs, us.rangeProlog, us.addrsym)
22282246
us.locsyms = d.collectUnitLocs(u)
22292247
}
22302248
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
22382256
func (d *dwctxt) writedebugaddr(unit *sym.CompilationUnit, debugaddr loader.Sym) {
22392257
dasu := d.ldr.MakeSymbolUpdater(debugaddr)
22402258

2259+
var dsyms []loader.Sym
22412260
for _, s := range unit.Textp {
22422261
fnSym := loader.Sym(s)
22432262
// NB: this looks at SDWARFFCN; it will need to also look
22442263
// at range and loc when they get there.
2245-
infosym, _, _, _ := d.ldr.GetFuncDwarfAuxSyms(fnSym)
2246-
2247-
// Walk the relocations of the subprogram DIE symbol to collect
2248-
// relocations corresponding to indirect function references
2249-
// via .debug_addr.
2250-
drelocs := d.ldr.Relocs(infosym)
2251-
for ri := 0; ri < drelocs.Count(); ri++ {
2252-
r := drelocs.At(ri)
2253-
if !r.Type().IsDwTxtAddr() {
2254-
continue
2255-
}
2256-
rsym := r.Sym()
2257-
rst := d.ldr.SymType(rsym)
2258-
// Do some consistency checks.
2259-
if !rst.IsText() {
2260-
// R_DWTXTADDR_* relocation should only refer to text
2261-
// symbols, so something apparently went wrong here.
2262-
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())
2263-
}
2264-
if runit := d.ldr.SymUnit(rsym); runit != unit {
2265-
log.Fatalf("internal error: R_DWTXTADDR_* relocation target text sym unit mismatch (want %q got %q)", unit.Lib.Pkg, runit.Lib.Pkg)
2264+
infosym, _, rangessym, _ := d.ldr.GetFuncDwarfAuxSyms(fnSym)
2265+
2266+
// Walk the relocations of the various DWARF symbols to
2267+
// collect relocations corresponding to indirect function
2268+
// references via .debug_addr.
2269+
dsyms = dsyms[:0]
2270+
dsyms = append(dsyms, infosym)
2271+
if rangessym != 0 {
2272+
dsyms = append(dsyms, rangessym)
2273+
}
2274+
for _, dsym := range dsyms {
2275+
drelocs := d.ldr.Relocs(dsym)
2276+
for ri := 0; ri < drelocs.Count(); ri++ {
2277+
r := drelocs.At(ri)
2278+
if !r.Type().IsDwTxtAddr() {
2279+
continue
2280+
}
2281+
rsym := r.Sym()
2282+
rst := d.ldr.SymType(rsym)
2283+
// Do some consistency checks.
2284+
if !rst.IsText() {
2285+
// R_DWTXTADDR_* relocation should only refer to
2286+
// text symbols, so something apparently went
2287+
// wrong here.
2288+
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())
2289+
}
2290+
if runit := d.ldr.SymUnit(rsym); runit != unit {
2291+
log.Fatalf("internal error: R_DWTXTADDR_* relocation target text sym unit mismatch (want %q got %q)", unit.Lib.Pkg, runit.Lib.Pkg)
2292+
}
2293+
d.assignDebugAddrSlot(unit, fnSym, r, dasu)
22662294
}
2267-
d.assignDebugAddrSlot(unit, fnSym, r, dasu)
22682295
}
22692296
}
22702297
}
@@ -2302,7 +2329,12 @@ func (d *dwctxt) dwarfGenerateDebugSyms() {
23022329
frameSym := mkSecSym(".debug_frame")
23032330
locSym := mkSecSym(".debug_loc")
23042331
lineSym := mkSecSym(".debug_line")
2305-
rangesSym := mkSecSym(".debug_ranges")
2332+
var rangesSym loader.Sym
2333+
if buildcfg.Experiment.Dwarf5 {
2334+
rangesSym = mkSecSym(".debug_rnglists")
2335+
} else {
2336+
rangesSym = mkSecSym(".debug_ranges")
2337+
}
23062338
infoSym := mkSecSym(".debug_info")
23072339
var addrSym loader.Sym
23082340
if buildcfg.Experiment.Dwarf5 {
@@ -2312,13 +2344,16 @@ func (d *dwctxt) dwarfGenerateDebugSyms() {
23122344
// Create the section objects
23132345
lineSec := dwarfSecInfo{syms: []loader.Sym{lineSym}}
23142346
locSec := dwarfSecInfo{syms: []loader.Sym{locSym}}
2315-
rangesSec := dwarfSecInfo{syms: []loader.Sym{rangesSym}}
23162347
frameSec := dwarfSecInfo{syms: []loader.Sym{frameSym}}
23172348
infoSec := dwarfSecInfo{syms: []loader.Sym{infoSym}}
2318-
var addrSec dwarfSecInfo
2349+
var addrSec, rangesSec dwarfSecInfo
23192350
if buildcfg.Experiment.Dwarf5 {
23202351
addrHdr := d.writeDebugAddrHdr()
23212352
addrSec.syms = []loader.Sym{addrSym, addrHdr}
2353+
rnglistsHdr := d.writeDebugRngListsHdr()
2354+
rangesSec.syms = []loader.Sym{rangesSym, rnglistsHdr}
2355+
} else {
2356+
rangesSec = dwarfSecInfo{syms: []loader.Sym{rangesSym}}
23222357
}
23232358

23242359
// Create any new symbols that will be needed during the
@@ -2386,13 +2421,19 @@ func (d *dwctxt) dwarfGenerateDebugSyms() {
23862421
}
23872422

23882423
if buildcfg.Experiment.Dwarf5 {
2389-
// Compute total size of the .debug_addr unit syms.
2390-
var addrtot uint64
2424+
// Compute total size of the DWARF5-specific .debug_* syms in
2425+
// each compilation unit.
2426+
var rltot, addrtot uint64
23912427
for i := 0; i < ncu; i++ {
23922428
addrtot += uint64(d.ldr.SymSize(unitSyms[i].addrsym))
2429+
rs := unitSyms[i].rangessyms
2430+
for _, s := range rs {
2431+
rltot += uint64(d.ldr.SymSize(s))
2432+
}
23932433
}
2394-
// Call a helper to patch the length field in the header.
2434+
// Call a helper to patch the length field in the headers.
23952435
patchHdr(&addrSec, addrtot)
2436+
patchHdr(&rangesSec, rltot)
23962437
}
23972438

23982439
// Stitch together the results.
@@ -2462,10 +2503,13 @@ func dwarfaddshstrings(ctxt *Link, add func(string)) {
24622503
return
24632504
}
24642505

2465-
secs := []string{"abbrev", "frame", "info", "loc", "line", "gdb_scripts", "ranges"}
2506+
secs := []string{"abbrev", "frame", "info", "loc", "line", "gdb_scripts"}
24662507
if buildcfg.Experiment.Dwarf5 {
2467-
secs = append(secs, "addr")
2508+
secs = append(secs, "addr", "rnglists")
2509+
} else {
2510+
secs = append(secs, "ranges")
24682511
}
2512+
24692513
for _, sec := range secs {
24702514
add(".debug_" + sec)
24712515
if ctxt.IsExternal() {
@@ -2623,6 +2667,20 @@ func addDwsectCUSize(sname string, pkgname string, size uint64) {
26232667
dwsectCUSize[sname+"."+pkgname] += size
26242668
}
26252669

2670+
// writeDebugAddrHdr creates a new symbol and writes the content
2671+
// for the .debug_rnglists header payload to it, then returns the new sym.
2672+
// Format of the header is described in DWARF5 spec section 7.28.
2673+
func (d *dwctxt) writeDebugRngListsHdr() loader.Sym {
2674+
su := d.ldr.MakeSymbolUpdater(d.ldr.CreateExtSym("", 0))
2675+
su.SetType(sym.SDWARFRANGE)
2676+
su.SetReachable(true)
2677+
d.createUnitLength(su, 0) // will be filled in later.
2678+
su.AddUint16(d.arch, 5) // dwarf version (appendix F)
2679+
su.AddUint8(uint8(d.arch.PtrSize)) // address_size
2680+
su.AddUint8(0)
2681+
return su.Sym()
2682+
}
2683+
26262684
// writeDebugAddrHdr creates a new symbol and writes the content
26272685
// for the .debug_addr header payload to it, then returns the new sym.
26282686
// Format of the header is described in DWARF5 spec section 7.27.

0 commit comments

Comments
 (0)