From: Than McIntosh Date: Thu, 12 Dec 2024 00:20:58 +0000 (-0500) Subject: cmd/compile,cmd/link: move to DWARF5-style range lists X-Git-Tag: go1.25rc1~847 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=4c0a47a8ff74c5fe4366e1016250607943562569;p=gostls13.git 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 LUCI-TryBot-Result: Go LUCI Reviewed-by: David Chase --- 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) - - // 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) + infosym, _, rangessym, _ := d.ldr.GetFuncDwarfAuxSyms(fnSym) + + // 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() { @@ -2623,6 +2667,20 @@ func addDwsectCUSize(sname string, pkgname string, size uint64) { dwsectCUSize[sname+"."+pkgname] += size } +// 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.