Commit 78a37347 authored by Jeremy Faller's avatar Jeremy Faller

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 <jeremy@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarAustin Clements <austin@google.com>
Reviewed-by: default avatarCherry Zhang <cherryyz@google.com>
parent d979ac33
...@@ -402,7 +402,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) { ...@@ -402,7 +402,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
case objabi.R_ADDRCUOFF: case objabi.R_ADDRCUOFF:
// debug_range and debug_loc elements use this relocation type to get an // debug_range and debug_loc elements use this relocation type to get an
// offset from the start of the compile unit. // 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. // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
case objabi.R_GOTPCREL: case objabi.R_GOTPCREL:
...@@ -1782,7 +1782,8 @@ func (ctxt *Link) dodata() { ...@@ -1782,7 +1782,8 @@ func (ctxt *Link) dodata() {
case sym.SDWARFLOC: case sym.SDWARFLOC:
sect = addsection(ctxt.Arch, &Segdwarf, ".debug_loc", 04) sect = addsection(ctxt.Arch, &Segdwarf, ".debug_loc", 04)
default: 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 sect.Align = 1
......
...@@ -126,8 +126,9 @@ func deadcode(ctxt *Link) { ...@@ -126,8 +126,9 @@ func deadcode(ctxt *Link) {
textp := make([]*sym.Symbol, 0, len(ctxt.Textp)) textp := make([]*sym.Symbol, 0, len(ctxt.Textp))
for _, s := range ctxt.Textp { for _, s := range ctxt.Textp {
if s.Attr.Reachable() { if s.Attr.Reachable() {
if s.Lib != nil { if s.Unit != nil {
s.Lib.Textp = append(s.Lib.Textp, s) s.Unit.Lib.Textp = append(s.Unit.Lib.Textp, s)
s.Unit.Textp = append(s.Unit.Textp, s)
} }
textp = append(textp, s) textp = append(textp, s)
} }
......
...@@ -176,7 +176,7 @@ func newdie(ctxt *Link, parent *dwarf.DWDie, abbrev int, name string, version in ...@@ -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_VARIABLE || version == 0 {
if abbrev == dwarf.DW_ABRV_COMPUNIT { if abbrev == dwarf.DW_ABRV_COMPUNIT {
// Avoid collisions with "real" symbol names. // 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 := ctxt.Syms.Lookup(dwarf.InfoPrefix+name, version)
s.Attr |= sym.AttrNotInSymbolTable s.Attr |= sym.AttrNotInSymbolTable
...@@ -858,11 +858,17 @@ func synthesizechantypes(ctxt *Link, die *dwarf.DWDie) { ...@@ -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) { func dwarfDefineGlobal(ctxt *Link, s *sym.Symbol, str string, v int64, gotype *sym.Symbol) {
lib := s.Lib // Find a suitable CU DIE to include the global.
if lib == nil { // One would think it's as simple as just looking at the unit, but that might
lib = ctxt.LibraryByPkg["runtime"] // 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) newabslocexprattr(dv, v, s)
if !s.IsFileLocal() { if !s.IsFileLocal() {
newattr(dv, dwarf.DW_AT_external, dwarf.DW_CLS_FLAG, 1, 0) 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) { ...@@ -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. // calcCompUnitRanges calculates the PC ranges of the compilation units.
func calcCompUnitRanges(ctxt *Link) { func calcCompUnitRanges(ctxt *Link) {
var prevUnit *compilationUnit var prevUnit *sym.CompilationUnit
for _, s := range ctxt.Textp { for _, s := range ctxt.Textp {
if s.FuncInfo == nil { if s.FuncInfo == nil {
continue continue
} }
unit := ctxt.compUnitByPackage[s.Lib] unit := s.Unit
// Update PC ranges. // Update PC ranges.
// //
// We don't simply compare the end of the previous // We don't simply compare the end of the previous
...@@ -959,18 +952,17 @@ func calcCompUnitRanges(ctxt *Link) { ...@@ -959,18 +952,17 @@ func calcCompUnitRanges(ctxt *Link) {
// only create boundaries between symbols from // only create boundaries between symbols from
// different units. // different units.
if prevUnit != unit { 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 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) { func movetomodule(ctxt *Link, parent *dwarf.DWDie) {
runtimelib := ctxt.LibraryByPkg["runtime"] die := ctxt.runtimeCU.DWInfo.Child
die := ctxt.compUnitByPackage[runtimelib].dwinfo.Child
if die == nil { if die == nil {
ctxt.compUnitByPackage[runtimelib].dwinfo.Child = parent.Child ctxt.runtimeCU.DWInfo.Child = parent.Child
return return
} }
for die.Link != nil { for die.Link != nil {
...@@ -1124,7 +1116,7 @@ func importInfoSymbol(ctxt *Link, dsym *sym.Symbol) { ...@@ -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} var dwarfctxt dwarf.Context = dwctxt{ctxt}
is_stmt := uint8(1) // initially = recommended default_is_stmt = 1, tracks is_stmt toggles. 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) { ...@@ -1133,7 +1125,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) {
headerstart := int64(-1) headerstart := int64(-1)
headerend := 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) // Write .debug_line Line Number Program Header (sec 6.2.4)
// Fields marked with (*) must be changed for 64-bit dwarf // Fields marked with (*) must be changed for 64-bit dwarf
...@@ -1166,7 +1158,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { ...@@ -1166,7 +1158,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) {
// Create the file table. fileNums maps from global file // Create the file table. fileNums maps from global file
// indexes (created by numberfile) to CU-local indexes. // indexes (created by numberfile) to CU-local indexes.
fileNums := make(map[int]int) 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) dsym := dwarfFuncSym(ctxt, s, dwarf.InfoPrefix, true)
for _, f := range s.FuncInfo.File { for _, f := range s.FuncInfo.File {
if _, ok := fileNums[int(f.Value)]; ok { if _, ok := fileNums[int(f.Value)]; ok {
...@@ -1206,7 +1198,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { ...@@ -1206,7 +1198,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) {
dwarf.Uleb128put(dwarfctxt, ls, 1+int64(ctxt.Arch.PtrSize)) dwarf.Uleb128put(dwarfctxt, ls, 1+int64(ctxt.Arch.PtrSize))
ls.AddUint8(dwarf.DW_LNE_set_address) ls.AddUint8(dwarf.DW_LNE_set_address)
s := unit.lib.Textp[0] s := unit.Textp[0]
pc := s.Value pc := s.Value
line := 1 line := 1
file := 1 file := 1
...@@ -1215,7 +1207,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { ...@@ -1215,7 +1207,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) {
pcfile := obj.NewPCIter(uint32(ctxt.Arch.MinLC)) pcfile := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
pcline := obj.NewPCIter(uint32(ctxt.Arch.MinLC)) pcline := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
pcstmt := 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) finddebugruntimepath(s)
pcfile.Init(s.FuncInfo.Pcfile.P) pcfile.Init(s.FuncInfo.Pcfile.P)
...@@ -1239,7 +1231,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { ...@@ -1239,7 +1231,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) {
ls.AddUint8(dwarf.DW_LNS_set_file) ls.AddUint8(dwarf.DW_LNS_set_file)
idx, ok := fileNums[int(pcfile.Value)] idx, ok := fileNums[int(pcfile.Value)]
if !ok { 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)) dwarf.Uleb128put(dwarfctxt, ls, int64(idx))
file = int(pcfile.Value) file = int(pcfile.Value)
...@@ -1287,7 +1279,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { ...@@ -1287,7 +1279,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) {
pcline.Next() 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. // If there is more than one function, ensure default value is established.
is_stmt = 1 is_stmt = 1
ls.AddUint8(uint8(dwarf.DW_LNS_negate_stmt)) ls.AddUint8(uint8(dwarf.DW_LNS_negate_stmt))
...@@ -1299,7 +1291,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { ...@@ -1299,7 +1291,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) {
ls.AddUint8(dwarf.DW_LNE_end_sequence) ls.AddUint8(dwarf.DW_LNE_end_sequence)
if ctxt.HeadType == objabi.Haix { 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) { if isDwarf64(ctxt) {
ls.SetUint(ctxt.Arch, unitLengthOffset+4, uint64(ls.Size-unitstart)) // +4 because of 0xFFFFFFFF 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) { ...@@ -1316,7 +1308,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) {
// DIE flavors (ex: variables) then those DIEs would need to // DIE flavors (ex: variables) then those DIEs would need to
// be included below. // be included below.
missing := make(map[int]interface{}) missing := make(map[int]interface{})
for _, f := range unit.funcDIEs { for _, f := range unit.FuncDIEs {
for ri := range f.R { for ri := range f.R {
r := &f.R[ri] r := &f.R[ri]
if r.Type != objabi.R_DWARFFILEREF { if r.Type != objabi.R_DWARFFILEREF {
...@@ -1351,18 +1343,18 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { ...@@ -1351,18 +1343,18 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) {
} }
// writepcranges generates the DW_AT_ranges table for compilation unit cu. // 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} var dwarfctxt dwarf.Context = dwctxt{ctxt}
unitLengthOffset := ranges.Size unitLengthOffset := ranges.Size
// Create PC ranges for this CU. // 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_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_low_pc, dwarf.DW_CLS_ADDRESS, base.Value, base)
dwarf.PutBasedRanges(dwarfctxt, ranges, pcs) dwarf.PutBasedRanges(dwarfctxt, ranges, pcs)
if ctxt.HeadType == objabi.Haix { 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 ( ...@@ -1543,7 +1535,7 @@ const (
COMPUNITHEADERSIZE = 4 + 2 + 4 + 1 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 := ctxt.Syms.Lookup(".debug_info", 0)
infosec.Type = sym.SDWARFINFO infosec.Type = sym.SDWARFINFO
infosec.Attr |= sym.AttrReachable infosec.Attr |= sym.AttrReachable
...@@ -1552,10 +1544,10 @@ func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevs ...@@ -1552,10 +1544,10 @@ func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevs
var dwarfctxt dwarf.Context = dwctxt{ctxt} var dwarfctxt dwarf.Context = dwctxt{ctxt}
for _, u := range units { for _, u := range units {
compunit := u.dwinfo compunit := u.DWInfo
s := dtolsym(compunit.Sym) s := dtolsym(compunit.Sym)
if len(u.lib.Textp) == 0 && u.dwinfo.Child == nil { if len(u.Textp) == 0 && u.DWInfo.Child == nil {
continue continue
} }
...@@ -1577,10 +1569,10 @@ func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevs ...@@ -1577,10 +1569,10 @@ func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevs
dwarf.PutAttrs(dwarfctxt, s, compunit.Abbrev, compunit.Attr) dwarf.PutAttrs(dwarfctxt, s, compunit.Abbrev, compunit.Attr)
cu := []*sym.Symbol{s} cu := []*sym.Symbol{s}
cu = append(cu, u.absFnDIEs...) cu = append(cu, u.AbsFnDIEs...)
cu = append(cu, u.funcDIEs...) cu = append(cu, u.FuncDIEs...)
if u.consts != nil { if u.Consts != nil {
cu = append(cu, u.consts) cu = append(cu, u.Consts)
} }
var cusize int64 var cusize int64
for _, child := range cu { for _, child := range cu {
...@@ -1772,8 +1764,6 @@ func dwarfGenerateDebugInfo(ctxt *Link) { ...@@ -1772,8 +1764,6 @@ func dwarfGenerateDebugInfo(ctxt *Link) {
dwsectCUSize = make(map[string]uint64) dwsectCUSize = make(map[string]uint64)
} }
ctxt.compUnitByPackage = make(map[*sym.Library]*compilationUnit)
// Forctxt.Diagnostic messages. // Forctxt.Diagnostic messages.
newattr(&dwtypes, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len("dwtypes")), "dwtypes") newattr(&dwtypes, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len("dwtypes")), "dwtypes")
...@@ -1821,23 +1811,31 @@ func dwarfGenerateDebugInfo(ctxt *Link) { ...@@ -1821,23 +1811,31 @@ func dwarfGenerateDebugInfo(ctxt *Link) {
flagVariants := make(map[string]bool) flagVariants := make(map[string]bool)
for _, lib := range ctxt.Library { for _, lib := range ctxt.Library {
unit := &compilationUnit{lib: lib} consts := ctxt.Syms.ROLookup(dwarf.ConstInfoPrefix+lib.Pkg, 0)
if s := ctxt.Syms.ROLookup(dwarf.ConstInfoPrefix+lib.Pkg, 0); s != nil { for _, unit := range lib.Units {
importInfoSymbol(ctxt, s) // We drop the constants into the first CU.
unit.consts = s if consts != nil {
importInfoSymbol(ctxt, consts)
unit.Consts = consts
consts = nil
} }
ctxt.compUnits = append(ctxt.compUnits, unit) ctxt.compUnits = append(ctxt.compUnits, unit)
ctxt.compUnitByPackage[lib] = unit
unit.dwinfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, unit.lib.Pkg, 0) // We need at least one runtime unit.
newattr(unit.dwinfo, dwarf.DW_AT_language, dwarf.DW_CLS_CONSTANT, int64(dwarf.DW_LANG_Go), 0) if unit.Lib.Pkg == "runtime" {
ctxt.runtimeCU = 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. // OS X linker requires compilation dir or absolute path in comp unit name to output debug info.
compDir := getCompilationDir() compDir := getCompilationDir()
// TODO: Make this be the actual compilation directory, not // TODO: Make this be the actual compilation directory, not
// the linker directory. If we move CU construction into the // the linker directory. If we move CU construction into the
// compiler, this should happen naturally. // compiler, this should happen naturally.
newattr(unit.dwinfo, dwarf.DW_AT_comp_dir, dwarf.DW_CLS_STRING, int64(len(compDir)), compDir) 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) producerExtra := ctxt.Syms.Lookup(dwarf.CUInfoPrefix+"producer."+unit.Lib.Pkg, 0)
producer := "Go cmd/compile " + objabi.Version producer := "Go cmd/compile " + objabi.Version
if len(producerExtra.P) > 0 { if len(producerExtra.P) > 0 {
// We put a semicolon before the flags to clearly // We put a semicolon before the flags to clearly
...@@ -1852,37 +1850,36 @@ func dwarfGenerateDebugInfo(ctxt *Link) { ...@@ -1852,37 +1850,36 @@ func dwarfGenerateDebugInfo(ctxt *Link) {
flagVariants[""] = true flagVariants[""] = true
} }
newattr(unit.dwinfo, dwarf.DW_AT_producer, dwarf.DW_CLS_STRING, int64(len(producer)), producer) newattr(unit.DWInfo, dwarf.DW_AT_producer, dwarf.DW_CLS_STRING, int64(len(producer)), producer)
var pkgname string var pkgname string
if s := ctxt.Syms.ROLookup(dwarf.CUInfoPrefix+"packagename."+unit.lib.Pkg, 0); s != nil { if s := ctxt.Syms.ROLookup(dwarf.CUInfoPrefix+"packagename."+unit.Lib.Pkg, 0); s != nil {
pkgname = string(s.P) pkgname = string(s.P)
} }
newattr(unit.dwinfo, dwarf.DW_AT_go_package_name, dwarf.DW_CLS_STRING, int64(len(pkgname)), pkgname) newattr(unit.DWInfo, dwarf.DW_AT_go_package_name, dwarf.DW_CLS_STRING, int64(len(pkgname)), pkgname)
if len(lib.Textp) == 0 { if len(unit.Textp) == 0 {
unit.dwinfo.Abbrev = dwarf.DW_ABRV_COMPUNIT_TEXTLESS unit.DWInfo.Abbrev = dwarf.DW_ABRV_COMPUNIT_TEXTLESS
} }
// Scan all functions in this compilation unit, create DIEs for all // Scan all functions in this compilation unit, create DIEs for all
// referenced types, create the file table for debug_line, find all // referenced types, create the file table for debug_line, find all
// referenced abstract functions. // referenced abstract functions.
// Collect all debug_range symbols in unit.rangeSyms // Collect all debug_range symbols in unit.rangeSyms
for _, s := range 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, false) dsym := dwarfFuncSym(ctxt, s, dwarf.InfoPrefix, false)
dsym.Attr |= sym.AttrNotInSymbolTable | sym.AttrReachable dsym.Attr |= sym.AttrNotInSymbolTable | sym.AttrReachable
dsym.Type = sym.SDWARFINFO dsym.Type = sym.SDWARFINFO
unit.funcDIEs = append(unit.funcDIEs, dsym) unit.FuncDIEs = append(unit.FuncDIEs, dsym)
rangeSym := dwarfFuncSym(ctxt, s, dwarf.RangePrefix, false) rangeSym := dwarfFuncSym(ctxt, s, dwarf.RangePrefix, false)
if rangeSym != nil && rangeSym.Size > 0 { if rangeSym != nil && rangeSym.Size > 0 {
rangeSym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable rangeSym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable
rangeSym.Type = sym.SDWARFRANGE rangeSym.Type = sym.SDWARFRANGE
if ctxt.HeadType == objabi.Haix { if ctxt.HeadType == objabi.Haix {
addDwsectCUSize(".debug_ranges", unit.lib.String(), uint64(rangeSym.Size)) addDwsectCUSize(".debug_ranges", unit.Lib.Pkg, uint64(rangeSym.Size))
} }
unit.rangeSyms = append(unit.rangeSyms, rangeSym) unit.RangeSyms = append(unit.RangeSyms, rangeSym)
} }
for ri := 0; ri < len(dsym.R); ri++ { for ri := 0; ri < len(dsym.R); ri++ {
...@@ -1892,7 +1889,7 @@ func dwarfGenerateDebugInfo(ctxt *Link) { ...@@ -1892,7 +1889,7 @@ func dwarfGenerateDebugInfo(ctxt *Link) {
if strings.HasPrefix(rsym.Name, dwarf.InfoPrefix) && strings.HasSuffix(rsym.Name, dwarf.AbstractFuncSuffix) && !rsym.Attr.OnList() { if strings.HasPrefix(rsym.Name, dwarf.InfoPrefix) && strings.HasSuffix(rsym.Name, dwarf.AbstractFuncSuffix) && !rsym.Attr.OnList() {
// abstract function // abstract function
rsym.Attr |= sym.AttrOnList rsym.Attr |= sym.AttrOnList
unit.absFnDIEs = append(unit.absFnDIEs, rsym) unit.AbsFnDIEs = append(unit.AbsFnDIEs, rsym)
importInfoSymbol(ctxt, rsym) importInfoSymbol(ctxt, rsym)
} else if rsym.Size == 0 { } else if rsym.Size == 0 {
// a type we do not have a DIE for // a type we do not have a DIE for
...@@ -1903,6 +1900,7 @@ func dwarfGenerateDebugInfo(ctxt *Link) { ...@@ -1903,6 +1900,7 @@ func dwarfGenerateDebugInfo(ctxt *Link) {
} }
} }
} }
}
// Fix for 31034: if the objects feeding into this link were compiled // Fix for 31034: if the objects feeding into this link were compiled
// with different sets of flags, then don't issue an error if // with different sets of flags, then don't issue an error if
...@@ -1946,12 +1944,12 @@ func dwarfGenerateDebugSyms(ctxt *Link) { ...@@ -1946,12 +1944,12 @@ func dwarfGenerateDebugSyms(ctxt *Link) {
debugRanges.Attr |= sym.AttrReachable debugRanges.Attr |= sym.AttrReachable
syms = append(syms, debugLine) syms = append(syms, debugLine)
for _, u := range ctxt.compUnits { for _, u := range ctxt.compUnits {
reversetree(&u.dwinfo.Child) reversetree(&u.DWInfo.Child)
if u.dwinfo.Abbrev == dwarf.DW_ABRV_COMPUNIT_TEXTLESS { if u.DWInfo.Abbrev == dwarf.DW_ABRV_COMPUNIT_TEXTLESS {
continue continue
} }
writelines(ctxt, u, debugLine) 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. // newdie adds DIEs to the *beginning* of the parent's DIE list.
...@@ -1975,15 +1973,15 @@ func dwarfGenerateDebugSyms(ctxt *Link) { ...@@ -1975,15 +1973,15 @@ func dwarfGenerateDebugSyms(ctxt *Link) {
syms = collectlocs(ctxt, syms, ctxt.compUnits) syms = collectlocs(ctxt, syms, ctxt.compUnits)
syms = append(syms, debugRanges) syms = append(syms, debugRanges)
for _, unit := range ctxt.compUnits { for _, unit := range ctxt.compUnits {
syms = append(syms, unit.rangeSyms...) syms = append(syms, unit.RangeSyms...)
} }
dwarfp = syms 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 empty := true
for _, u := range units { for _, u := range units {
for _, fn := range u.funcDIEs { for _, fn := range u.FuncDIEs {
for i := range fn.R { for i := range fn.R {
reloc := &fn.R[i] // Copying sym.Reloc has measurable impact on performance 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) { if reloc.Type == objabi.R_DWARFSECREF && strings.HasPrefix(reloc.Sym.Name, dwarf.LocPrefix) {
...@@ -2126,21 +2124,21 @@ func dwarfcompress(ctxt *Link) { ...@@ -2126,21 +2124,21 @@ func dwarfcompress(ctxt *Link) {
Segdwarf.Length = pos - Segdwarf.Vaddr Segdwarf.Length = pos - Segdwarf.Vaddr
} }
type compilationUnitByStartPC []*compilationUnit type compilationUnitByStartPC []*sym.CompilationUnit
func (v compilationUnitByStartPC) Len() int { return len(v) } 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) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v compilationUnitByStartPC) Less(i, j int) bool { func (v compilationUnitByStartPC) Less(i, j int) bool {
switch { switch {
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 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 true 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 return false
default: 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
} }
} }
......
...@@ -1624,6 +1624,9 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, ...@@ -1624,6 +1624,9 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
c4 := bgetc(f) c4 := bgetc(f)
f.MustSeek(start, 0) 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) magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
if magic == 0x7f454c46 { // \x7F E L F if magic == 0x7f454c46 { // \x7F E L F
ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) { 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, ...@@ -1770,7 +1773,7 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
default: default:
log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups) 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 strictDupMsgCount += c
addImports(ctxt, lib, pn) addImports(ctxt, lib, pn)
return nil return nil
......
...@@ -92,8 +92,8 @@ type Link struct { ...@@ -92,8 +92,8 @@ type Link struct {
// Used to implement field tracking. // Used to implement field tracking.
Reachparent map[*sym.Symbol]*sym.Symbol Reachparent map[*sym.Symbol]*sym.Symbol
compUnits []*compilationUnit // DWARF compilation units compUnits []*sym.CompilationUnit // DWARF compilation units
compUnitByPackage map[*sym.Library]*compilationUnit runtimeCU *sym.CompilationUnit // One of the runtime CUs, the last one seen.
relocbuf []byte // temporary buffer for applying relocations relocbuf []byte // temporary buffer for applying relocations
} }
......
...@@ -39,6 +39,7 @@ type objReader struct { ...@@ -39,6 +39,7 @@ type objReader struct {
arch *sys.Arch arch *sys.Arch
syms *sym.Symbols syms *sym.Symbols
lib *sym.Library lib *sym.Library
unit *sym.CompilationUnit
pn string pn string
dupSym *sym.Symbol dupSym *sym.Symbol
localSymVersion int localSymVersion int
...@@ -81,7 +82,7 @@ const ( ...@@ -81,7 +82,7 @@ const (
// Load loads an object file f into library lib. // Load loads an object file f into library lib.
// The symbols loaded are added to syms. // 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() start := f.Offset()
roObject := f.SliceRO(uint64(length)) roObject := f.SliceRO(uint64(length))
if roObject != nil { if roObject != nil {
...@@ -90,6 +91,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, le ...@@ -90,6 +91,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, le
r := &objReader{ r := &objReader{
rd: f, rd: f,
lib: lib, lib: lib,
unit: unit,
arch: arch, arch: arch,
syms: syms, syms: syms,
pn: pn, pn: pn,
...@@ -254,7 +256,7 @@ func (r *objReader) readSym() { ...@@ -254,7 +256,7 @@ func (r *objReader) readSym() {
overwrite: overwrite:
s.File = r.pkgpref[:len(r.pkgpref)-1] s.File = r.pkgpref[:len(r.pkgpref)-1]
s.Lib = r.lib s.Unit = r.unit
if dupok { if dupok {
s.Attr |= sym.AttrDuplicateOK s.Attr |= sym.AttrDuplicateOK
} }
...@@ -405,7 +407,7 @@ overwrite: ...@@ -405,7 +407,7 @@ overwrite:
reason = fmt.Sprintf("new length %d != old length %d", reason = fmt.Sprintf("new length %d != old length %d",
len(data), len(dup.P)) 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 // For the moment, whitelist DWARF subprogram DIEs for
// auto-generated wrapper functions. What seems to happen // auto-generated wrapper functions. What seems to happen
......
// 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
}
...@@ -17,6 +17,7 @@ type Library struct { ...@@ -17,6 +17,7 @@ type Library struct {
DupTextSyms []*Symbol // dupok text symbols defined in this library DupTextSyms []*Symbol // dupok text symbols defined in this library
Main bool Main bool
Safe bool Safe bool
Units []*CompilationUnit
} }
func (l Library) String() string { func (l Library) String() string {
......
...@@ -32,7 +32,7 @@ type Symbol struct { ...@@ -32,7 +32,7 @@ type Symbol struct {
auxinfo *AuxSymbol auxinfo *AuxSymbol
Sect *Section Sect *Section
FuncInfo *FuncInfo FuncInfo *FuncInfo
Lib *Library // Package defining this symbol Unit *CompilationUnit
// P contains the raw symbol data. // P contains the raw symbol data.
P []byte P []byte
R []Reloc R []Reloc
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment