diff --git a/src/cmd/compile/internal/ssa/debug.go b/src/cmd/compile/internal/ssa/debug.go index 381777c17d..59d0294264 100644 --- a/src/cmd/compile/internal/ssa/debug.go +++ b/src/cmd/compile/internal/ssa/debug.go @@ -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 { diff --git a/src/cmd/internal/dwarf/dwarf_defs.go b/src/cmd/internal/dwarf/dwarf_defs.go index db4245e95d..b4675cb193 100644 --- a/src/cmd/internal/dwarf/dwarf_defs.go +++ b/src/cmd/internal/dwarf/dwarf_defs.go @@ -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 ( diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index cabdedecf1..602d70ddb9 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -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) }