1
0
mirror of https://github.com/golang/go synced 2024-09-24 03:00:12 -06:00

cmd/{compile,link}: relocate generation of DWARF for global vars

Move DWARF generation for global variables from the linker to the
compiler. This effectively parallelizes this part of DWARF generation,
speeds up the linker minutely, and gives us a slightly more rational
implementation (there was really no compelling reason to do DWARF gen
for globals in the linker).

Change-Id: I0c1c98d3a647258697e90eb91d1d8a9f6f7f376a
Reviewed-on: https://go-review.googlesource.com/c/go/+/295011
Trust: Than McIntosh <thanm@google.com>
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
This commit is contained in:
Than McIntosh 2021-01-07 16:25:41 -05:00
parent 1c9e587b90
commit c819907754
6 changed files with 60 additions and 36 deletions

View File

@ -105,7 +105,7 @@ func Main(archInit func(*ssagen.ArchInfo)) {
// Record flags that affect the build result. (And don't
// record flags that don't, since that would cause spurious
// changes in the binary.)
dwarfgen.RecordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre")
dwarfgen.RecordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarf", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre")
if !base.EnableTrace && base.Flag.LowerT {
log.Fatalf("compiler not built with support for -t")

View File

@ -195,6 +195,7 @@ func dumpGlobal(n *ir.Name) {
}
types.CalcSize(n.Type())
ggloblnod(n)
base.Ctxt.DwarfGlobal(base.Ctxt.Pkgpath, types.TypeSymName(n.Type()), n.Linksym())
}
func dumpGlobalConst(n ir.Node) {

View File

@ -1041,6 +1041,15 @@ func PutIntConst(ctxt Context, info, typ Sym, name string, val int64) {
putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_sdata, DW_CLS_CONSTANT, val, nil)
}
// PutGlobal writes a DIE for a global variable.
func PutGlobal(ctxt Context, info, typ, gvar Sym, name string) {
Uleb128put(ctxt, info, DW_ABRV_VARIABLE)
putattr(ctxt, info, DW_ABRV_VARIABLE, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
putattr(ctxt, info, DW_ABRV_VARIABLE, DW_FORM_block1, DW_CLS_ADDRESS, 0, gvar)
putattr(ctxt, info, DW_ABRV_VARIABLE, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, typ)
putattr(ctxt, info, DW_ABRV_VARIABLE, DW_FORM_flag, DW_CLS_FLAG, 1, nil)
}
// PutBasedRanges writes a range table to sym. All addresses in ranges are
// relative to some base address, which must be arranged by the caller
// (e.g., with a DW_AT_low_pc attribute, or in a BASE-prefixed range).

View File

@ -402,6 +402,31 @@ func (ctxt *Link) DwarfIntConst(myimportpath, name, typename string, val int64)
dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val)
}
// DwarfGlobal creates a link symbol containing a DWARF entry for
// a global variable.
func (ctxt *Link) DwarfGlobal(myimportpath, typename string, varSym *LSym) {
if myimportpath == "" || varSym.Local() {
return
}
var varname string
if varSym.Pkg == "_" {
// The frontend uses package "_" to mark symbols that should not
// be referenced by index, e.g. linkname'd symbols.
varname = varSym.Name
} else {
// Convert "".<name> into a fully qualified package.sym name.
varname = objabi.PathToPrefix(myimportpath) + varSym.Name[len(`""`):]
}
dieSymName := dwarf.InfoPrefix + varname
dieSym := ctxt.LookupInit(dieSymName, func(s *LSym) {
s.Type = objabi.SDWARFVAR
s.Set(AttrDuplicateOK, true) // needed for shared linkage
ctxt.Data = append(ctxt.Data, s)
})
typeSym := ctxt.Lookup(dwarf.InfoPrefix + typename)
dwarf.PutGlobal(dwCtxt{ctxt}, dieSym, typeSym, varSym, varname)
}
func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath string) {
absfn := ctxt.DwFixups.AbsFuncDwarfSym(s)
if absfn.Size != 0 {

View File

@ -458,12 +458,6 @@ func newmemberoffsetattr(die *dwarf.DWDie, offs int32) {
newattr(die, dwarf.DW_AT_data_member_location, dwarf.DW_CLS_CONSTANT, int64(offs), nil)
}
// GDB doesn't like FORM_addr for AT_location, so emit a
// location expression that evals to a const.
func (d *dwctxt) newabslocexprattr(die *dwarf.DWDie, addr int64, symIdx loader.Sym) {
newattr(die, dwarf.DW_AT_location, dwarf.DW_CLS_ADDRESS, addr, dwSym(symIdx))
}
func (d *dwctxt) lookupOrDiag(n string) loader.Sym {
symIdx := d.ldr.Lookup(n, 0)
if symIdx == 0 {
@ -1020,25 +1014,6 @@ func (d *dwctxt) synthesizechantypes(ctxt *Link, die *dwarf.DWDie) {
}
}
func (d *dwctxt) dwarfDefineGlobal(ctxt *Link, symIdx loader.Sym, str string, v int64, gotype loader.Sym) {
// 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.
unit := d.ldr.SymUnit(symIdx)
if unit == nil {
unit = ctxt.runtimeCU
}
ver := d.ldr.SymVersion(symIdx)
dv := d.newdie(unit.DWInfo, dwarf.DW_ABRV_VARIABLE, str, int(ver))
d.newabslocexprattr(dv, v, symIdx)
if d.ldr.SymVersion(symIdx) < sym.SymVerStatic {
newattr(dv, dwarf.DW_AT_external, dwarf.DW_CLS_FLAG, 1, 0)
}
dt := d.defgotype(gotype)
d.newrefattr(dv, dwarf.DW_AT_type, dt)
}
// createUnitLength creates the initial length field with value v and update
// offset of unit_length if needed.
func (d *dwctxt) createUnitLength(su *loader.SymbolBuilder, v uint64) {
@ -1552,7 +1527,7 @@ func appendSyms(syms []loader.Sym, src []sym.LoaderSym) []loader.Sym {
func (d *dwctxt) writeUnitInfo(u *sym.CompilationUnit, abbrevsym loader.Sym, infoEpilog loader.Sym) []loader.Sym {
syms := []loader.Sym{}
if len(u.Textp) == 0 && u.DWInfo.Child == nil {
if len(u.Textp) == 0 && u.DWInfo.Child == nil && len(u.VarDIEs) == 0 {
return syms
}
@ -1583,6 +1558,7 @@ func (d *dwctxt) writeUnitInfo(u *sym.CompilationUnit, abbrevsym loader.Sym, inf
if u.Consts != 0 {
cu = append(cu, loader.Sym(u.Consts))
}
cu = appendSyms(cu, u.VarDIEs)
var cusize int64
for _, child := range cu {
cusize += int64(len(d.ldr.Data(child)))
@ -1907,10 +1883,11 @@ func dwarfGenerateDebugInfo(ctxt *Link) {
checkStrictDups = 1
}
// Create DIEs for global variables and the types they use.
// FIXME: ideally this should be done in the compiler, since
// for globals there isn't any abiguity about which package
// a global belongs to.
// Make a pass through all data symbols, looking for those
// corresponding to reachable, Go-generated, user-visible
// global variables. For each global of this sort, locate
// the corresponding compiler-generated DIE symbol and tack
// it onto the list associated with the unit.
for idx := loader.Sym(1); idx < loader.Sym(d.ldr.NDef()); idx++ {
if !d.ldr.AttrReachable(idx) ||
d.ldr.AttrNotInSymbolTable(idx) ||
@ -1925,7 +1902,8 @@ func dwarfGenerateDebugInfo(ctxt *Link) {
continue
}
// Skip things with no type
if d.ldr.SymGoType(idx) == 0 {
gt := d.ldr.SymGoType(idx)
if gt == 0 {
continue
}
// Skip file local symbols (this includes static tmps, stack
@ -1939,10 +1917,20 @@ func dwarfGenerateDebugInfo(ctxt *Link) {
continue
}
// Create DIE for global.
sv := d.ldr.SymValue(idx)
gt := d.ldr.SymGoType(idx)
d.dwarfDefineGlobal(ctxt, idx, sn, sv, gt)
// Find compiler-generated DWARF info sym for global in question,
// and tack it onto the appropriate unit. Note that there are
// circumstances under which we can't find the compiler-generated
// symbol-- this typically happens as a result of compiler options
// (e.g. compile package X with "-dwarf=0").
// FIXME: use an aux sym or a relocation here instead of a
// name lookup.
varDIE := d.ldr.Lookup(dwarf.InfoPrefix+sn, 0)
if varDIE != 0 {
unit := d.ldr.SymUnit(idx)
d.defgotype(gt)
unit.VarDIEs = append(unit.VarDIEs, sym.LoaderSym(varDIE))
}
}
d.synthesizestringtypes(ctxt, dwtypes.Child)

View File

@ -29,6 +29,7 @@ type CompilationUnit struct {
Consts LoaderSym // Package constants DIEs
FuncDIEs []LoaderSym // Function DIE subtrees
VarDIEs []LoaderSym // Global variable DIEs
AbsFnDIEs []LoaderSym // Abstract function DIE subtrees
RangeSyms []LoaderSym // Symbols for debug_range
Textp []LoaderSym // Text symbols in this CU