Commit 9c833831 authored by Alessandro Arzilli's avatar Alessandro Arzilli Committed by Heschi Kreinick

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 <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarHeschi Kreinick <heschi@google.com>
parent 669fa8f3
// 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 <exe> <suffix>
//
// Opens <exe>, which must be an executable or a library and checks that
// there is an entry in .debug_info whose name ends in <suffix>
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)
}
...@@ -32,6 +32,10 @@ GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o=unnamed1.so u ...@@ -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" -buildmode=plugin -o=unnamed2.so unnamed2/main.go
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" host 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 LD_LIBRARY_PATH=$(pwd) ./host
# Test that types and itabs get properly uniqified. # Test that types and itabs get properly uniqified.
......
...@@ -1602,7 +1602,7 @@ func (ctxt *Link) dodata() { ...@@ -1602,7 +1602,7 @@ func (ctxt *Link) dodata() {
datap = append(datap, data[symn]...) datap = append(datap, data[symn]...)
} }
dwarfgeneratedebugsyms(ctxt) dwarfGenerateDebugSyms(ctxt)
var i int var i int
for ; i < len(dwarfp); i++ { for ; i < len(dwarfp); i++ {
......
...@@ -21,6 +21,7 @@ import ( ...@@ -21,6 +21,7 @@ import (
"cmd/link/internal/sym" "cmd/link/internal/sym"
"fmt" "fmt"
"log" "log"
"sort"
"strings" "strings"
) )
...@@ -828,6 +829,16 @@ func synthesizechantypes(ctxt *Link, die *dwarf.DWDie) { ...@@ -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 // For use with pass.c::genasmsym
func defdwsymb(ctxt *Link, s *sym.Symbol, str string, t SymbolType, v int64, gotype *sym.Symbol) { func defdwsymb(ctxt *Link, s *sym.Symbol, str string, t SymbolType, v int64, gotype *sym.Symbol) {
if strings.HasPrefix(str, "go.string.") { if strings.HasPrefix(str, "go.string.") {
...@@ -837,32 +848,24 @@ func defdwsymb(ctxt *Link, s *sym.Symbol, str string, t SymbolType, v int64, got ...@@ -837,32 +848,24 @@ func defdwsymb(ctxt *Link, s *sym.Symbol, str string, t SymbolType, v int64, got
return 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 { switch t {
case DataSym, BSSSym:
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: default:
return 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)
} }
fallthrough
case AutoSym, ParamSym, DeletedAutoSym: dwarfDefineGlobal(ctxt, s, str, v, gotype)
dt = defgotype(ctxt, gotype)
}
if dv != nil { case AutoSym, ParamSym, DeletedAutoSym:
newrefattr(dv, dwarf.DW_AT_type, dt) defgotype(ctxt, gotype)
} }
} }
...@@ -875,27 +878,17 @@ type compilationUnit struct { ...@@ -875,27 +878,17 @@ type compilationUnit struct {
dwinfo *dwarf.DWDie // CU root DIE dwinfo *dwarf.DWDie // CU root DIE
funcDIEs []*sym.Symbol // Function DIE subtrees funcDIEs []*sym.Symbol // Function DIE subtrees
absFnDIEs []*sym.Symbol // Abstract 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. // calcCompUnitRanges calculates the PC ranges of the compilation units.
func getCompilationUnits(ctxt *Link) []*compilationUnit { func calcCompUnitRanges(ctxt *Link) {
units := []*compilationUnit{}
index := make(map[*sym.Library]*compilationUnit)
var prevUnit *compilationUnit var prevUnit *compilationUnit
for _, s := range ctxt.Textp { for _, s := range ctxt.Textp {
if s.FuncInfo == nil { if s.FuncInfo == nil {
continue continue
} }
unit := index[s.Lib] unit := ctxt.compUnitByPackage[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
}
// Update PC ranges. // Update PC ranges.
// //
...@@ -910,7 +903,6 @@ func getCompilationUnits(ctxt *Link) []*compilationUnit { ...@@ -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 unit.pcs[len(unit.pcs)-1].End = s.Value - unit.lib.Textp[0].Value + s.Size
} }
return units
} }
func movetomodule(parent *dwarf.DWDie) { func movetomodule(parent *dwarf.DWDie) {
...@@ -1064,62 +1056,13 @@ func importInfoSymbol(ctxt *Link, dsym *sym.Symbol) { ...@@ -1064,62 +1056,13 @@ func importInfoSymbol(ctxt *Link, dsym *sym.Symbol) {
for i := range dsym.R { for i := range dsym.R {
r := &dsym.R[i] // Copying sym.Reloc has measurable impact on performance r := &dsym.R[i] // Copying sym.Reloc has measurable impact on performance
if r.Type == objabi.R_DWARFSECREF && r.Sym.Size == 0 { 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) n := nameFromDIESym(r.Sym)
defgotype(ctxt, ctxt.Syms.Lookup("type."+n, 0)) defgotype(ctxt, ctxt.Syms.Lookup("type."+n, 0))
} }
} }
} }
// For the specified function, collect symbols corresponding to any func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) (dwinfo *dwarf.DWDie) {
// "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) {
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.
...@@ -1130,7 +1073,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo ...@@ -1130,7 +1073,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo
lang := dwarf.DW_LANG_Go 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_language, dwarf.DW_CLS_CONSTANT, int64(lang), 0)
newattr(dwinfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, ls.Size, ls) 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. // 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 ...@@ -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 // the linker directory. If we move CU construction into the
// compiler, this should happen naturally. // compiler, this should happen naturally.
newattr(dwinfo, dwarf.DW_AT_comp_dir, dwarf.DW_CLS_STRING, int64(len(compDir)), compDir) 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 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
...@@ -1183,7 +1126,8 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo ...@@ -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 // 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 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 { for _, f := range s.FuncInfo.File {
if _, ok := fileNums[int(f.Value)]; ok { if _, ok := fileNums[int(f.Value)]; ok {
continue continue
...@@ -1195,20 +1139,16 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo ...@@ -1195,20 +1139,16 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo
ls.AddUint8(0) ls.AddUint8(0)
ls.AddUint8(0) ls.AddUint8(0)
} }
for ri := 0; ri < len(dsym.R); ri++ {
// 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 {
r := &dsym.R[ri] r := &dsym.R[ri]
if r.Type != objabi.R_DWARFFILEREF { if r.Type != objabi.R_DWARFFILEREF {
continue continue
} }
_, ok := fileNums[int(r.Sym.Value)] // A file that is only mentioned in an inlined subroutine will appear
if !ok { // 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 fileNums[int(r.Sym.Value)] = len(fileNums) + 1
Addstring(ls, r.Sym.Name) Addstring(ls, r.Sym.Name)
ls.AddUint8(0) ls.AddUint8(0)
...@@ -1216,7 +1156,6 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo ...@@ -1216,7 +1156,6 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo
ls.AddUint8(0) ls.AddUint8(0)
} }
} }
}
// 4 zeros: the string termination + 3 fields. // 4 zeros: the string termination + 3 fields.
ls.AddUint8(0) ls.AddUint8(0)
...@@ -1227,7 +1166,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo ...@@ -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)) dwarf.Uleb128put(dwarfctxt, ls, 1+int64(ctxt.Arch.PtrSize))
ls.AddUint8(dwarf.DW_LNE_set_address) ls.AddUint8(dwarf.DW_LNE_set_address)
s := textp[0] s := unit.lib.Textp[0]
pc := s.Value pc := s.Value
line := 1 line := 1
file := 1 file := 1
...@@ -1236,19 +1175,12 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo ...@@ -1236,19 +1175,12 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo
var pcfile Pciter var pcfile Pciter
var pcline Pciter var pcline Pciter
var pcstmt Pciter var pcstmt Pciter
for i, s := range textp { for i, s := range unit.lib.Textp {
dsym := ctxt.Syms.Lookup(dwarf.InfoPrefix+s.Name, int(s.Version))
funcs = append(funcs, dsym)
absfuncs = collectAbstractFunctions(ctxt, s, dsym, absfuncs)
finddebugruntimepath(s) 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, &pcfile, &s.FuncInfo.Pcfile)
pciterinit(ctxt, &pcline, &s.FuncInfo.Pcline) pciterinit(ctxt, &pcline, &s.FuncInfo.Pcline)
pciterinit(ctxt, &pcstmt, &pctostmtData) pciterinit(ctxt, &pcstmt, &sym.Pcdata{P: s.FuncInfo.IsStmtSym.P})
if pcstmt.done != 0 { if pcstmt.done != 0 {
// Assembly files lack a pcstmt section, we assume that every instruction // 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 ...@@ -1312,7 +1244,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo
pciternext(&pcline) 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. // 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))
...@@ -1333,7 +1265,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo ...@@ -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 // 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 funcs { 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 {
...@@ -1364,7 +1296,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo ...@@ -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. // writepcranges generates the DW_AT_ranges table for compilation unit cu.
...@@ -1516,24 +1448,6 @@ func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol { ...@@ -1516,24 +1448,6 @@ func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
return syms 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 * Walk DWarfDebugInfoEntries, and emit .debug_info
*/ */
...@@ -1672,24 +1586,15 @@ func writegdbscript(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol { ...@@ -1672,24 +1586,15 @@ func writegdbscript(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
var prototypedies map[string]*dwarf.DWDie var prototypedies map[string]*dwarf.DWDie
/* func dwarfEnabled(ctxt *Link) bool {
* 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) {
if *FlagW { // disable dwarf if *FlagW { // disable dwarf
return return false
} }
if *FlagS && ctxt.HeadType != objabi.Hdarwin { if *FlagS && ctxt.HeadType != objabi.Hdarwin {
return return false
} }
if ctxt.HeadType == objabi.Hplan9 || ctxt.HeadType == objabi.Hjs { if ctxt.HeadType == objabi.Hplan9 || ctxt.HeadType == objabi.Hjs {
return return false
} }
if ctxt.LinkMode == LinkExternal { if ctxt.LinkMode == LinkExternal {
...@@ -1698,14 +1603,27 @@ func dwarfgeneratedebugsyms(ctxt *Link) { ...@@ -1698,14 +1603,27 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
case ctxt.HeadType == objabi.Hdarwin: case ctxt.HeadType == objabi.Hdarwin:
case ctxt.HeadType == objabi.Hwindows: case ctxt.HeadType == objabi.Hwindows:
default: default:
return return false
} }
} }
if ctxt.Debugvlog != 0 { return true
ctxt.Logf("%5.2f dwarf\n", Cputime()) }
// 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. // 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")
...@@ -1748,12 +1666,84 @@ func dwarfgeneratedebugsyms(ctxt *Link) { ...@@ -1748,12 +1666,84 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
defgotype(ctxt, lookupOrDiag(ctxt, typ)) defgotype(ctxt, lookupOrDiag(ctxt, typ))
} }
// Create DIEs for global variables and the types they use.
genasmsym(ctxt, defdwsymb) 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) abbrev := writeabbrev(ctxt)
syms := []*sym.Symbol{abbrev} 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. // Write per-package line and range tables and start their CU DIEs.
debugLine := ctxt.Syms.Lookup(".debug_line", 0) debugLine := ctxt.Syms.Lookup(".debug_line", 0)
...@@ -1762,16 +1752,11 @@ func dwarfgeneratedebugsyms(ctxt *Link) { ...@@ -1762,16 +1752,11 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
debugRanges.Type = sym.SDWARFRANGE debugRanges.Type = sym.SDWARFRANGE
debugRanges.Attr |= sym.AttrReachable debugRanges.Attr |= sym.AttrReachable
syms = append(syms, debugLine) syms = append(syms, debugLine)
for _, u := range units { for _, u := range ctxt.compUnits {
u.dwinfo, u.funcDIEs, u.absFnDIEs = writelines(ctxt, u.lib, u.lib.Textp, debugLine) u.dwinfo = writelines(ctxt, u, debugLine)
writepcranges(ctxt, u.dwinfo, u.lib.Textp[0], u.pcs, debugRanges) 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. // newdie adds DIEs to the *beginning* of the parent's DIE list.
// Now that we're done creating DIEs, reverse the trees so DIEs // Now that we're done creating DIEs, reverse the trees so DIEs
// appear in the order they were created. // appear in the order they were created.
...@@ -1784,7 +1769,7 @@ func dwarfgeneratedebugsyms(ctxt *Link) { ...@@ -1784,7 +1769,7 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
// Need to reorder symbols so sym.SDWARFINFO is after all sym.SDWARFSECT // Need to reorder symbols so sym.SDWARFINFO is after all sym.SDWARFSECT
// (but we need to generate dies before writepub) // (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 = writeframes(ctxt, syms)
syms = writepub(ctxt, ".debug_pubnames", ispubname, syms) syms = writepub(ctxt, ".debug_pubnames", ispubname, syms)
...@@ -1793,9 +1778,11 @@ func dwarfgeneratedebugsyms(ctxt *Link) { ...@@ -1793,9 +1778,11 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
// Now we're done writing SDWARFSECT symbols, so we can write // Now we're done writing SDWARFSECT symbols, so we can write
// other SDWARF* symbols. // other SDWARF* symbols.
syms = append(syms, infosyms...) syms = append(syms, infosyms...)
syms = collectlocs(ctxt, syms, units) syms = collectlocs(ctxt, syms, ctxt.compUnits)
syms = append(syms, debugRanges) syms = append(syms, debugRanges)
syms = writeranges(ctxt, syms) for _, unit := range ctxt.compUnits {
syms = append(syms, unit.rangeSyms...)
}
dwarfp = syms dwarfp = syms
} }
...@@ -2006,3 +1993,12 @@ func dwarfcompress(ctxt *Link) { ...@@ -2006,3 +1993,12 @@ func dwarfcompress(ctxt *Link) {
} }
Segdwarf.Length = pos - Segdwarf.Vaddr 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
}
...@@ -654,7 +654,6 @@ func (ctxt *Link) mangleTypeSym() { ...@@ -654,7 +654,6 @@ func (ctxt *Link) mangleTypeSym() {
return return
} }
*FlagW = true // disable DWARF generation
for _, s := range ctxt.Syms.Allsym { for _, s := range ctxt.Syms.Allsym {
newName := typeSymbolMangle(s.Name) newName := typeSymbolMangle(s.Name)
if newName != s.Name { if newName != s.Name {
......
...@@ -89,6 +89,9 @@ type Link struct { ...@@ -89,6 +89,9 @@ 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
compUnitByPackage map[*sym.Library]*compilationUnit
} }
type unresolvedSymKey struct { type unresolvedSymKey struct {
......
...@@ -208,6 +208,7 @@ func Main(arch *sys.Arch, theArch Arch) { ...@@ -208,6 +208,7 @@ func Main(arch *sys.Arch, theArch Arch) {
ctxt.dostrdata() ctxt.dostrdata()
deadcode(ctxt) deadcode(ctxt)
dwarfGenerateDebugInfo(ctxt)
if objabi.Fieldtrack_enabled != 0 { if objabi.Fieldtrack_enabled != 0 {
fieldtrack(ctxt) fieldtrack(ctxt)
} }
......
...@@ -318,6 +318,8 @@ overwrite: ...@@ -318,6 +318,8 @@ overwrite:
pc.InlTree[i].Func = r.readSymIndex() pc.InlTree[i].Func = r.readSymIndex()
} }
s.FuncInfo.IsStmtSym = r.syms.Lookup(dwarf.IsStmtPrefix+s.Name, int(s.Version))
s.Lib = r.lib s.Lib = r.lib
if !dupok { if !dupok {
if s.Attr.OnList() { if s.Attr.OnList() {
......
...@@ -478,6 +478,7 @@ type FuncInfo struct { ...@@ -478,6 +478,7 @@ type FuncInfo struct {
Pcline Pcdata Pcline Pcdata
Pcinline Pcdata Pcinline Pcdata
Pcdata []Pcdata Pcdata []Pcdata
IsStmtSym *Symbol
Funcdata []*Symbol Funcdata []*Symbol
Funcdataoff []int64 Funcdataoff []int64
File []*Symbol File []*Symbol
......
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