From 9c833831b2bdaa465349194797cf3894cb85f9c4 Mon Sep 17 00:00:00 2001 From: Alessandro Arzilli Date: Tue, 24 Apr 2018 13:05:10 +0200 Subject: [PATCH] cmd/link: move dwarf part of DWARF generation before type name mangling Splits part of dwarfgeneratedebugsyms into a new function, dwarfGenerateDebugInfo which is called between deadcode elimination and type name mangling. This function takes care of collecting and processing the DIEs for all functions and package-level variables and also generates DIEs for all types used in the program. Fixes #23733 Change-Id: I75ef0608fbed2dffc3be7a477f1b03e7e740ec61 Reviewed-on: https://go-review.googlesource.com/111237 Run-TryBot: Heschi Kreinick TryBot-Result: Gobot Gobot Reviewed-by: Heschi Kreinick --- misc/cgo/testplugin/src/checkdwarf/main.go | 106 +++++++ misc/cgo/testplugin/test.bash | 4 + src/cmd/link/internal/ld/data.go | 2 +- src/cmd/link/internal/ld/dwarf.go | 320 ++++++++++----------- src/cmd/link/internal/ld/lib.go | 1 - src/cmd/link/internal/ld/link.go | 3 + src/cmd/link/internal/ld/main.go | 1 + src/cmd/link/internal/objfile/objfile.go | 2 + src/cmd/link/internal/sym/symbol.go | 1 + 9 files changed, 276 insertions(+), 164 deletions(-) create mode 100644 misc/cgo/testplugin/src/checkdwarf/main.go diff --git a/misc/cgo/testplugin/src/checkdwarf/main.go b/misc/cgo/testplugin/src/checkdwarf/main.go new file mode 100644 index 00000000000000..b689c4af15f47b --- /dev/null +++ b/misc/cgo/testplugin/src/checkdwarf/main.go @@ -0,0 +1,106 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Usage: +// +// checkdwarf +// +// Opens , which must be an executable or a library and checks that +// there is an entry in .debug_info whose name ends in + +package main + +import ( + "debug/dwarf" + "debug/elf" + "debug/macho" + "debug/pe" + "fmt" + "os" + "strings" +) + +func usage() { + fmt.Fprintf(os.Stderr, "checkdwarf executable-or-library DIE-suffix\n") +} + +type dwarfer interface { + DWARF() (*dwarf.Data, error) +} + +func openElf(path string) dwarfer { + exe, err := elf.Open(path) + if err != nil { + return nil + } + return exe +} + +func openMacho(path string) dwarfer { + exe, err := macho.Open(path) + if err != nil { + return nil + } + return exe +} + +func openPE(path string) dwarfer { + exe, err := pe.Open(path) + if err != nil { + return nil + } + return exe +} + +func main() { + if len(os.Args) != 3 { + usage() + } + + exePath := os.Args[1] + dieSuffix := os.Args[2] + + var exe dwarfer + + for _, openfn := range []func(string) dwarfer{openMacho, openPE, openElf} { + exe = openfn(exePath) + if exe != nil { + break + } + } + + if exe == nil { + fmt.Fprintf(os.Stderr, "could not open %s", exePath) + os.Exit(1) + } + + data, err := exe.DWARF() + if err != nil { + fmt.Fprintf(os.Stderr, "error opening DWARF: %v", err) + os.Exit(1) + } + + rdr := data.Reader() + for { + e, err := rdr.Next() + if err != nil { + fmt.Fprintf(os.Stderr, "error reading DWARF: %v", err) + os.Exit(1) + } + if e == nil { + break + } + name, hasname := e.Val(dwarf.AttrName).(string) + if !hasname { + continue + } + if strings.HasSuffix(name, dieSuffix) { + // found + os.Exit(0) + } + } + + fmt.Fprintf(os.Stderr, "no entry with a name ending in %q was found", dieSuffix) + os.Exit(1) +} diff --git a/misc/cgo/testplugin/test.bash b/misc/cgo/testplugin/test.bash index bf8ed3cd191eae..5a87f5e74673d5 100755 --- a/misc/cgo/testplugin/test.bash +++ b/misc/cgo/testplugin/test.bash @@ -32,6 +32,10 @@ GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o=unnamed1.so u GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o=unnamed2.so unnamed2/main.go GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" host +# test that DWARF sections are emitted for plugins and programs importing "plugin" +go run src/checkdwarf/main.go plugin2.so plugin2.UnexportedNameReuse +go run src/checkdwarf/main.go host main.main + LD_LIBRARY_PATH=$(pwd) ./host # Test that types and itabs get properly uniqified. diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index ff0d3a8d84e55b..ee98aef20dc199 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -1602,7 +1602,7 @@ func (ctxt *Link) dodata() { datap = append(datap, data[symn]...) } - dwarfgeneratedebugsyms(ctxt) + dwarfGenerateDebugSyms(ctxt) var i int for ; i < len(dwarfp); i++ { diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 4cb9295f438de5..959fc8290c08d9 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -21,6 +21,7 @@ import ( "cmd/link/internal/sym" "fmt" "log" + "sort" "strings" ) @@ -828,6 +829,16 @@ func synthesizechantypes(ctxt *Link, die *dwarf.DWDie) { } } +func dwarfDefineGlobal(ctxt *Link, s *sym.Symbol, str string, v int64, gotype *sym.Symbol) { + dv := newdie(ctxt, &dwglobals, dwarf.DW_ABRV_VARIABLE, str, int(s.Version)) + newabslocexprattr(dv, v, s) + if s.Version == 0 { + newattr(dv, dwarf.DW_AT_external, dwarf.DW_CLS_FLAG, 1, 0) + } + dt := defgotype(ctxt, gotype) + newrefattr(dv, dwarf.DW_AT_type, dt) +} + // For use with pass.c::genasmsym func defdwsymb(ctxt *Link, s *sym.Symbol, str string, t SymbolType, v int64, gotype *sym.Symbol) { if strings.HasPrefix(str, "go.string.") { @@ -837,32 +848,24 @@ func defdwsymb(ctxt *Link, s *sym.Symbol, str string, t SymbolType, v int64, got return } - if strings.HasPrefix(str, "type.") && str != "type.*" && !strings.HasPrefix(str, "type..") { - defgotype(ctxt, s) - return - } - - var dv *dwarf.DWDie - - var dt *sym.Symbol switch t { - default: - return - case DataSym, BSSSym: - dv = newdie(ctxt, &dwglobals, dwarf.DW_ABRV_VARIABLE, str, int(s.Version)) - newabslocexprattr(dv, v, s) - if s.Version == 0 { - newattr(dv, dwarf.DW_AT_external, dwarf.DW_CLS_FLAG, 1, 0) + switch s.Type { + case sym.SDATA, sym.SNOPTRDATA, sym.STYPE, sym.SBSS, sym.SNOPTRBSS, sym.STLSBSS: + // ok + case sym.SRODATA: + if gotype != nil { + defgotype(ctxt, gotype) + } + return + default: + return } - fallthrough - case AutoSym, ParamSym, DeletedAutoSym: - dt = defgotype(ctxt, gotype) - } + dwarfDefineGlobal(ctxt, s, str, v, gotype) - if dv != nil { - newrefattr(dv, dwarf.DW_AT_type, dt) + case AutoSym, ParamSym, DeletedAutoSym: + defgotype(ctxt, gotype) } } @@ -875,27 +878,17 @@ type compilationUnit struct { dwinfo *dwarf.DWDie // CU root DIE funcDIEs []*sym.Symbol // Function DIE subtrees absFnDIEs []*sym.Symbol // Abstract function DIE subtrees + rangeSyms []*sym.Symbol // symbols for debug_range } -// getCompilationUnits divides the symbols in ctxt.Textp by package. -func getCompilationUnits(ctxt *Link) []*compilationUnit { - units := []*compilationUnit{} - index := make(map[*sym.Library]*compilationUnit) +// calcCompUnitRanges calculates the PC ranges of the compilation units. +func calcCompUnitRanges(ctxt *Link) { var prevUnit *compilationUnit for _, s := range ctxt.Textp { if s.FuncInfo == nil { continue } - unit := index[s.Lib] - if unit == nil { - unit = &compilationUnit{lib: s.Lib} - if s := ctxt.Syms.ROLookup(dwarf.ConstInfoPrefix+s.Lib.Pkg, 0); s != nil { - importInfoSymbol(ctxt, s) - unit.consts = s - } - units = append(units, unit) - index[s.Lib] = unit - } + unit := ctxt.compUnitByPackage[s.Lib] // Update PC ranges. // @@ -910,7 +903,6 @@ func getCompilationUnits(ctxt *Link) []*compilationUnit { } unit.pcs[len(unit.pcs)-1].End = s.Value - unit.lib.Textp[0].Value + s.Size } - return units } func movetomodule(parent *dwarf.DWDie) { @@ -1064,62 +1056,13 @@ func importInfoSymbol(ctxt *Link, dsym *sym.Symbol) { for i := range dsym.R { r := &dsym.R[i] // Copying sym.Reloc has measurable impact on performance if r.Type == objabi.R_DWARFSECREF && r.Sym.Size == 0 { - if ctxt.BuildMode == BuildModeShared { - // These type symbols may not be present in BuildModeShared. Skip. - continue - } n := nameFromDIESym(r.Sym) defgotype(ctxt, ctxt.Syms.Lookup("type."+n, 0)) } } } -// For the specified function, collect symbols corresponding to any -// "abstract" subprogram DIEs referenced. The first case of interest -// is a concrete subprogram DIE, which will refer to its corresponding -// abstract subprogram DIE, and then there can be references from a -// non-abstract subprogram DIE to the abstract subprogram DIEs for any -// functions inlined into this one. -// -// A given abstract subprogram DIE can be referenced in numerous -// places (even within the same DIE), so it is important to make sure -// it gets imported and added to the absfuncs lists only once. - -func collectAbstractFunctions(ctxt *Link, fn *sym.Symbol, dsym *sym.Symbol, absfuncs []*sym.Symbol) []*sym.Symbol { - - var newabsfns []*sym.Symbol - - // Walk the relocations on the primary subprogram DIE and look for - // references to abstract funcs. - for i := range dsym.R { - reloc := &dsym.R[i] // Copying sym.Reloc has measurable impact on performance - candsym := reloc.Sym - if reloc.Type != objabi.R_DWARFSECREF { - continue - } - if !strings.HasPrefix(candsym.Name, dwarf.InfoPrefix) { - continue - } - if !strings.HasSuffix(candsym.Name, dwarf.AbstractFuncSuffix) { - continue - } - if candsym.Attr.OnList() { - continue - } - candsym.Attr |= sym.AttrOnList - newabsfns = append(newabsfns, candsym) - } - - // Import any new symbols that have turned up. - for _, absdsym := range newabsfns { - importInfoSymbol(ctxt, absdsym) - absfuncs = append(absfuncs, absdsym) - } - - return absfuncs -} - -func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbol) (dwinfo *dwarf.DWDie, funcs []*sym.Symbol, absfuncs []*sym.Symbol) { +func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) (dwinfo *dwarf.DWDie) { var dwarfctxt dwarf.Context = dwctxt{ctxt} is_stmt := uint8(1) // initially = recommended default_is_stmt = 1, tracks is_stmt toggles. @@ -1130,7 +1073,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo lang := dwarf.DW_LANG_Go - dwinfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, lib.Pkg, 0) + dwinfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, unit.lib.Pkg, 0) newattr(dwinfo, dwarf.DW_AT_language, dwarf.DW_CLS_CONSTANT, int64(lang), 0) newattr(dwinfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, ls.Size, ls) // OS X linker requires compilation dir or absolute path in comp unit name to output debug info. @@ -1139,7 +1082,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo // the linker directory. If we move CU construction into the // compiler, this should happen naturally. newattr(dwinfo, dwarf.DW_AT_comp_dir, dwarf.DW_CLS_STRING, int64(len(compDir)), compDir) - producerExtra := ctxt.Syms.Lookup(dwarf.CUInfoPrefix+"producer."+lib.Pkg, 0) + producerExtra := ctxt.Syms.Lookup(dwarf.CUInfoPrefix+"producer."+unit.lib.Pkg, 0) producer := "Go cmd/compile " + objabi.Version if len(producerExtra.P) > 0 { // We put a semicolon before the flags to clearly @@ -1183,7 +1126,8 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo // Create the file table. fileNums maps from global file // indexes (created by numberfile) to CU-local indexes. fileNums := make(map[int]int) - for _, s := range textp { // textp has been dead-code-eliminated already. + for _, s := range unit.lib.Textp { // textp has been dead-code-eliminated already. + dsym := ctxt.Syms.Lookup(dwarf.InfoPrefix+s.Name, int(s.Version)) for _, f := range s.FuncInfo.File { if _, ok := fileNums[int(f.Value)]; ok { continue @@ -1195,26 +1139,21 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo ls.AddUint8(0) ls.AddUint8(0) } - - // Look up the .debug_info sym for the function. We do this - // now so that we can walk the sym's relocations to discover - // files that aren't mentioned in S.FuncInfo.File (for - // example, files mentioned only in an inlined subroutine). - dsym := ctxt.Syms.Lookup(dwarf.InfoPrefix+s.Name, int(s.Version)) - importInfoSymbol(ctxt, dsym) - for ri := range dsym.R { + for ri := 0; ri < len(dsym.R); ri++ { r := &dsym.R[ri] if r.Type != objabi.R_DWARFFILEREF { continue } - _, ok := fileNums[int(r.Sym.Value)] - if !ok { - fileNums[int(r.Sym.Value)] = len(fileNums) + 1 - Addstring(ls, r.Sym.Name) - ls.AddUint8(0) - ls.AddUint8(0) - ls.AddUint8(0) + // A file that is only mentioned in an inlined subroutine will appear + // as a R_DWARFFILEREF but not in s.FuncInfo.File + if _, ok := fileNums[int(r.Sym.Value)]; ok { + continue } + fileNums[int(r.Sym.Value)] = len(fileNums) + 1 + Addstring(ls, r.Sym.Name) + ls.AddUint8(0) + ls.AddUint8(0) + ls.AddUint8(0) } } @@ -1227,7 +1166,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo dwarf.Uleb128put(dwarfctxt, ls, 1+int64(ctxt.Arch.PtrSize)) ls.AddUint8(dwarf.DW_LNE_set_address) - s := textp[0] + s := unit.lib.Textp[0] pc := s.Value line := 1 file := 1 @@ -1236,19 +1175,12 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo var pcfile Pciter var pcline Pciter var pcstmt Pciter - for i, s := range textp { - dsym := ctxt.Syms.Lookup(dwarf.InfoPrefix+s.Name, int(s.Version)) - funcs = append(funcs, dsym) - absfuncs = collectAbstractFunctions(ctxt, s, dsym, absfuncs) - + for i, s := range unit.lib.Textp { finddebugruntimepath(s) - isStmtsSym := ctxt.Syms.ROLookup(dwarf.IsStmtPrefix+s.Name, int(s.Version)) - pctostmtData := sym.Pcdata{P: isStmtsSym.P} - pciterinit(ctxt, &pcfile, &s.FuncInfo.Pcfile) pciterinit(ctxt, &pcline, &s.FuncInfo.Pcline) - pciterinit(ctxt, &pcstmt, &pctostmtData) + pciterinit(ctxt, &pcstmt, &sym.Pcdata{P: s.FuncInfo.IsStmtSym.P}) if pcstmt.done != 0 { // Assembly files lack a pcstmt section, we assume that every instruction @@ -1312,7 +1244,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo pciternext(&pcline) } } - if is_stmt == 0 && i < len(textp)-1 { + if is_stmt == 0 && i < len(unit.lib.Textp)-1 { // If there is more than one function, ensure default value is established. is_stmt = 1 ls.AddUint8(uint8(dwarf.DW_LNS_negate_stmt)) @@ -1333,7 +1265,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo // DIE flavors (ex: variables) then those DIEs would need to // be included below. missing := make(map[int]interface{}) - for _, f := range funcs { + for _, f := range unit.funcDIEs { for ri := range f.R { r := &f.R[ri] if r.Type != objabi.R_DWARFFILEREF { @@ -1364,7 +1296,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo } } - return dwinfo, funcs, absfuncs + return dwinfo } // writepcranges generates the DW_AT_ranges table for compilation unit cu. @@ -1516,24 +1448,6 @@ func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol { return syms } -func writeranges(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol { - for _, s := range ctxt.Textp { - rangeSym := ctxt.Syms.ROLookup(dwarf.RangePrefix+s.Name, int(s.Version)) - if rangeSym == nil || rangeSym.Size == 0 { - continue - } - rangeSym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable - rangeSym.Type = sym.SDWARFRANGE - // LLVM doesn't support base address entries. Strip them out so LLDB and dsymutil don't get confused. - if ctxt.HeadType == objabi.Hdarwin { - fn := ctxt.Syms.ROLookup(dwarf.InfoPrefix+s.Name, int(s.Version)) - removeDwarfAddrListBaseAddress(ctxt, fn, rangeSym, false) - } - syms = append(syms, rangeSym) - } - return syms -} - /* * Walk DWarfDebugInfoEntries, and emit .debug_info */ @@ -1672,24 +1586,15 @@ func writegdbscript(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol { var prototypedies map[string]*dwarf.DWDie -/* - * This is the main entry point for generating dwarf. After emitting - * the mandatory debug_abbrev section, it calls writelines() to set up - * the per-compilation unit part of the DIE tree, while simultaneously - * emitting the debug_line section. When the final tree contains - * forward references, it will write the debug_info section in 2 - * passes. - * - */ -func dwarfgeneratedebugsyms(ctxt *Link) { +func dwarfEnabled(ctxt *Link) bool { if *FlagW { // disable dwarf - return + return false } if *FlagS && ctxt.HeadType != objabi.Hdarwin { - return + return false } if ctxt.HeadType == objabi.Hplan9 || ctxt.HeadType == objabi.Hjs { - return + return false } if ctxt.LinkMode == LinkExternal { @@ -1698,14 +1603,27 @@ func dwarfgeneratedebugsyms(ctxt *Link) { case ctxt.HeadType == objabi.Hdarwin: case ctxt.HeadType == objabi.Hwindows: default: - return + return false } } - if ctxt.Debugvlog != 0 { - ctxt.Logf("%5.2f dwarf\n", Cputime()) + return true +} + +// dwarfGenerateDebugInfo generated debug info entries for all types, +// variables and functions in the program. +// Along with dwarfGenerateDebugSyms they are the two main entry points into +// dwarf generation: dwarfGenerateDebugInfo does all the work that should be +// done before symbol names are mangled while dwarfgeneratedebugsyms does +// all the work that can only be done after addresses have been assigned to +// text symbols. +func dwarfGenerateDebugInfo(ctxt *Link) { + if !dwarfEnabled(ctxt) { + return } + ctxt.compUnitByPackage = make(map[*sym.Library]*compilationUnit) + // Forctxt.Diagnostic messages. newattr(&dwtypes, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len("dwtypes")), "dwtypes") @@ -1748,12 +1666,84 @@ func dwarfgeneratedebugsyms(ctxt *Link) { defgotype(ctxt, lookupOrDiag(ctxt, typ)) } + // Create DIEs for global variables and the types they use. genasmsym(ctxt, defdwsymb) + for _, lib := range ctxt.Library { + if len(lib.Textp) == 0 { + continue + } + unit := &compilationUnit{lib: lib} + if s := ctxt.Syms.ROLookup(dwarf.ConstInfoPrefix+lib.Pkg, 0); s != nil { + importInfoSymbol(ctxt, s) + unit.consts = s + } + ctxt.compUnits = append(ctxt.compUnits, unit) + ctxt.compUnitByPackage[lib] = unit + + // Scan all functions in this compilation unit, create DIEs for all + // referenced types, create the file table for debug_line, find all + // referenced abstract functions. + // Collect all debug_range symbols in unit.rangeSyms + for _, s := range lib.Textp { // textp has been dead-code-eliminated already. + dsym := ctxt.Syms.ROLookup(dwarf.InfoPrefix+s.Name, int(s.Version)) + dsym.Attr |= sym.AttrNotInSymbolTable | sym.AttrReachable + dsym.Type = sym.SDWARFINFO + unit.funcDIEs = append(unit.funcDIEs, dsym) + + rangeSym := ctxt.Syms.ROLookup(dwarf.RangePrefix+s.Name, int(s.Version)) + if rangeSym != nil && rangeSym.Size > 0 { + rangeSym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable + rangeSym.Type = sym.SDWARFRANGE + // LLVM doesn't support base address entries. Strip them out so LLDB and dsymutil don't get confused. + if ctxt.HeadType == objabi.Hdarwin { + removeDwarfAddrListBaseAddress(ctxt, dsym, rangeSym, false) + } + unit.rangeSyms = append(unit.rangeSyms, rangeSym) + } + + for ri := 0; ri < len(dsym.R); ri++ { + r := &dsym.R[ri] + if r.Type == objabi.R_DWARFSECREF { + rsym := r.Sym + if strings.HasPrefix(rsym.Name, dwarf.InfoPrefix) && strings.HasSuffix(rsym.Name, dwarf.AbstractFuncSuffix) && !rsym.Attr.OnList() { + // abstract function + rsym.Attr |= sym.AttrOnList + unit.absFnDIEs = append(unit.absFnDIEs, rsym) + importInfoSymbol(ctxt, rsym) + } else if rsym.Size == 0 { + // a type we do not have a DIE for + n := nameFromDIESym(rsym) + defgotype(ctxt, ctxt.Syms.Lookup("type."+n, 0)) + } + } + } + } + } + + synthesizestringtypes(ctxt, dwtypes.Child) + synthesizeslicetypes(ctxt, dwtypes.Child) + synthesizemaptypes(ctxt, dwtypes.Child) + synthesizechantypes(ctxt, dwtypes.Child) +} + +// dwarfGenerateDebugSyms constructs debug_line, debug_frame, debug_loc, +// debug_pubnames and debug_pubtypes. It also writes out the debug_info +// section using symbols generated in dwarfGenerateDebugInfo. +func dwarfGenerateDebugSyms(ctxt *Link) { + if !dwarfEnabled(ctxt) { + return + } + + if ctxt.Debugvlog != 0 { + ctxt.Logf("%5.2f dwarf\n", Cputime()) + } + abbrev := writeabbrev(ctxt) syms := []*sym.Symbol{abbrev} - units := getCompilationUnits(ctxt) + calcCompUnitRanges(ctxt) + sort.Sort(compilationUnitByStartPC(ctxt.compUnits)) // Write per-package line and range tables and start their CU DIEs. debugLine := ctxt.Syms.Lookup(".debug_line", 0) @@ -1762,16 +1752,11 @@ func dwarfgeneratedebugsyms(ctxt *Link) { debugRanges.Type = sym.SDWARFRANGE debugRanges.Attr |= sym.AttrReachable syms = append(syms, debugLine) - for _, u := range units { - u.dwinfo, u.funcDIEs, u.absFnDIEs = writelines(ctxt, u.lib, u.lib.Textp, debugLine) + for _, u := range ctxt.compUnits { + u.dwinfo = writelines(ctxt, u, debugLine) writepcranges(ctxt, u.dwinfo, u.lib.Textp[0], u.pcs, debugRanges) } - synthesizestringtypes(ctxt, dwtypes.Child) - synthesizeslicetypes(ctxt, dwtypes.Child) - synthesizemaptypes(ctxt, dwtypes.Child) - synthesizechantypes(ctxt, dwtypes.Child) - // newdie adds DIEs to the *beginning* of the parent's DIE list. // Now that we're done creating DIEs, reverse the trees so DIEs // appear in the order they were created. @@ -1784,7 +1769,7 @@ func dwarfgeneratedebugsyms(ctxt *Link) { // Need to reorder symbols so sym.SDWARFINFO is after all sym.SDWARFSECT // (but we need to generate dies before writepub) - infosyms := writeinfo(ctxt, nil, units, abbrev) + infosyms := writeinfo(ctxt, nil, ctxt.compUnits, abbrev) syms = writeframes(ctxt, syms) syms = writepub(ctxt, ".debug_pubnames", ispubname, syms) @@ -1793,9 +1778,11 @@ func dwarfgeneratedebugsyms(ctxt *Link) { // Now we're done writing SDWARFSECT symbols, so we can write // other SDWARF* symbols. syms = append(syms, infosyms...) - syms = collectlocs(ctxt, syms, units) + syms = collectlocs(ctxt, syms, ctxt.compUnits) syms = append(syms, debugRanges) - syms = writeranges(ctxt, syms) + for _, unit := range ctxt.compUnits { + syms = append(syms, unit.rangeSyms...) + } dwarfp = syms } @@ -2006,3 +1993,12 @@ func dwarfcompress(ctxt *Link) { } Segdwarf.Length = pos - Segdwarf.Vaddr } + +type compilationUnitByStartPC []*compilationUnit + +func (v compilationUnitByStartPC) Len() int { return len(v) } +func (v compilationUnitByStartPC) Swap(i, j int) { v[i], v[j] = v[j], v[i] } + +func (v compilationUnitByStartPC) Less(i, j int) bool { + return v[i].lib.Textp[0].Value < v[j].lib.Textp[0].Value +} diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 331b6ca6145edd..5e99149d2549cf 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -654,7 +654,6 @@ func (ctxt *Link) mangleTypeSym() { return } - *FlagW = true // disable DWARF generation for _, s := range ctxt.Syms.Allsym { newName := typeSymbolMangle(s.Name) if newName != s.Name { diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index bf5754435786fa..48b92724b6fe07 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -89,6 +89,9 @@ type Link struct { // Used to implement field tracking. Reachparent map[*sym.Symbol]*sym.Symbol + + compUnits []*compilationUnit // DWARF compilation units + compUnitByPackage map[*sym.Library]*compilationUnit } type unresolvedSymKey struct { diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 0c5ac470438adb..905380a1dbfda2 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -208,6 +208,7 @@ func Main(arch *sys.Arch, theArch Arch) { ctxt.dostrdata() deadcode(ctxt) + dwarfGenerateDebugInfo(ctxt) if objabi.Fieldtrack_enabled != 0 { fieldtrack(ctxt) } diff --git a/src/cmd/link/internal/objfile/objfile.go b/src/cmd/link/internal/objfile/objfile.go index 67868be2a19261..e3800de30413b3 100644 --- a/src/cmd/link/internal/objfile/objfile.go +++ b/src/cmd/link/internal/objfile/objfile.go @@ -318,6 +318,8 @@ overwrite: pc.InlTree[i].Func = r.readSymIndex() } + s.FuncInfo.IsStmtSym = r.syms.Lookup(dwarf.IsStmtPrefix+s.Name, int(s.Version)) + s.Lib = r.lib if !dupok { if s.Attr.OnList() { diff --git a/src/cmd/link/internal/sym/symbol.go b/src/cmd/link/internal/sym/symbol.go index 95ad8654b5cef1..a6c2aaea778f57 100644 --- a/src/cmd/link/internal/sym/symbol.go +++ b/src/cmd/link/internal/sym/symbol.go @@ -478,6 +478,7 @@ type FuncInfo struct { Pcline Pcdata Pcinline Pcdata Pcdata []Pcdata + IsStmtSym *Symbol Funcdata []*Symbol Funcdataoff []int64 File []*Symbol