From: Than McIntosh Date: Wed, 10 Jun 2020 17:14:15 +0000 (-0400) Subject: [dev.link] cmd/link: rework line table generation to reduce heap mem X-Git-Tag: go1.16beta1~1378^2~85 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=d08bab99b74b6da2f10e16fdcd4fb4b410ae07cb;p=gostls13.git [dev.link] cmd/link: rework line table generation to reduce heap mem Rework the way symbols are handled in DWARF line table generation to eliminate copying the data payload for all SWDWARFLINES syms (emitted by the compiler) into the payload of the ".debug_line" section symbol (generated by the linker). Instead, chain together the SWDWARFLINES symbols into a list, then append that list to the section sym list in dwarfp (this moves us from a single monolithic .debug_line to a .debug_line section sym followed by a list symbols (one per function and an epilog symbol per compilation unit). To enable this work, move the emission of the DW_LNE_set_address op (at the start of each function) from the linker to the compiler. Change-Id: Iec61b44a451f7a386c82a89bf944de482b018789 Reviewed-on: https://go-review.googlesource.com/c/go/+/237427 Reviewed-by: Cherry Zhang Reviewed-by: Jeremy Faller --- diff --git a/src/cmd/internal/obj/dwarf.go b/src/cmd/internal/obj/dwarf.go index 4118c6442c..1811ac7881 100644 --- a/src/cmd/internal/obj/dwarf.go +++ b/src/cmd/internal/obj/dwarf.go @@ -44,6 +44,13 @@ func (ctxt *Link) generateDebugLinesSymbol(s, lines *LSym) { } } + // Emit a LNE_set_address extended opcode, so as to establish the + // starting text address of this function. + dctxt.AddUint8(lines, 0) + dwarf.Uleb128put(dctxt, lines, 1+int64(ctxt.Arch.PtrSize)) + dctxt.AddUint8(lines, dwarf.DW_LNE_set_address) + dctxt.AddAddress(lines, s, 0) + // Set up the debug_lines state machine. // NB: This state machine is reset to this state when we've finished // generating the line table. See below. diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index da05d1bd2e..89dd4b37f1 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -1172,7 +1172,14 @@ func expandFile(fname string) string { return expandGoroot(fname) } -func (d *dwctxt) writelines(unit *sym.CompilationUnit, ls loader.Sym) { +// writelines collects up and chains together the symbols needed to +// form the DWARF line table for the specified compilation unit, +// appends them to the list 'syms' and returns the updated list. +// Additions will include an initial symbol containing the line table +// header and prolog (with file table), then a series of +// compiler-emitted line table symbols (one per live function), and +// finally an epilog symbol containing an end-of-sequence operator. +func (d *dwctxt) writelines(unit *sym.CompilationUnit, syms []loader.Sym) []loader.Sym { is_stmt := uint8(1) // initially = recommended default_is_stmt = 1, tracks is_stmt toggles. @@ -1180,17 +1187,18 @@ func (d *dwctxt) writelines(unit *sym.CompilationUnit, ls loader.Sym) { headerstart := int64(-1) headerend := int64(-1) + ls := d.ldr.CreateExtSym("", 0) + syms = append(syms, ls) + d.ldr.SetAttrNotInSymbolTable(ls, true) + d.ldr.SetAttrReachable(ls, true) lsu := d.ldr.MakeSymbolUpdater(ls) - newattr(unit.DWInfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, lsu.Size(), dwSym(ls)) - - internalExec := d.linkctxt.BuildMode == BuildModeExe && d.linkctxt.IsInternal() - addAddrPlus := loader.GenAddAddrPlusFunc(internalExec) + lsu.SetType(sym.SDWARFLINES) + newattr(unit.DWInfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, 0, dwSym(ls)) // Write .debug_line Line Number Program Header (sec 6.2.4) // Fields marked with (*) must be changed for 64-bit dwarf unitLengthOffset := lsu.Size() d.createUnitLength(lsu, 0) // unit_length (*), filled in at end - unitstart = lsu.Size() lsu.AddUint16(d.arch, 2) // dwarf version (appendix F) -- version 3 is incompatible w/ XCode 9.0's dsymutil, latest supported on OSX 10.12 as of 2018-05 headerLengthOffset := lsu.Size() @@ -1245,36 +1253,31 @@ func (d *dwctxt) writelines(unit *sym.CompilationUnit, ls loader.Sym) { lsu.AddUint8(0) // terminate file_names. headerend = lsu.Size() + unitlen := lsu.Size() - unitstart // Output the state machine for each function remaining. - var lastAddr int64 for _, s := range unit.Textp { fnSym := loader.Sym(s) - - // Set the PC. - lsu.AddUint8(0) - dwarf.Uleb128put(d, lsDwsym, 1+int64(d.arch.PtrSize)) - lsu.AddUint8(dwarf.DW_LNE_set_address) - addr := addAddrPlus(lsu, d.arch, fnSym, 0) - // Make sure the units are sorted. - if addr < lastAddr { - d.linkctxt.Errorf(fnSym, "address wasn't increasing %x < %x", - addr, lastAddr) - } - lastAddr = addr - - // Output the line table. - // TODO: Now that we have all the debug information in separate - // symbols, it would make sense to use a rope, and concatenate them all - // together rather then the append() below. This would allow us to have - // the compiler emit the DW_LNE_set_address and a rope data structure - // to concat them all together in the output. _, _, _, lines := d.ldr.GetFuncDwarfAuxSyms(fnSym) + + // Chain the line symbol onto the list. if lines != 0 { - lsu.AddBytes(d.ldr.Data(lines)) + syms = append(syms, lines) + unitlen += int64(len(d.ldr.Data(lines))) } } + // NB: at some point if we have an end sequence op + // after each function (to enable reordering) generated + // in the compiler, we can get rid of this. + epilogsym := d.ldr.CreateExtSym("", 0) + syms = append(syms, epilogsym) + d.ldr.SetAttrNotInSymbolTable(epilogsym, true) + d.ldr.SetAttrReachable(epilogsym, true) + elsu := d.ldr.MakeSymbolUpdater(epilogsym) + elsu.SetType(sym.SDWARFLINES) + elsDwsym := dwSym(epilogsym) + // Issue 38192: the DWARF standard specifies that when you issue // an end-sequence op, the PC value should be one past the last // text address in the translation unit, so apply a delta to the @@ -1283,24 +1286,28 @@ func (d *dwctxt) writelines(unit *sym.CompilationUnit, ls loader.Sym) { // table, which we don't want. The 1 + ptrsize amount is somewhat // arbitrary, this is chosen to be consistent with the way LLVM // emits its end sequence ops. - lsu.AddUint8(dwarf.DW_LNS_advance_pc) - dwarf.Uleb128put(d, lsDwsym, int64(1+d.arch.PtrSize)) + elsu.AddUint8(dwarf.DW_LNS_advance_pc) + dwarf.Uleb128put(d, elsDwsym, int64(1+d.arch.PtrSize)) // Emit an end-sequence at the end of the unit. - lsu.AddUint8(0) // start extended opcode - dwarf.Uleb128put(d, lsDwsym, 1) - lsu.AddUint8(dwarf.DW_LNE_end_sequence) + elsu.AddUint8(0) // start extended opcode + dwarf.Uleb128put(d, elsDwsym, 1) + elsu.AddUint8(dwarf.DW_LNE_end_sequence) + unitlen += elsu.Size() if d.linkctxt.HeadType == objabi.Haix { - saveDwsectCUSize(".debug_line", unit.Lib.Pkg, uint64(lsu.Size()-unitLengthOffset)) + saveDwsectCUSize(".debug_line", unit.Lib.Pkg, uint64(unitlen)) } + if isDwarf64(d.linkctxt) { - lsu.SetUint(d.arch, unitLengthOffset+4, uint64(lsu.Size()-unitstart)) // +4 because of 0xFFFFFFFF + lsu.SetUint(d.arch, unitLengthOffset+4, uint64(unitlen)) // +4 because of 0xFFFFFFFF lsu.SetUint(d.arch, headerLengthOffset, uint64(headerend-headerstart)) } else { - lsu.SetUint32(d.arch, unitLengthOffset, uint32(lsu.Size()-unitstart)) + lsu.SetUint32(d.arch, unitLengthOffset, uint32(unitlen)) lsu.SetUint32(d.arch, headerLengthOffset, uint32(headerend-headerstart)) } + + return syms } // writepcranges generates the DW_AT_ranges table for compilation unit cu. @@ -1963,6 +1970,7 @@ func (d *dwctxt) dwarfGenerateDebugSyms() { dlu.SetType(sym.SDWARFSECT) d.ldr.SetAttrReachable(debugLine, true) dwarfp = append(dwarfp, dwarfSecInfo{syms: []loader.Sym{debugLine}}) + linesec := &dwarfp[len(dwarfp)-1] debugRanges := d.ldr.LookupOrCreateSym(".debug_ranges", 0) dru := d.ldr.MakeSymbolUpdater(debugRanges) @@ -1975,7 +1983,7 @@ func (d *dwctxt) dwarfGenerateDebugSyms() { if u.DWInfo.Abbrev == dwarf.DW_ABRV_COMPUNIT_TEXTLESS { continue } - d.writelines(u, debugLine) + linesec.syms = d.writelines(u, linesec.syms) base := loader.Sym(u.Textp[0]) d.writepcranges(u, base, u.PCs, debugRanges) }