mirror of
https://github.com/golang/go.git
synced 2025-05-07 08:32:59 +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
|
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) {
|
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
|
getPC := debugInfo.GetPC
|
||||||
|
|
||||||
if ctxt.UseBASEntries {
|
if ctxt.UseBASEntries {
|
||||||
|
@ -465,6 +465,20 @@ const (
|
|||||||
DW_RLE_start_length = 0x7
|
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
|
// Table 7.27 (DWARF version 5), containing the encodings for the
|
||||||
// line number header entry formats.
|
// line number header entry formats.
|
||||||
const (
|
const (
|
||||||
|
@ -2261,7 +2261,7 @@ func (d *dwctxt) writedebugaddr(unit *sym.CompilationUnit, debugaddr loader.Sym)
|
|||||||
fnSym := loader.Sym(s)
|
fnSym := loader.Sym(s)
|
||||||
// NB: this looks at SDWARFFCN; it will need to also look
|
// NB: this looks at SDWARFFCN; it will need to also look
|
||||||
// at range and loc when they get there.
|
// 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
|
// Walk the relocations of the various DWARF symbols to
|
||||||
// collect relocations corresponding to indirect function
|
// collect relocations corresponding to indirect function
|
||||||
@ -2271,6 +2271,9 @@ func (d *dwctxt) writedebugaddr(unit *sym.CompilationUnit, debugaddr loader.Sym)
|
|||||||
if rangessym != 0 {
|
if rangessym != 0 {
|
||||||
dsyms = append(dsyms, rangessym)
|
dsyms = append(dsyms, rangessym)
|
||||||
}
|
}
|
||||||
|
if locsym != 0 {
|
||||||
|
dsyms = append(dsyms, locsym)
|
||||||
|
}
|
||||||
for _, dsym := range dsyms {
|
for _, dsym := range dsyms {
|
||||||
drelocs := d.ldr.Relocs(dsym)
|
drelocs := d.ldr.Relocs(dsym)
|
||||||
for ri := 0; ri < drelocs.Count(); ri++ {
|
for ri := 0; ri < drelocs.Count(); ri++ {
|
||||||
@ -2327,13 +2330,14 @@ func (d *dwctxt) dwarfGenerateDebugSyms() {
|
|||||||
|
|
||||||
// Create the section symbols.
|
// Create the section symbols.
|
||||||
frameSym := mkSecSym(".debug_frame")
|
frameSym := mkSecSym(".debug_frame")
|
||||||
locSym := mkSecSym(".debug_loc")
|
|
||||||
lineSym := mkSecSym(".debug_line")
|
lineSym := mkSecSym(".debug_line")
|
||||||
var rangesSym loader.Sym
|
var rangesSym, locSym loader.Sym
|
||||||
if buildcfg.Experiment.Dwarf5 {
|
if buildcfg.Experiment.Dwarf5 {
|
||||||
rangesSym = mkSecSym(".debug_rnglists")
|
rangesSym = mkSecSym(".debug_rnglists")
|
||||||
|
locSym = mkSecSym(".debug_loclists")
|
||||||
} else {
|
} else {
|
||||||
rangesSym = mkSecSym(".debug_ranges")
|
rangesSym = mkSecSym(".debug_ranges")
|
||||||
|
locSym = mkSecSym(".debug_loc")
|
||||||
}
|
}
|
||||||
infoSym := mkSecSym(".debug_info")
|
infoSym := mkSecSym(".debug_info")
|
||||||
var addrSym loader.Sym
|
var addrSym loader.Sym
|
||||||
@ -2343,17 +2347,19 @@ func (d *dwctxt) dwarfGenerateDebugSyms() {
|
|||||||
|
|
||||||
// Create the section objects
|
// Create the section objects
|
||||||
lineSec := dwarfSecInfo{syms: []loader.Sym{lineSym}}
|
lineSec := dwarfSecInfo{syms: []loader.Sym{lineSym}}
|
||||||
locSec := dwarfSecInfo{syms: []loader.Sym{locSym}}
|
|
||||||
frameSec := dwarfSecInfo{syms: []loader.Sym{frameSym}}
|
frameSec := dwarfSecInfo{syms: []loader.Sym{frameSym}}
|
||||||
infoSec := dwarfSecInfo{syms: []loader.Sym{infoSym}}
|
infoSec := dwarfSecInfo{syms: []loader.Sym{infoSym}}
|
||||||
var addrSec, rangesSec dwarfSecInfo
|
var addrSec, rangesSec, locSec dwarfSecInfo
|
||||||
if buildcfg.Experiment.Dwarf5 {
|
if buildcfg.Experiment.Dwarf5 {
|
||||||
addrHdr := d.writeDebugAddrHdr()
|
addrHdr := d.writeDebugAddrHdr()
|
||||||
addrSec.syms = []loader.Sym{addrSym, addrHdr}
|
addrSec.syms = []loader.Sym{addrSym, addrHdr}
|
||||||
rnglistsHdr := d.writeDebugRngListsHdr()
|
rnglistsHdr := d.writeDebugRngListsHdr()
|
||||||
rangesSec.syms = []loader.Sym{rangesSym, rnglistsHdr}
|
rangesSec.syms = []loader.Sym{rangesSym, rnglistsHdr}
|
||||||
|
loclistsHdr := d.writeDebugLocListsHdr()
|
||||||
|
locSec.syms = []loader.Sym{locSym, loclistsHdr}
|
||||||
} else {
|
} else {
|
||||||
rangesSec = dwarfSecInfo{syms: []loader.Sym{rangesSym}}
|
rangesSec = dwarfSecInfo{syms: []loader.Sym{rangesSym}}
|
||||||
|
locSec = dwarfSecInfo{syms: []loader.Sym{locSym}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create any new symbols that will be needed during the
|
// Create any new symbols that will be needed during the
|
||||||
@ -2423,17 +2429,22 @@ func (d *dwctxt) dwarfGenerateDebugSyms() {
|
|||||||
if buildcfg.Experiment.Dwarf5 {
|
if buildcfg.Experiment.Dwarf5 {
|
||||||
// Compute total size of the DWARF5-specific .debug_* syms in
|
// Compute total size of the DWARF5-specific .debug_* syms in
|
||||||
// each compilation unit.
|
// each compilation unit.
|
||||||
var rltot, addrtot uint64
|
var rltot, addrtot, loctot uint64
|
||||||
for i := 0; i < ncu; i++ {
|
for i := 0; i < ncu; i++ {
|
||||||
addrtot += uint64(d.ldr.SymSize(unitSyms[i].addrsym))
|
addrtot += uint64(d.ldr.SymSize(unitSyms[i].addrsym))
|
||||||
rs := unitSyms[i].rangessyms
|
rs := unitSyms[i].rangessyms
|
||||||
for _, s := range rs {
|
for _, s := range rs {
|
||||||
rltot += uint64(d.ldr.SymSize(s))
|
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.
|
// Call a helper to patch the length field in the headers.
|
||||||
patchHdr(&addrSec, addrtot)
|
patchHdr(&addrSec, addrtot)
|
||||||
patchHdr(&rangesSec, rltot)
|
patchHdr(&rangesSec, rltot)
|
||||||
|
patchHdr(&locSec, loctot)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stitch together the results.
|
// Stitch together the results.
|
||||||
@ -2505,9 +2516,9 @@ func dwarfaddshstrings(ctxt *Link, add func(string)) {
|
|||||||
|
|
||||||
secs := []string{"abbrev", "frame", "info", "loc", "line", "gdb_scripts"}
|
secs := []string{"abbrev", "frame", "info", "loc", "line", "gdb_scripts"}
|
||||||
if buildcfg.Experiment.Dwarf5 {
|
if buildcfg.Experiment.Dwarf5 {
|
||||||
secs = append(secs, "addr", "rnglists")
|
secs = append(secs, "addr", "rnglists", "loclists")
|
||||||
} else {
|
} else {
|
||||||
secs = append(secs, "ranges")
|
secs = append(secs, "ranges", "loc")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, sec := range secs {
|
for _, sec := range secs {
|
||||||
@ -2667,30 +2678,33 @@ func addDwsectCUSize(sname string, pkgname string, size uint64) {
|
|||||||
dwsectCUSize[sname+"."+pkgname] += size
|
dwsectCUSize[sname+"."+pkgname] += size
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeDebugAddrHdr creates a new symbol and writes the content
|
// writeDebugMiscSecHdr writes a header section for the new new DWARF5
|
||||||
// for the .debug_rnglists header payload to it, then returns the new sym.
|
// sections ".debug_addr", ".debug_loclists", and ".debug_rnglists".
|
||||||
// Format of the header is described in DWARF5 spec section 7.28.
|
// A description of the format/layout of these headers can be found in
|
||||||
func (d *dwctxt) writeDebugRngListsHdr() loader.Sym {
|
// 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 := d.ldr.MakeSymbolUpdater(d.ldr.CreateExtSym("", 0))
|
||||||
su.SetType(sym.SDWARFRANGE)
|
su.SetType(st)
|
||||||
su.SetReachable(true)
|
su.SetReachable(true)
|
||||||
d.createUnitLength(su, 0) // will be filled in later.
|
d.createUnitLength(su, 0) // will be filled in later.
|
||||||
su.AddUint16(d.arch, 5) // dwarf version (appendix F)
|
su.AddUint16(d.arch, 5) // dwarf version (appendix F)
|
||||||
su.AddUint8(uint8(d.arch.PtrSize)) // address_size
|
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()
|
return su.Sym()
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeDebugAddrHdr creates a new symbol and writes the content
|
func (d *dwctxt) writeDebugRngListsHdr() loader.Sym {
|
||||||
// for the .debug_addr header payload to it, then returns the new sym.
|
return d.writeDebugMiscSecHdr(sym.SDWARFRANGE, true)
|
||||||
// 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))
|
func (d *dwctxt) writeDebugLocListsHdr() loader.Sym {
|
||||||
su.SetType(sym.SDWARFADDR)
|
return d.writeDebugMiscSecHdr(sym.SDWARFLOC, true)
|
||||||
su.SetReachable(true)
|
}
|
||||||
d.createUnitLength(su, 0) // will be filled in later.
|
|
||||||
su.AddUint16(d.arch, 5) // dwarf version (appendix F)
|
func (d *dwctxt) writeDebugAddrHdr() loader.Sym {
|
||||||
su.AddUint8(uint8(d.arch.PtrSize)) // address_size
|
return d.writeDebugMiscSecHdr(sym.SDWARFADDR, false)
|
||||||
su.AddUint8(0)
|
|
||||||
return su.Sym()
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user