From 1c8943bd59157878141faab0c93848f45d3d51d1 Mon Sep 17 00:00:00 2001 From: Alessandro Arzilli Date: Tue, 25 Sep 2018 11:52:24 +0200 Subject: [PATCH] cmd/link: move DIE of global variables to their compile unit The DIEs for global variables were all assigned to the first emitted compile unit in debug_info, regardless of what it was. Move them instead to their respective compile units. Change-Id: If794fa0ba4702f5b959c6e8c16119b16e7ecf6d8 Reviewed-on: https://go-review.googlesource.com/137235 Reviewed-by: Than McIntosh --- .../compile/internal/ssa/stmtlines_test.go | 3 + src/cmd/internal/dwarf/dwarf.go | 13 ++ src/cmd/link/dwarf_test.go | 3 + src/cmd/link/internal/ld/dwarf.go | 126 ++++++++++-------- src/cmd/link/internal/objfile/objfile.go | 2 +- 5 files changed, 88 insertions(+), 59 deletions(-) diff --git a/src/cmd/compile/internal/ssa/stmtlines_test.go b/src/cmd/compile/internal/ssa/stmtlines_test.go index 1081f83f6d..c0fc7adab5 100644 --- a/src/cmd/compile/internal/ssa/stmtlines_test.go +++ b/src/cmd/compile/internal/ssa/stmtlines_test.go @@ -62,6 +62,9 @@ func TestStmtLines(t *testing.T) { if pkgname == "runtime" { continue } + if e.Val(dwarf.AttrStmtList) == nil { + continue + } lrdr, err := dw.LineReader(e) must(err) diff --git a/src/cmd/internal/dwarf/dwarf.go b/src/cmd/internal/dwarf/dwarf.go index 96fb2b765b..355091feda 100644 --- a/src/cmd/internal/dwarf/dwarf.go +++ b/src/cmd/internal/dwarf/dwarf.go @@ -304,6 +304,7 @@ const ( const ( DW_ABRV_NULL = iota DW_ABRV_COMPUNIT + DW_ABRV_COMPUNIT_TEXTLESS DW_ABRV_FUNCTION DW_ABRV_FUNCTION_ABSTRACT DW_ABRV_FUNCTION_CONCRETE @@ -368,6 +369,18 @@ var abbrevs = [DW_NABRV]dwAbbrev{ }, }, + /* COMPUNIT_TEXTLESS */ + { + DW_TAG_compile_unit, + DW_CHILDREN_yes, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_language, DW_FORM_data1}, + {DW_AT_comp_dir, DW_FORM_string}, + {DW_AT_producer, DW_FORM_string}, + }, + }, + /* FUNCTION */ { DW_TAG_subprogram, diff --git a/src/cmd/link/dwarf_test.go b/src/cmd/link/dwarf_test.go index ff11689bbc..2c01456f6b 100644 --- a/src/cmd/link/dwarf_test.go +++ b/src/cmd/link/dwarf_test.go @@ -122,6 +122,9 @@ func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string) r.SkipChildren() continue } + if cu.Val(dwarf.AttrStmtList) == nil { + continue + } lr, err := d.LineReader(cu) if err != nil { t.Fatal(err) diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 2164fa80a0..743f4cedd4 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -5,7 +5,7 @@ // TODO/NICETOHAVE: // - eliminate DW_CLS_ if not used // - package info in compilation units -// - assign global variables and types to their packages +// - assign types to their packages // - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg // ptype struct '[]uint8' and qualifiers need to be quoted away // - file:line info for variables @@ -106,15 +106,8 @@ func writeabbrev(ctxt *Link) *sym.Symbol { return s } -/* - * Root DIEs for compilation units, types and global variables. - */ -var dwroot dwarf.DWDie - var dwtypes dwarf.DWDie -var dwglobals dwarf.DWDie - func newattr(die *dwarf.DWDie, attr uint16, cls int, value int64, data interface{}) *dwarf.DWAttr { a := new(dwarf.DWAttr) a.Link = die.Attr @@ -835,7 +828,11 @@ 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)) + lib := s.Lib + if lib == nil { + lib = ctxt.LibraryByPkg["runtime"] + } + dv := newdie(ctxt, ctxt.compUnitByPackage[lib].dwinfo, 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) @@ -910,10 +907,11 @@ func calcCompUnitRanges(ctxt *Link) { } } -func movetomodule(parent *dwarf.DWDie) { - die := dwroot.Child.Child +func movetomodule(ctxt *Link, parent *dwarf.DWDie) { + runtimelib := ctxt.LibraryByPkg["runtime"] + die := ctxt.compUnitByPackage[runtimelib].dwinfo.Child if die == nil { - dwroot.Child.Child = parent.Child + ctxt.compUnitByPackage[runtimelib].dwinfo.Child = parent.Child return } for die.Link != nil { @@ -1067,7 +1065,7 @@ func importInfoSymbol(ctxt *Link, dsym *sym.Symbol) { } } -func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) (dwinfo *dwarf.DWDie) { +func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { var dwarfctxt dwarf.Context = dwctxt{ctxt} is_stmt := uint8(1) // initially = recommended default_is_stmt = 1, tracks is_stmt toggles. @@ -1076,29 +1074,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) (dwinfo *dwar headerstart := int64(-1) headerend := int64(-1) - lang := dwarf.DW_LANG_Go - - 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. - 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(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) - } - newattr(dwinfo, dwarf.DW_AT_producer, dwarf.DW_CLS_STRING, int64(len(producer)), producer) + 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 @@ -1300,8 +1276,6 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) (dwinfo *dwar } } } - - return dwinfo } // writepcranges generates the DW_AT_ranges table for compilation unit cu. @@ -1468,15 +1442,13 @@ func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevs var dwarfctxt dwarf.Context = dwctxt{ctxt} - // Re-index per-package information by its CU die. - unitByDIE := make(map[*dwarf.DWDie]*compilationUnit) for _, u := range units { - unitByDIE[u.dwinfo] = u - } - - for compunit := dwroot.Child; compunit != nil; compunit = compunit.Link { + compunit := u.dwinfo s := dtolsym(compunit.Sym) - u := unitByDIE[compunit] + + if len(u.lib.Textp) == 0 && u.dwinfo.Child == nil { + continue + } // Write .debug_info Compilation Unit Header (sec 7.5.1) // Fields marked with (*) must be changed for 64-bit dwarf @@ -1536,7 +1508,11 @@ func writepub(ctxt *Link, sname string, ispub func(*dwarf.DWDie) bool, syms []*s s.Type = sym.SDWARFSECT syms = append(syms, s) - for compunit := dwroot.Child; compunit != nil; compunit = compunit.Link { + for _, u := range ctxt.compUnits { + if len(u.lib.Textp) == 0 && u.dwinfo.Child == nil { + continue + } + compunit := u.dwinfo sectionstart := s.Size culength := uint32(getattr(compunit, dwarf.DW_AT_byte_size).Value) + 4 @@ -1671,13 +1647,10 @@ func dwarfGenerateDebugInfo(ctxt *Link) { defgotype(ctxt, lookupOrDiag(ctxt, typ)) } - // Create DIEs for global variables and the types they use. - genasmsym(ctxt, defdwsymb) + // fake root DIE for compile unit DIEs + var dwroot dwarf.DWDie 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) @@ -1686,6 +1659,31 @@ func dwarfGenerateDebugInfo(ctxt *Link) { 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) + } + newattr(unit.dwinfo, dwarf.DW_AT_producer, dwarf.DW_CLS_STRING, int64(len(producer)), producer) + + if len(lib.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. @@ -1726,6 +1724,9 @@ func dwarfGenerateDebugInfo(ctxt *Link) { } } + // Create DIEs for global variables and the types they use. + genasmsym(ctxt, defdwsymb) + synthesizestringtypes(ctxt, dwtypes.Child) synthesizeslicetypes(ctxt, dwtypes.Child) synthesizemaptypes(ctxt, dwtypes.Child) @@ -1758,19 +1759,19 @@ func dwarfGenerateDebugSyms(ctxt *Link) { debugRanges.Attr |= sym.AttrReachable syms = append(syms, debugLine) for _, u := range ctxt.compUnits { - u.dwinfo = writelines(ctxt, u, debugLine) + reversetree(&u.dwinfo.Child) + if u.dwinfo.Abbrev == dwarf.DW_ABRV_COMPUNIT_TEXTLESS { + continue + } + writelines(ctxt, u, debugLine) writepcranges(ctxt, u.dwinfo, u.lib.Textp[0], u.pcs, debugRanges) } // 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. - reversetree(&dwroot.Child) reversetree(&dwtypes.Child) - reversetree(&dwglobals.Child) - - movetomodule(&dwtypes) - movetomodule(&dwglobals) + movetomodule(ctxt, &dwtypes) // Need to reorder symbols so sym.SDWARFINFO is after all sym.SDWARFSECT // (but we need to generate dies before writepub) @@ -2005,5 +2006,14 @@ 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 + 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: + return true + case len(v[i].lib.Textp) == 0 && len(v[j].lib.Textp) != 0: + return false + default: + return v[i].lib.Textp[0].Value < v[j].lib.Textp[0].Value + } } diff --git a/src/cmd/link/internal/objfile/objfile.go b/src/cmd/link/internal/objfile/objfile.go index e3800de304..3a8923b073 100644 --- a/src/cmd/link/internal/objfile/objfile.go +++ b/src/cmd/link/internal/objfile/objfile.go @@ -203,6 +203,7 @@ func (r *objReader) readSym() { overwrite: s.File = pkg + s.Lib = r.lib if dupok { s.Attr |= sym.AttrDuplicateOK } @@ -320,7 +321,6 @@ overwrite: s.FuncInfo.IsStmtSym = r.syms.Lookup(dwarf.IsStmtPrefix+s.Name, int(s.Version)) - s.Lib = r.lib if !dupok { if s.Attr.OnList() { log.Fatalf("symbol %s listed multiple times", s.Name) -- 2.50.0