Skip to content

Commit bef2bb8

Browse files
committed
cmd/compile,cmd/link: move to DWARF5-style location lists
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 <[email protected]> Reviewed-by: David Chase <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]>
1 parent 4c0a47a commit bef2bb8

File tree

3 files changed

+113
-26
lines changed

3 files changed

+113
-26
lines changed

src/cmd/compile/internal/ssa/debug.go

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1486,8 +1486,67 @@ func (state *debugState) writePendingEntry(varID VarID, endBlock, endValue ID) {
14861486
state.lists[varID] = list
14871487
}
14881488

1489-
// PutLocationList adds list (a location list in its intermediate representation) to listSym.
1489+
// PutLocationList adds list (a location list in its intermediate
1490+
// representation) to listSym.
14901491
func (debugInfo *FuncDebug) PutLocationList(list []byte, ctxt *obj.Link, listSym, startPC *obj.LSym) {
1492+
if buildcfg.Experiment.Dwarf5 {
1493+
debugInfo.PutLocationListDwarf5(list, ctxt, listSym, startPC)
1494+
} else {
1495+
debugInfo.PutLocationListDwarf4(list, ctxt, listSym, startPC)
1496+
}
1497+
}
1498+
1499+
// PutLocationListDwarf5 adds list (a location list in its intermediate
1500+
// representation) to listSym in DWARF 5 format. NB: this is a somewhat
1501+
// hacky implementation in that it actually reads a DWARF4 encoded
1502+
// info from list (with all its DWARF4-specific quirks) then re-encodes
1503+
// it in DWARF5. It would probably be better at some point to have
1504+
// ssa/debug encode the list in a version-independent form and then
1505+
// have this func (and PutLocationListDwarf4) intoduce the quirks.
1506+
func (debugInfo *FuncDebug) PutLocationListDwarf5(list []byte, ctxt *obj.Link, listSym, startPC *obj.LSym) {
1507+
getPC := debugInfo.GetPC
1508+
1509+
// base address entry
1510+
listSym.WriteInt(ctxt, listSym.Size, 1, dwarf.DW_LLE_base_addressx)
1511+
listSym.WriteDwTxtAddrx(ctxt, listSym.Size, startPC, ctxt.DwTextCount*2)
1512+
1513+
var stbuf, enbuf [10]byte
1514+
stb, enb := stbuf[:], enbuf[:]
1515+
// Re-read list, translating its address from block/value ID to PC.
1516+
for i := 0; i < len(list); {
1517+
begin := getPC(decodeValue(ctxt, readPtr(ctxt, list[i:])))
1518+
end := getPC(decodeValue(ctxt, readPtr(ctxt, list[i+ctxt.Arch.PtrSize:])))
1519+
1520+
// Write LLE_offset_pair tag followed by payload (ULEB for start
1521+
// and then end).
1522+
listSym.WriteInt(ctxt, listSym.Size, 1, dwarf.DW_LLE_offset_pair)
1523+
stb, enb = stb[:0], enb[:0]
1524+
stb = dwarf.AppendUleb128(stb, uint64(begin))
1525+
enb = dwarf.AppendUleb128(enb, uint64(end))
1526+
listSym.WriteBytes(ctxt, listSym.Size, stb)
1527+
listSym.WriteBytes(ctxt, listSym.Size, enb)
1528+
1529+
// The encoded data in "list" is in DWARF4 format, which uses
1530+
// a 2-byte length; DWARF5 uses an LEB-encoded value for this
1531+
// length. Read the length and then re-encode it.
1532+
i += 2 * ctxt.Arch.PtrSize
1533+
datalen := int(ctxt.Arch.ByteOrder.Uint16(list[i:]))
1534+
i += 2
1535+
stb = stb[:0]
1536+
stb = dwarf.AppendUleb128(stb, uint64(datalen))
1537+
listSym.WriteBytes(ctxt, listSym.Size, stb) // copy length
1538+
listSym.WriteBytes(ctxt, listSym.Size, list[i:i+datalen]) // loc desc
1539+
1540+
i += datalen
1541+
}
1542+
1543+
// Terminator
1544+
listSym.WriteInt(ctxt, listSym.Size, 1, dwarf.DW_LLE_end_of_list)
1545+
}
1546+
1547+
// PutLocationListDwarf4 adds list (a location list in its intermediate
1548+
// representation) to listSym in DWARF 4 format.
1549+
func (debugInfo *FuncDebug) PutLocationListDwarf4(list []byte, ctxt *obj.Link, listSym, startPC *obj.LSym) {
14911550
getPC := debugInfo.GetPC
14921551

14931552
if ctxt.UseBASEntries {

src/cmd/internal/dwarf/dwarf_defs.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,20 @@ const (
465465
DW_RLE_start_length = 0x7
466466
)
467467

468+
// Table 7.10 (DWARF version 5), containing the encodings for the
469+
// .debug_loclists entry formats.
470+
const (
471+
DW_LLE_end_of_list = 0x0
472+
DW_LLE_base_addressx = 0x1
473+
DW_LLE_startx_endx = 0x2
474+
DW_LLE_startx_length = 0x3
475+
DW_LLE_offset_pair = 0x4
476+
DW_LLE_default_location = 0x5
477+
DW_LLE_base_address = 0x6
478+
DW_LLE_start_end = 0x7
479+
DW_LLE_start_length = 0x8
480+
)
481+
468482
// Table 7.27 (DWARF version 5), containing the encodings for the
469483
// line number header entry formats.
470484
const (

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

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2261,7 +2261,7 @@ func (d *dwctxt) writedebugaddr(unit *sym.CompilationUnit, debugaddr loader.Sym)
22612261
fnSym := loader.Sym(s)
22622262
// NB: this looks at SDWARFFCN; it will need to also look
22632263
// at range and loc when they get there.
2264-
infosym, _, rangessym, _ := d.ldr.GetFuncDwarfAuxSyms(fnSym)
2264+
infosym, locsym, rangessym, _ := d.ldr.GetFuncDwarfAuxSyms(fnSym)
22652265

22662266
// Walk the relocations of the various DWARF symbols to
22672267
// collect relocations corresponding to indirect function
@@ -2271,6 +2271,9 @@ func (d *dwctxt) writedebugaddr(unit *sym.CompilationUnit, debugaddr loader.Sym)
22712271
if rangessym != 0 {
22722272
dsyms = append(dsyms, rangessym)
22732273
}
2274+
if locsym != 0 {
2275+
dsyms = append(dsyms, locsym)
2276+
}
22742277
for _, dsym := range dsyms {
22752278
drelocs := d.ldr.Relocs(dsym)
22762279
for ri := 0; ri < drelocs.Count(); ri++ {
@@ -2327,13 +2330,14 @@ func (d *dwctxt) dwarfGenerateDebugSyms() {
23272330

23282331
// Create the section symbols.
23292332
frameSym := mkSecSym(".debug_frame")
2330-
locSym := mkSecSym(".debug_loc")
23312333
lineSym := mkSecSym(".debug_line")
2332-
var rangesSym loader.Sym
2334+
var rangesSym, locSym loader.Sym
23332335
if buildcfg.Experiment.Dwarf5 {
23342336
rangesSym = mkSecSym(".debug_rnglists")
2337+
locSym = mkSecSym(".debug_loclists")
23352338
} else {
23362339
rangesSym = mkSecSym(".debug_ranges")
2340+
locSym = mkSecSym(".debug_loc")
23372341
}
23382342
infoSym := mkSecSym(".debug_info")
23392343
var addrSym loader.Sym
@@ -2343,17 +2347,19 @@ func (d *dwctxt) dwarfGenerateDebugSyms() {
23432347

23442348
// Create the section objects
23452349
lineSec := dwarfSecInfo{syms: []loader.Sym{lineSym}}
2346-
locSec := dwarfSecInfo{syms: []loader.Sym{locSym}}
23472350
frameSec := dwarfSecInfo{syms: []loader.Sym{frameSym}}
23482351
infoSec := dwarfSecInfo{syms: []loader.Sym{infoSym}}
2349-
var addrSec, rangesSec dwarfSecInfo
2352+
var addrSec, rangesSec, locSec dwarfSecInfo
23502353
if buildcfg.Experiment.Dwarf5 {
23512354
addrHdr := d.writeDebugAddrHdr()
23522355
addrSec.syms = []loader.Sym{addrSym, addrHdr}
23532356
rnglistsHdr := d.writeDebugRngListsHdr()
23542357
rangesSec.syms = []loader.Sym{rangesSym, rnglistsHdr}
2358+
loclistsHdr := d.writeDebugLocListsHdr()
2359+
locSec.syms = []loader.Sym{locSym, loclistsHdr}
23552360
} else {
23562361
rangesSec = dwarfSecInfo{syms: []loader.Sym{rangesSym}}
2362+
locSec = dwarfSecInfo{syms: []loader.Sym{locSym}}
23572363
}
23582364

23592365
// Create any new symbols that will be needed during the
@@ -2423,17 +2429,22 @@ func (d *dwctxt) dwarfGenerateDebugSyms() {
24232429
if buildcfg.Experiment.Dwarf5 {
24242430
// Compute total size of the DWARF5-specific .debug_* syms in
24252431
// each compilation unit.
2426-
var rltot, addrtot uint64
2432+
var rltot, addrtot, loctot uint64
24272433
for i := 0; i < ncu; i++ {
24282434
addrtot += uint64(d.ldr.SymSize(unitSyms[i].addrsym))
24292435
rs := unitSyms[i].rangessyms
24302436
for _, s := range rs {
24312437
rltot += uint64(d.ldr.SymSize(s))
24322438
}
2439+
loc := unitSyms[i].locsyms
2440+
for _, s := range loc {
2441+
loctot += uint64(d.ldr.SymSize(s))
2442+
}
24332443
}
24342444
// Call a helper to patch the length field in the headers.
24352445
patchHdr(&addrSec, addrtot)
24362446
patchHdr(&rangesSec, rltot)
2447+
patchHdr(&locSec, loctot)
24372448
}
24382449

24392450
// Stitch together the results.
@@ -2505,9 +2516,9 @@ func dwarfaddshstrings(ctxt *Link, add func(string)) {
25052516

25062517
secs := []string{"abbrev", "frame", "info", "loc", "line", "gdb_scripts"}
25072518
if buildcfg.Experiment.Dwarf5 {
2508-
secs = append(secs, "addr", "rnglists")
2519+
secs = append(secs, "addr", "rnglists", "loclists")
25092520
} else {
2510-
secs = append(secs, "ranges")
2521+
secs = append(secs, "ranges", "loc")
25112522
}
25122523

25132524
for _, sec := range secs {
@@ -2667,30 +2678,33 @@ func addDwsectCUSize(sname string, pkgname string, size uint64) {
26672678
dwsectCUSize[sname+"."+pkgname] += size
26682679
}
26692680

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 {
2681+
// writeDebugMiscSecHdr writes a header section for the new new DWARF5
2682+
// sections ".debug_addr", ".debug_loclists", and ".debug_rnglists".
2683+
// A description of the format/layout of these headers can be found in
2684+
// the DWARF5 spec in sections 7.27 (.debug_addr), 7.28
2685+
// (.debug_rnglists) and 7.29 (.debug_loclists).
2686+
func (d *dwctxt) writeDebugMiscSecHdr(st sym.SymKind, addOffsetEntryCount bool) loader.Sym {
26742687
su := d.ldr.MakeSymbolUpdater(d.ldr.CreateExtSym("", 0))
2675-
su.SetType(sym.SDWARFRANGE)
2688+
su.SetType(st)
26762689
su.SetReachable(true)
26772690
d.createUnitLength(su, 0) // will be filled in later.
26782691
su.AddUint16(d.arch, 5) // dwarf version (appendix F)
26792692
su.AddUint8(uint8(d.arch.PtrSize)) // address_size
2680-
su.AddUint8(0)
2693+
su.AddUint8(0) // segment selector
2694+
if addOffsetEntryCount {
2695+
su.AddUint32(d.arch, 0) // offset entry count (required but unused)
2696+
}
26812697
return su.Sym()
26822698
}
26832699

2684-
// writeDebugAddrHdr creates a new symbol and writes the content
2685-
// for the .debug_addr header payload to it, then returns the new sym.
2686-
// Format of the header is described in DWARF5 spec section 7.27.
2700+
func (d *dwctxt) writeDebugRngListsHdr() loader.Sym {
2701+
return d.writeDebugMiscSecHdr(sym.SDWARFRANGE, true)
2702+
}
2703+
2704+
func (d *dwctxt) writeDebugLocListsHdr() loader.Sym {
2705+
return d.writeDebugMiscSecHdr(sym.SDWARFLOC, true)
2706+
}
2707+
26872708
func (d *dwctxt) writeDebugAddrHdr() loader.Sym {
2688-
su := d.ldr.MakeSymbolUpdater(d.ldr.CreateExtSym("", 0))
2689-
su.SetType(sym.SDWARFADDR)
2690-
su.SetReachable(true)
2691-
d.createUnitLength(su, 0) // will be filled in later.
2692-
su.AddUint16(d.arch, 5) // dwarf version (appendix F)
2693-
su.AddUint8(uint8(d.arch.PtrSize)) // address_size
2694-
su.AddUint8(0)
2695-
return su.Sym()
2709+
return d.writeDebugMiscSecHdr(sym.SDWARFADDR, false)
26962710
}

0 commit comments

Comments
 (0)