From 78a37347143bd03026a6c6860a550b1638ce5314 Mon Sep 17 00:00:00 2001 From: Jeremy Faller Date: Fri, 9 Aug 2019 11:36:03 -0400 Subject: [PATCH] cmd/link: add notion of multiple compilation units per package As we move the debug_line generation into the compiler, we need to upgrade the notion of compilationUnit to not just be on a per package basis. That won't be the case as it will be impossible for all compilationUnits to have the same set of files names used to build the debug_lines table. (For example, assembled files in a package don't know about any files but themselves, so the debug_lines table could only reference themseves. As such, we need to break the 1:1 relationship between compUnit and package.) Change-Id: I2e517bb6c01de0115bbf777af828a2fe59c09ce8 Reviewed-on: https://go-review.googlesource.com/c/go/+/189618 Run-TryBot: Jeremy Faller TryBot-Result: Gobot Gobot Reviewed-by: Austin Clements Reviewed-by: Cherry Zhang --- src/cmd/link/internal/ld/data.go | 5 +- src/cmd/link/internal/ld/deadcode.go | 5 +- src/cmd/link/internal/ld/dwarf.go | 256 +++++++++--------- src/cmd/link/internal/ld/lib.go | 5 +- src/cmd/link/internal/ld/link.go | 4 +- src/cmd/link/internal/objfile/objfile.go | 8 +- src/cmd/link/internal/sym/compilation_unit.go | 22 ++ src/cmd/link/internal/sym/library.go | 1 + src/cmd/link/internal/sym/symbol.go | 2 +- 9 files changed, 168 insertions(+), 140 deletions(-) create mode 100644 src/cmd/link/internal/sym/compilation_unit.go diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 8e35f5c9dc..2266d301dd 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -402,7 +402,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) { case objabi.R_ADDRCUOFF: // debug_range and debug_loc elements use this relocation type to get an // offset from the start of the compile unit. - o = Symaddr(r.Sym) + r.Add - Symaddr(r.Sym.Lib.Textp[0]) + o = Symaddr(r.Sym) + r.Add - Symaddr(r.Sym.Unit.Lib.Textp[0]) // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call. case objabi.R_GOTPCREL: @@ -1782,7 +1782,8 @@ func (ctxt *Link) dodata() { case sym.SDWARFLOC: sect = addsection(ctxt.Arch, &Segdwarf, ".debug_loc", 04) default: - Errorf(dwarfp[i], "unknown DWARF section %v", curType) + // Error is unrecoverable, so panic. + panic(fmt.Sprintf("unknown DWARF section %v", curType)) } sect.Align = 1 diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go index f9a0ee0f96..418703cb2f 100644 --- a/src/cmd/link/internal/ld/deadcode.go +++ b/src/cmd/link/internal/ld/deadcode.go @@ -126,8 +126,9 @@ func deadcode(ctxt *Link) { textp := make([]*sym.Symbol, 0, len(ctxt.Textp)) for _, s := range ctxt.Textp { if s.Attr.Reachable() { - if s.Lib != nil { - s.Lib.Textp = append(s.Lib.Textp, s) + if s.Unit != nil { + s.Unit.Lib.Textp = append(s.Unit.Lib.Textp, s) + s.Unit.Textp = append(s.Unit.Textp, s) } textp = append(textp, s) } diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 7969abb990..e42e4f6656 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -176,7 +176,7 @@ func newdie(ctxt *Link, parent *dwarf.DWDie, abbrev int, name string, version in if abbrev != dwarf.DW_ABRV_VARIABLE || version == 0 { if abbrev == dwarf.DW_ABRV_COMPUNIT { // Avoid collisions with "real" symbol names. - name = ".pkg." + name + name = fmt.Sprintf(".pkg.%s.%d", name, len(ctxt.compUnits)) } s := ctxt.Syms.Lookup(dwarf.InfoPrefix+name, version) s.Attr |= sym.AttrNotInSymbolTable @@ -858,11 +858,17 @@ func synthesizechantypes(ctxt *Link, die *dwarf.DWDie) { } func dwarfDefineGlobal(ctxt *Link, s *sym.Symbol, str string, v int64, gotype *sym.Symbol) { - lib := s.Lib - if lib == nil { - lib = ctxt.LibraryByPkg["runtime"] + // Find a suitable CU DIE to include the global. + // One would think it's as simple as just looking at the unit, but that might + // not have any reachable code. So, we go to the runtime's CU if our unit + // isn't otherwise reachable. + var unit *sym.CompilationUnit + if s.Unit != nil { + unit = s.Unit + } else { + unit = ctxt.runtimeCU } - dv := newdie(ctxt, ctxt.compUnitByPackage[lib].dwinfo, dwarf.DW_ABRV_VARIABLE, str, int(s.Version)) + dv := newdie(ctxt, unit.DWInfo, dwarf.DW_ABRV_VARIABLE, str, int(s.Version)) newabslocexprattr(dv, v, s) if !s.IsFileLocal() { newattr(dv, dwarf.DW_AT_external, dwarf.DW_CLS_FLAG, 1, 0) @@ -930,27 +936,14 @@ func addDwarfAddrRef(ctxt *Link, s *sym.Symbol, t *sym.Symbol) { } } -// compilationUnit is per-compilation unit (equivalently, per-package) -// debug-related data. -type compilationUnit struct { - lib *sym.Library - consts *sym.Symbol // Package constants DIEs - pcs []dwarf.Range // PC ranges, relative to textp[0] - 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 -} - // calcCompUnitRanges calculates the PC ranges of the compilation units. func calcCompUnitRanges(ctxt *Link) { - var prevUnit *compilationUnit + var prevUnit *sym.CompilationUnit for _, s := range ctxt.Textp { if s.FuncInfo == nil { continue } - unit := ctxt.compUnitByPackage[s.Lib] - + unit := s.Unit // Update PC ranges. // // We don't simply compare the end of the previous @@ -959,18 +952,17 @@ func calcCompUnitRanges(ctxt *Link) { // only create boundaries between symbols from // different units. if prevUnit != unit { - unit.pcs = append(unit.pcs, dwarf.Range{Start: s.Value - unit.lib.Textp[0].Value}) + unit.PCs = append(unit.PCs, dwarf.Range{Start: s.Value - unit.Textp[0].Value}) prevUnit = unit } - unit.pcs[len(unit.pcs)-1].End = s.Value - unit.lib.Textp[0].Value + s.Size + unit.PCs[len(unit.PCs)-1].End = s.Value - unit.Textp[0].Value + s.Size } } func movetomodule(ctxt *Link, parent *dwarf.DWDie) { - runtimelib := ctxt.LibraryByPkg["runtime"] - die := ctxt.compUnitByPackage[runtimelib].dwinfo.Child + die := ctxt.runtimeCU.DWInfo.Child if die == nil { - ctxt.compUnitByPackage[runtimelib].dwinfo.Child = parent.Child + ctxt.runtimeCU.DWInfo.Child = parent.Child return } for die.Link != nil { @@ -1124,7 +1116,7 @@ func importInfoSymbol(ctxt *Link, dsym *sym.Symbol) { } } -func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { +func writelines(ctxt *Link, unit *sym.CompilationUnit, ls *sym.Symbol) { var dwarfctxt dwarf.Context = dwctxt{ctxt} is_stmt := uint8(1) // initially = recommended default_is_stmt = 1, tracks is_stmt toggles. @@ -1133,7 +1125,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { headerstart := int64(-1) headerend := int64(-1) - newattr(unit.dwinfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, ls.Size, ls) + newattr(unit.DWInfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, ls.Size, ls) // Write .debug_line Line Number Program Header (sec 6.2.4) // Fields marked with (*) must be changed for 64-bit dwarf @@ -1166,7 +1158,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { // 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 unit.lib.Textp { // textp has been dead-code-eliminated already. + for _, s := range unit.Textp { // textp has been dead-code-eliminated already. dsym := dwarfFuncSym(ctxt, s, dwarf.InfoPrefix, true) for _, f := range s.FuncInfo.File { if _, ok := fileNums[int(f.Value)]; ok { @@ -1206,7 +1198,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { dwarf.Uleb128put(dwarfctxt, ls, 1+int64(ctxt.Arch.PtrSize)) ls.AddUint8(dwarf.DW_LNE_set_address) - s := unit.lib.Textp[0] + s := unit.Textp[0] pc := s.Value line := 1 file := 1 @@ -1215,7 +1207,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { pcfile := obj.NewPCIter(uint32(ctxt.Arch.MinLC)) pcline := obj.NewPCIter(uint32(ctxt.Arch.MinLC)) pcstmt := obj.NewPCIter(uint32(ctxt.Arch.MinLC)) - for i, s := range unit.lib.Textp { + for i, s := range unit.Textp { finddebugruntimepath(s) pcfile.Init(s.FuncInfo.Pcfile.P) @@ -1239,7 +1231,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { ls.AddUint8(dwarf.DW_LNS_set_file) idx, ok := fileNums[int(pcfile.Value)] if !ok { - Exitf("pcln table file missing from DWARF line table") + Exitf("pcln table file missing from DWARF line table %q", s.Unit.Lib.Pkg) } dwarf.Uleb128put(dwarfctxt, ls, int64(idx)) file = int(pcfile.Value) @@ -1287,7 +1279,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { pcline.Next() } } - if is_stmt == 0 && i < len(unit.lib.Textp)-1 { + if is_stmt == 0 && i < len(unit.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)) @@ -1299,7 +1291,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { ls.AddUint8(dwarf.DW_LNE_end_sequence) if ctxt.HeadType == objabi.Haix { - saveDwsectCUSize(".debug_line", unit.lib.String(), uint64(ls.Size-unitLengthOffset)) + saveDwsectCUSize(".debug_line", unit.Lib.Pkg, uint64(ls.Size-unitLengthOffset)) } if isDwarf64(ctxt) { ls.SetUint(ctxt.Arch, unitLengthOffset+4, uint64(ls.Size-unitstart)) // +4 because of 0xFFFFFFFF @@ -1316,7 +1308,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { // DIE flavors (ex: variables) then those DIEs would need to // be included below. missing := make(map[int]interface{}) - for _, f := range unit.funcDIEs { + for _, f := range unit.FuncDIEs { for ri := range f.R { r := &f.R[ri] if r.Type != objabi.R_DWARFFILEREF { @@ -1351,18 +1343,18 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { } // writepcranges generates the DW_AT_ranges table for compilation unit cu. -func writepcranges(ctxt *Link, unit *compilationUnit, base *sym.Symbol, pcs []dwarf.Range, ranges *sym.Symbol) { +func writepcranges(ctxt *Link, unit *sym.CompilationUnit, base *sym.Symbol, pcs []dwarf.Range, ranges *sym.Symbol) { var dwarfctxt dwarf.Context = dwctxt{ctxt} unitLengthOffset := ranges.Size // Create PC ranges for this CU. - newattr(unit.dwinfo, dwarf.DW_AT_ranges, dwarf.DW_CLS_PTR, ranges.Size, ranges) - newattr(unit.dwinfo, dwarf.DW_AT_low_pc, dwarf.DW_CLS_ADDRESS, base.Value, base) + newattr(unit.DWInfo, dwarf.DW_AT_ranges, dwarf.DW_CLS_PTR, ranges.Size, ranges) + newattr(unit.DWInfo, dwarf.DW_AT_low_pc, dwarf.DW_CLS_ADDRESS, base.Value, base) dwarf.PutBasedRanges(dwarfctxt, ranges, pcs) if ctxt.HeadType == objabi.Haix { - addDwsectCUSize(".debug_ranges", unit.lib.String(), uint64(ranges.Size-unitLengthOffset)) + addDwsectCUSize(".debug_ranges", unit.Lib.Pkg, uint64(ranges.Size-unitLengthOffset)) } } @@ -1543,7 +1535,7 @@ const ( COMPUNITHEADERSIZE = 4 + 2 + 4 + 1 ) -func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevsym *sym.Symbol, pubNames, pubTypes *pubWriter) []*sym.Symbol { +func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*sym.CompilationUnit, abbrevsym *sym.Symbol, pubNames, pubTypes *pubWriter) []*sym.Symbol { infosec := ctxt.Syms.Lookup(".debug_info", 0) infosec.Type = sym.SDWARFINFO infosec.Attr |= sym.AttrReachable @@ -1552,10 +1544,10 @@ func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevs var dwarfctxt dwarf.Context = dwctxt{ctxt} for _, u := range units { - compunit := u.dwinfo + compunit := u.DWInfo s := dtolsym(compunit.Sym) - if len(u.lib.Textp) == 0 && u.dwinfo.Child == nil { + if len(u.Textp) == 0 && u.DWInfo.Child == nil { continue } @@ -1577,10 +1569,10 @@ func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevs dwarf.PutAttrs(dwarfctxt, s, compunit.Abbrev, compunit.Attr) cu := []*sym.Symbol{s} - cu = append(cu, u.absFnDIEs...) - cu = append(cu, u.funcDIEs...) - if u.consts != nil { - cu = append(cu, u.consts) + cu = append(cu, u.AbsFnDIEs...) + cu = append(cu, u.FuncDIEs...) + if u.Consts != nil { + cu = append(cu, u.Consts) } var cusize int64 for _, child := range cu { @@ -1772,8 +1764,6 @@ func dwarfGenerateDebugInfo(ctxt *Link) { dwsectCUSize = make(map[string]uint64) } - ctxt.compUnitByPackage = make(map[*sym.Library]*compilationUnit) - // Forctxt.Diagnostic messages. newattr(&dwtypes, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len("dwtypes")), "dwtypes") @@ -1821,83 +1811,91 @@ func dwarfGenerateDebugInfo(ctxt *Link) { flagVariants := make(map[string]bool) for _, lib := range ctxt.Library { - 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 - - unit.dwinfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, unit.lib.Pkg, 0) - newattr(unit.dwinfo, dwarf.DW_AT_language, dwarf.DW_CLS_CONSTANT, int64(dwarf.DW_LANG_Go), 0) - // OS X linker requires compilation dir or absolute path in comp unit name to output debug info. - compDir := getCompilationDir() - // TODO: Make this be the actual compilation directory, not - // the linker directory. If we move CU construction into the - // compiler, this should happen naturally. - newattr(unit.dwinfo, dwarf.DW_AT_comp_dir, dwarf.DW_CLS_STRING, int64(len(compDir)), compDir) - 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 - // separate them from the version, which can be long - // and have lots of weird things in it in development - // versions. We promise not to put a semicolon in the - // version, so it should be safe for readers to scan - // forward to the semicolon. - producer += "; " + string(producerExtra.P) - flagVariants[string(producerExtra.P)] = true - } else { - flagVariants[""] = true - } + consts := ctxt.Syms.ROLookup(dwarf.ConstInfoPrefix+lib.Pkg, 0) + for _, unit := range lib.Units { + // We drop the constants into the first CU. + if consts != nil { + importInfoSymbol(ctxt, consts) + unit.Consts = consts + consts = nil + } - newattr(unit.dwinfo, dwarf.DW_AT_producer, dwarf.DW_CLS_STRING, int64(len(producer)), producer) + ctxt.compUnits = append(ctxt.compUnits, unit) - var pkgname string - if s := ctxt.Syms.ROLookup(dwarf.CUInfoPrefix+"packagename."+unit.lib.Pkg, 0); s != nil { - pkgname = string(s.P) - } - newattr(unit.dwinfo, dwarf.DW_AT_go_package_name, dwarf.DW_CLS_STRING, int64(len(pkgname)), pkgname) + // We need at least one runtime unit. + if unit.Lib.Pkg == "runtime" { + ctxt.runtimeCU = unit + } - if len(lib.Textp) == 0 { - unit.dwinfo.Abbrev = dwarf.DW_ABRV_COMPUNIT_TEXTLESS - } + unit.DWInfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, unit.Lib.Pkg, 0) + newattr(unit.DWInfo, dwarf.DW_AT_language, dwarf.DW_CLS_CONSTANT, int64(dwarf.DW_LANG_Go), 0) + // OS X linker requires compilation dir or absolute path in comp unit name to output debug info. + compDir := getCompilationDir() + // TODO: Make this be the actual compilation directory, not + // the linker directory. If we move CU construction into the + // compiler, this should happen naturally. + newattr(unit.DWInfo, dwarf.DW_AT_comp_dir, dwarf.DW_CLS_STRING, int64(len(compDir)), compDir) + 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 + // separate them from the version, which can be long + // and have lots of weird things in it in development + // versions. We promise not to put a semicolon in the + // version, so it should be safe for readers to scan + // forward to the semicolon. + producer += "; " + string(producerExtra.P) + flagVariants[string(producerExtra.P)] = true + } else { + flagVariants[""] = true + } - // 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 := dwarfFuncSym(ctxt, s, dwarf.InfoPrefix, false) - dsym.Attr |= sym.AttrNotInSymbolTable | sym.AttrReachable - dsym.Type = sym.SDWARFINFO - unit.funcDIEs = append(unit.funcDIEs, dsym) - - rangeSym := dwarfFuncSym(ctxt, s, dwarf.RangePrefix, false) - if rangeSym != nil && rangeSym.Size > 0 { - rangeSym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable - rangeSym.Type = sym.SDWARFRANGE - if ctxt.HeadType == objabi.Haix { - addDwsectCUSize(".debug_ranges", unit.lib.String(), uint64(rangeSym.Size)) + newattr(unit.DWInfo, dwarf.DW_AT_producer, dwarf.DW_CLS_STRING, int64(len(producer)), producer) - } - unit.rangeSyms = append(unit.rangeSyms, rangeSym) + var pkgname string + if s := ctxt.Syms.ROLookup(dwarf.CUInfoPrefix+"packagename."+unit.Lib.Pkg, 0); s != nil { + pkgname = string(s.P) } + newattr(unit.DWInfo, dwarf.DW_AT_go_package_name, dwarf.DW_CLS_STRING, int64(len(pkgname)), pkgname) + + if len(unit.Textp) == 0 { + unit.DWInfo.Abbrev = dwarf.DW_ABRV_COMPUNIT_TEXTLESS + } + + // 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 unit.Textp { // textp has been dead-code-eliminated already. + dsym := dwarfFuncSym(ctxt, s, dwarf.InfoPrefix, false) + dsym.Attr |= sym.AttrNotInSymbolTable | sym.AttrReachable + dsym.Type = sym.SDWARFINFO + unit.FuncDIEs = append(unit.FuncDIEs, dsym) + + rangeSym := dwarfFuncSym(ctxt, s, dwarf.RangePrefix, false) + if rangeSym != nil && rangeSym.Size > 0 { + rangeSym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable + rangeSym.Type = sym.SDWARFRANGE + if ctxt.HeadType == objabi.Haix { + addDwsectCUSize(".debug_ranges", unit.Lib.Pkg, uint64(rangeSym.Size)) + } + 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)) + 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)) + } } } } @@ -1946,12 +1944,12 @@ func dwarfGenerateDebugSyms(ctxt *Link) { debugRanges.Attr |= sym.AttrReachable syms = append(syms, debugLine) for _, u := range ctxt.compUnits { - reversetree(&u.dwinfo.Child) - if u.dwinfo.Abbrev == dwarf.DW_ABRV_COMPUNIT_TEXTLESS { + reversetree(&u.DWInfo.Child) + if u.DWInfo.Abbrev == dwarf.DW_ABRV_COMPUNIT_TEXTLESS { continue } writelines(ctxt, u, debugLine) - writepcranges(ctxt, u, u.lib.Textp[0], u.pcs, debugRanges) + writepcranges(ctxt, u, u.Textp[0], u.PCs, debugRanges) } // newdie adds DIEs to the *beginning* of the parent's DIE list. @@ -1975,15 +1973,15 @@ func dwarfGenerateDebugSyms(ctxt *Link) { syms = collectlocs(ctxt, syms, ctxt.compUnits) syms = append(syms, debugRanges) for _, unit := range ctxt.compUnits { - syms = append(syms, unit.rangeSyms...) + syms = append(syms, unit.RangeSyms...) } dwarfp = syms } -func collectlocs(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit) []*sym.Symbol { +func collectlocs(ctxt *Link, syms []*sym.Symbol, units []*sym.CompilationUnit) []*sym.Symbol { empty := true for _, u := range units { - for _, fn := range u.funcDIEs { + for _, fn := range u.FuncDIEs { for i := range fn.R { reloc := &fn.R[i] // Copying sym.Reloc has measurable impact on performance if reloc.Type == objabi.R_DWARFSECREF && strings.HasPrefix(reloc.Sym.Name, dwarf.LocPrefix) { @@ -2126,21 +2124,21 @@ func dwarfcompress(ctxt *Link) { Segdwarf.Length = pos - Segdwarf.Vaddr } -type compilationUnitByStartPC []*compilationUnit +type compilationUnitByStartPC []*sym.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 { switch { - case len(v[i].lib.Textp) == 0 && len(v[j].lib.Textp) == 0: - return v[i].lib.Pkg < v[j].lib.Pkg - case len(v[i].lib.Textp) != 0 && len(v[j].lib.Textp) == 0: + case len(v[i].Textp) == 0 && len(v[j].Textp) == 0: + return v[i].Lib.Pkg < v[j].Lib.Pkg + case len(v[i].Textp) != 0 && len(v[j].Textp) == 0: return true - case len(v[i].lib.Textp) == 0 && len(v[j].lib.Textp) != 0: + case len(v[i].Textp) == 0 && len(v[j].Textp) != 0: return false default: - return v[i].lib.Textp[0].Value < v[j].lib.Textp[0].Value + return v[i].Textp[0].Value < v[j].Textp[0].Value } } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index c2de8cbef9..3739838bce 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1624,6 +1624,9 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, c4 := bgetc(f) f.MustSeek(start, 0) + unit := &sym.CompilationUnit{Lib: lib} + lib.Units = append(lib.Units, unit) + magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4) if magic == 0x7f454c46 { // \x7F E L F ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) { @@ -1770,7 +1773,7 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, default: log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups) } - c := objfile.Load(ctxt.Arch, ctxt.Syms, f, lib, eof-f.Offset(), pn, flags) + c := objfile.Load(ctxt.Arch, ctxt.Syms, f, lib, unit, eof-f.Offset(), pn, flags) strictDupMsgCount += c addImports(ctxt, lib, pn) return nil diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index dc39f084bf..53092d2e8f 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -92,8 +92,8 @@ type Link struct { // Used to implement field tracking. Reachparent map[*sym.Symbol]*sym.Symbol - compUnits []*compilationUnit // DWARF compilation units - compUnitByPackage map[*sym.Library]*compilationUnit + compUnits []*sym.CompilationUnit // DWARF compilation units + runtimeCU *sym.CompilationUnit // One of the runtime CUs, the last one seen. relocbuf []byte // temporary buffer for applying relocations } diff --git a/src/cmd/link/internal/objfile/objfile.go b/src/cmd/link/internal/objfile/objfile.go index 107409b00d..b6bb8640eb 100644 --- a/src/cmd/link/internal/objfile/objfile.go +++ b/src/cmd/link/internal/objfile/objfile.go @@ -39,6 +39,7 @@ type objReader struct { arch *sys.Arch syms *sym.Symbols lib *sym.Library + unit *sym.CompilationUnit pn string dupSym *sym.Symbol localSymVersion int @@ -81,7 +82,7 @@ const ( // Load loads an object file f into library lib. // The symbols loaded are added to syms. -func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, length int64, pn string, flags int) int { +func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64, pn string, flags int) int { start := f.Offset() roObject := f.SliceRO(uint64(length)) if roObject != nil { @@ -90,6 +91,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, le r := &objReader{ rd: f, lib: lib, + unit: unit, arch: arch, syms: syms, pn: pn, @@ -254,7 +256,7 @@ func (r *objReader) readSym() { overwrite: s.File = r.pkgpref[:len(r.pkgpref)-1] - s.Lib = r.lib + s.Unit = r.unit if dupok { s.Attr |= sym.AttrDuplicateOK } @@ -405,7 +407,7 @@ overwrite: reason = fmt.Sprintf("new length %d != old length %d", len(data), len(dup.P)) } - fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.lib, dup, dup.Lib, reason) + fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.lib, dup, dup.Unit.Lib, reason) // For the moment, whitelist DWARF subprogram DIEs for // auto-generated wrapper functions. What seems to happen diff --git a/src/cmd/link/internal/sym/compilation_unit.go b/src/cmd/link/internal/sym/compilation_unit.go new file mode 100644 index 0000000000..f9684b0ea0 --- /dev/null +++ b/src/cmd/link/internal/sym/compilation_unit.go @@ -0,0 +1,22 @@ +// Copyright 2019 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. + +package sym + +import "cmd/internal/dwarf" + +// CompilationUnit is an abstraction used by DWARF to represent a chunk of +// debug-related data. We create a CompilationUnit per Object file in a +// library (so, one for all the Go code, one for each assembly file, etc.). +type CompilationUnit struct { + Pkg string // The package name, eg ("fmt", or "runtime") + Lib *Library // Our library + Consts *Symbol // Package constants DIEs + PCs []dwarf.Range // PC ranges, relative to Textp[0] + DWInfo *dwarf.DWDie // CU root DIE + FuncDIEs []*Symbol // Function DIE subtrees + AbsFnDIEs []*Symbol // Abstract function DIE subtrees + RangeSyms []*Symbol // Symbols for debug_range + Textp []*Symbol // Text symbols in this CU +} diff --git a/src/cmd/link/internal/sym/library.go b/src/cmd/link/internal/sym/library.go index 54b9dfe7a2..4f2023b8f7 100644 --- a/src/cmd/link/internal/sym/library.go +++ b/src/cmd/link/internal/sym/library.go @@ -17,6 +17,7 @@ type Library struct { DupTextSyms []*Symbol // dupok text symbols defined in this library Main bool Safe bool + Units []*CompilationUnit } func (l Library) String() string { diff --git a/src/cmd/link/internal/sym/symbol.go b/src/cmd/link/internal/sym/symbol.go index d115a3326f..da06b08ebd 100644 --- a/src/cmd/link/internal/sym/symbol.go +++ b/src/cmd/link/internal/sym/symbol.go @@ -32,7 +32,7 @@ type Symbol struct { auxinfo *AuxSymbol Sect *Section FuncInfo *FuncInfo - Lib *Library // Package defining this symbol + Unit *CompilationUnit // P contains the raw symbol data. P []byte R []Reloc -- 2.48.1