mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
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 <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: David Chase <drchase@google.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
This commit is contained in:
parent
4c0a47a8ff
commit
bef2bb80a9
@ -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 {
|
||||
|
@ -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 (
|
||||
|
@ -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) 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()
|
||||
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 {
|
||||
return d.writeDebugMiscSecHdr(sym.SDWARFADDR, false)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user