]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile,cmd/link: move to DWARF5-style location lists
authorThan McIntosh <thanm@golang.org>
Fri, 13 Dec 2024 01:47:30 +0000 (20:47 -0500)
committerThan McIntosh <thanm@golang.org>
Tue, 4 Mar 2025 12:48:53 +0000 (04:48 -0800)
This patch updates the compiler to generate DWARF5-style location
lists (e.g. entries that feed into .debug_loclists) as opposed to
DWARF4-style location lists (which wind up in .debug_loc). The DWARF5
format is much more compact, and can make indirect references to text
addresses via the .debug_addr section for further space savings.

Updates #26379.

Change-Id: If2e6fce1136d9cba5125ea51a71419596d1d1691
Reviewed-on: https://go-review.googlesource.com/c/go/+/635836
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
src/cmd/compile/internal/ssa/debug.go
src/cmd/internal/dwarf/dwarf_defs.go
src/cmd/link/internal/ld/dwarf.go

index 381777c17da03b5d5c1531296e7ea427d53479e1..59d029426443d44ee0689ee9a835bb18d1dc609c 100644 (file)
@@ -1486,8 +1486,67 @@ func (state *debugState) writePendingEntry(varID VarID, endBlock, endValue ID) {
        state.lists[varID] = list
 }
 
-// PutLocationList adds list (a location list in its intermediate representation) to listSym.
+// PutLocationList adds list (a location list in its intermediate
+// representation) to listSym.
 func (debugInfo *FuncDebug) PutLocationList(list []byte, ctxt *obj.Link, listSym, startPC *obj.LSym) {
+       if buildcfg.Experiment.Dwarf5 {
+               debugInfo.PutLocationListDwarf5(list, ctxt, listSym, startPC)
+       } else {
+               debugInfo.PutLocationListDwarf4(list, ctxt, listSym, startPC)
+       }
+}
+
+// PutLocationListDwarf5 adds list (a location list in its intermediate
+// representation) to listSym in DWARF 5 format. NB: this is a somewhat
+// hacky implementation in that it actually reads a DWARF4 encoded
+// info from list (with all its DWARF4-specific quirks) then re-encodes
+// it in DWARF5. It would probably be better at some point to have
+// ssa/debug encode the list in a version-independent form and then
+// have this func (and PutLocationListDwarf4) intoduce the quirks.
+func (debugInfo *FuncDebug) PutLocationListDwarf5(list []byte, ctxt *obj.Link, listSym, startPC *obj.LSym) {
+       getPC := debugInfo.GetPC
+
+       // base address entry
+       listSym.WriteInt(ctxt, listSym.Size, 1, dwarf.DW_LLE_base_addressx)
+       listSym.WriteDwTxtAddrx(ctxt, listSym.Size, startPC, ctxt.DwTextCount*2)
+
+       var stbuf, enbuf [10]byte
+       stb, enb := stbuf[:], enbuf[:]
+       // Re-read list, translating its address from block/value ID to PC.
+       for i := 0; i < len(list); {
+               begin := getPC(decodeValue(ctxt, readPtr(ctxt, list[i:])))
+               end := getPC(decodeValue(ctxt, readPtr(ctxt, list[i+ctxt.Arch.PtrSize:])))
+
+               // Write LLE_offset_pair tag followed by payload (ULEB for start
+               // and then end).
+               listSym.WriteInt(ctxt, listSym.Size, 1, dwarf.DW_LLE_offset_pair)
+               stb, enb = stb[:0], enb[:0]
+               stb = dwarf.AppendUleb128(stb, uint64(begin))
+               enb = dwarf.AppendUleb128(enb, uint64(end))
+               listSym.WriteBytes(ctxt, listSym.Size, stb)
+               listSym.WriteBytes(ctxt, listSym.Size, enb)
+
+               // The encoded data in "list" is in DWARF4 format, which uses
+               // a 2-byte length; DWARF5 uses an LEB-encoded value for this
+               // length. Read the length and then re-encode it.
+               i += 2 * ctxt.Arch.PtrSize
+               datalen := int(ctxt.Arch.ByteOrder.Uint16(list[i:]))
+               i += 2
+               stb = stb[:0]
+               stb = dwarf.AppendUleb128(stb, uint64(datalen))
+               listSym.WriteBytes(ctxt, listSym.Size, stb)               // copy length
+               listSym.WriteBytes(ctxt, listSym.Size, list[i:i+datalen]) // loc desc
+
+               i += datalen
+       }
+
+       // Terminator
+       listSym.WriteInt(ctxt, listSym.Size, 1, dwarf.DW_LLE_end_of_list)
+}
+
+// PutLocationListDwarf4 adds list (a location list in its intermediate
+// representation) to listSym in DWARF 4 format.
+func (debugInfo *FuncDebug) PutLocationListDwarf4(list []byte, ctxt *obj.Link, listSym, startPC *obj.LSym) {
        getPC := debugInfo.GetPC
 
        if ctxt.UseBASEntries {
index db4245e95d91b91c03f14646aca084b16685d5f6..b4675cb19329ff7807a87847b981193ebb206eee 100644 (file)
@@ -465,6 +465,20 @@ const (
        DW_RLE_start_length  = 0x7
 )
 
+// Table 7.10 (DWARF version 5), containing the encodings for the
+// .debug_loclists entry formats.
+const (
+       DW_LLE_end_of_list      = 0x0
+       DW_LLE_base_addressx    = 0x1
+       DW_LLE_startx_endx      = 0x2
+       DW_LLE_startx_length    = 0x3
+       DW_LLE_offset_pair      = 0x4
+       DW_LLE_default_location = 0x5
+       DW_LLE_base_address     = 0x6
+       DW_LLE_start_end        = 0x7
+       DW_LLE_start_length     = 0x8
+)
+
 // Table 7.27 (DWARF version 5), containing the encodings for the
 // line number header entry formats.
 const (
index cabdedecf1a41eb3aa851e641bed8ca5c8762fd1..602d70ddb98295bd457b5e9fb7f4d4a9c409f750 100644 (file)
@@ -2261,7 +2261,7 @@ func (d *dwctxt) writedebugaddr(unit *sym.CompilationUnit, debugaddr loader.Sym)
                fnSym := loader.Sym(s)
                // NB: this looks at SDWARFFCN; it will need to also look
                // at range and loc when they get there.
-               infosym, _, rangessym, _ := d.ldr.GetFuncDwarfAuxSyms(fnSym)
+               infosym, locsym, rangessym, _ := d.ldr.GetFuncDwarfAuxSyms(fnSym)
 
                // Walk the relocations of the various DWARF symbols to
                // collect relocations corresponding to indirect function
@@ -2271,6 +2271,9 @@ func (d *dwctxt) writedebugaddr(unit *sym.CompilationUnit, debugaddr loader.Sym)
                if rangessym != 0 {
                        dsyms = append(dsyms, rangessym)
                }
+               if locsym != 0 {
+                       dsyms = append(dsyms, locsym)
+               }
                for _, dsym := range dsyms {
                        drelocs := d.ldr.Relocs(dsym)
                        for ri := 0; ri < drelocs.Count(); ri++ {
@@ -2327,13 +2330,14 @@ func (d *dwctxt) dwarfGenerateDebugSyms() {
 
        // Create the section symbols.
        frameSym := mkSecSym(".debug_frame")
-       locSym := mkSecSym(".debug_loc")
        lineSym := mkSecSym(".debug_line")
-       var rangesSym loader.Sym
+       var rangesSym, locSym loader.Sym
        if buildcfg.Experiment.Dwarf5 {
                rangesSym = mkSecSym(".debug_rnglists")
+               locSym = mkSecSym(".debug_loclists")
        } else {
                rangesSym = mkSecSym(".debug_ranges")
+               locSym = mkSecSym(".debug_loc")
        }
        infoSym := mkSecSym(".debug_info")
        var addrSym loader.Sym
@@ -2343,17 +2347,19 @@ func (d *dwctxt) dwarfGenerateDebugSyms() {
 
        // Create the section objects
        lineSec := dwarfSecInfo{syms: []loader.Sym{lineSym}}
-       locSec := dwarfSecInfo{syms: []loader.Sym{locSym}}
        frameSec := dwarfSecInfo{syms: []loader.Sym{frameSym}}
        infoSec := dwarfSecInfo{syms: []loader.Sym{infoSym}}
-       var addrSec, rangesSec dwarfSecInfo
+       var addrSec, rangesSec, locSec dwarfSecInfo
        if buildcfg.Experiment.Dwarf5 {
                addrHdr := d.writeDebugAddrHdr()
                addrSec.syms = []loader.Sym{addrSym, addrHdr}
                rnglistsHdr := d.writeDebugRngListsHdr()
                rangesSec.syms = []loader.Sym{rangesSym, rnglistsHdr}
+               loclistsHdr := d.writeDebugLocListsHdr()
+               locSec.syms = []loader.Sym{locSym, loclistsHdr}
        } else {
                rangesSec = dwarfSecInfo{syms: []loader.Sym{rangesSym}}
+               locSec = dwarfSecInfo{syms: []loader.Sym{locSym}}
        }
 
        // Create any new symbols that will be needed during the
@@ -2423,17 +2429,22 @@ func (d *dwctxt) dwarfGenerateDebugSyms() {
        if buildcfg.Experiment.Dwarf5 {
                // Compute total size of the DWARF5-specific .debug_* syms in
                // each compilation unit.
-               var rltot, addrtot uint64
+               var rltot, addrtot, loctot 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))
                        }
+                       loc := unitSyms[i].locsyms
+                       for _, s := range loc {
+                               loctot += uint64(d.ldr.SymSize(s))
+                       }
                }
                // Call a helper to patch the length field in the headers.
                patchHdr(&addrSec, addrtot)
                patchHdr(&rangesSec, rltot)
+               patchHdr(&locSec, loctot)
        }
 
        // Stitch together the results.
@@ -2505,9 +2516,9 @@ func dwarfaddshstrings(ctxt *Link, add func(string)) {
 
        secs := []string{"abbrev", "frame", "info", "loc", "line", "gdb_scripts"}
        if buildcfg.Experiment.Dwarf5 {
-               secs = append(secs, "addr", "rnglists")
+               secs = append(secs, "addr", "rnglists", "loclists")
        } else {
-               secs = append(secs, "ranges")
+               secs = append(secs, "ranges", "loc")
        }
 
        for _, sec := range secs {
@@ -2667,30 +2678,33 @@ 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 {
+// writeDebugMiscSecHdr writes a header section for the new new DWARF5
+// sections ".debug_addr", ".debug_loclists", and ".debug_rnglists".
+// A description of the format/layout of these headers can be found in
+// the DWARF5 spec in sections 7.27 (.debug_addr), 7.28
+// (.debug_rnglists) and 7.29 (.debug_loclists).
+func (d *dwctxt) writeDebugMiscSecHdr(st sym.SymKind, addOffsetEntryCount bool) loader.Sym {
        su := d.ldr.MakeSymbolUpdater(d.ldr.CreateExtSym("", 0))
-       su.SetType(sym.SDWARFRANGE)
+       su.SetType(st)
        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)
+       su.AddUint8(0)                     // segment selector
+       if addOffsetEntryCount {
+               su.AddUint32(d.arch, 0) // offset entry count (required but unused)
+       }
        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) writeDebugRngListsHdr() loader.Sym {
+       return d.writeDebugMiscSecHdr(sym.SDWARFRANGE, true)
+}
+
+func (d *dwctxt) writeDebugLocListsHdr() loader.Sym {
+       return d.writeDebugMiscSecHdr(sym.SDWARFLOC, true)
+}
+
 func (d *dwctxt) writeDebugAddrHdr() loader.Sym {
-       su := d.ldr.MakeSymbolUpdater(d.ldr.CreateExtSym("", 0))
-       su.SetType(sym.SDWARFADDR)
-       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()
+       return d.writeDebugMiscSecHdr(sym.SDWARFADDR, false)
 }