]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: move dwarf part of DWARF generation before type name mangling
authorAlessandro Arzilli <alessandro.arzilli@gmail.com>
Tue, 24 Apr 2018 11:05:10 +0000 (13:05 +0200)
committerHeschi Kreinick <heschi@google.com>
Tue, 4 Sep 2018 17:44:41 +0000 (17:44 +0000)
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: Heschi Kreinick <heschi@google.com>
misc/cgo/testplugin/src/checkdwarf/main.go [new file with mode: 0644]
misc/cgo/testplugin/test.bash
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/dwarf.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/ld/link.go
src/cmd/link/internal/ld/main.go
src/cmd/link/internal/objfile/objfile.go
src/cmd/link/internal/sym/symbol.go

diff --git a/misc/cgo/testplugin/src/checkdwarf/main.go b/misc/cgo/testplugin/src/checkdwarf/main.go
new file mode 100644 (file)
index 0000000..b689c4a
--- /dev/null
@@ -0,0 +1,106 @@
+// 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)
+}
index bf8ed3cd191eaeef2e1075dcfe7a5d5de1a2adfe..5a87f5e74673d5d6e2961a899c7f73e55a6ebe09 100755 (executable)
@@ -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" 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
 
 # Test that types and itabs get properly uniqified.
index ff0d3a8d84e55b49606a261d536abb71cdad3c6a..ee98aef20dc1997ab5fec55f13d211f90bf49a1f 100644 (file)
@@ -1602,7 +1602,7 @@ func (ctxt *Link) dodata() {
                datap = append(datap, data[symn]...)
        }
 
-       dwarfgeneratedebugsyms(ctxt)
+       dwarfGenerateDebugSyms(ctxt)
 
        var i int
        for ; i < len(dwarfp); i++ {
index 4cb9295f438de57dc47a022483b1e4de0ef03196..959fc8290c08d96cbc461009016601e94d68febd 100644 (file)
@@ -21,6 +21,7 @@ import (
        "cmd/link/internal/sym"
        "fmt"
        "log"
+       "sort"
        "strings"
 )
 
@@ -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
 func defdwsymb(ctxt *Link, s *sym.Symbol, str string, t SymbolType, v int64, gotype *sym.Symbol) {
        if strings.HasPrefix(str, "go.string.") {
@@ -837,32 +848,24 @@ func defdwsymb(ctxt *Link, s *sym.Symbol, str string, t SymbolType, v int64, got
                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 {
-       default:
-               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)
+               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:
+                       return
                }
-               fallthrough
 
-       case AutoSym, ParamSym, DeletedAutoSym:
-               dt = defgotype(ctxt, gotype)
-       }
+               dwarfDefineGlobal(ctxt, s, str, v, gotype)
 
-       if dv != nil {
-               newrefattr(dv, dwarf.DW_AT_type, dt)
+       case AutoSym, ParamSym, DeletedAutoSym:
+               defgotype(ctxt, gotype)
        }
 }
 
@@ -875,27 +878,17 @@ type compilationUnit struct {
        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
 }
 
-// getCompilationUnits divides the symbols in ctxt.Textp by package.
-func getCompilationUnits(ctxt *Link) []*compilationUnit {
-       units := []*compilationUnit{}
-       index := make(map[*sym.Library]*compilationUnit)
+// calcCompUnitRanges calculates the PC ranges of the compilation units.
+func calcCompUnitRanges(ctxt *Link) {
        var prevUnit *compilationUnit
        for _, s := range ctxt.Textp {
                if s.FuncInfo == nil {
                        continue
                }
-               unit := index[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
-               }
+               unit := ctxt.compUnitByPackage[s.Lib]
 
                // Update PC ranges.
                //
@@ -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
        }
-       return units
 }
 
 func movetomodule(parent *dwarf.DWDie) {
@@ -1064,62 +1056,13 @@ func importInfoSymbol(ctxt *Link, dsym *sym.Symbol) {
        for i := range dsym.R {
                r := &dsym.R[i] // Copying sym.Reloc has measurable impact on performance
                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)
                        defgotype(ctxt, ctxt.Syms.Lookup("type."+n, 0))
                }
        }
 }
 
-// For the specified function, collect symbols corresponding to any
-// "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) {
+func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) (dwinfo *dwarf.DWDie) {
 
        var dwarfctxt dwarf.Context = dwctxt{ctxt}
        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
 
        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_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.
@@ -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
        // 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."+lib.Pkg, 0)
+       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
@@ -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
        // indexes (created by numberfile) to CU-local indexes.
        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 {
                        if _, ok := fileNums[int(f.Value)]; ok {
                                continue
@@ -1195,26 +1139,21 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo
                        ls.AddUint8(0)
                        ls.AddUint8(0)
                }
-
-               // 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 {
+               for ri := 0; ri < len(dsym.R); ri++ {
                        r := &dsym.R[ri]
                        if r.Type != objabi.R_DWARFFILEREF {
                                continue
                        }
-                       _, ok := fileNums[int(r.Sym.Value)]
-                       if !ok {
-                               fileNums[int(r.Sym.Value)] = len(fileNums) + 1
-                               Addstring(ls, r.Sym.Name)
-                               ls.AddUint8(0)
-                               ls.AddUint8(0)
-                               ls.AddUint8(0)
+                       // A file that is only mentioned in an inlined subroutine will appear
+                       // 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
+                       Addstring(ls, r.Sym.Name)
+                       ls.AddUint8(0)
+                       ls.AddUint8(0)
+                       ls.AddUint8(0)
                }
        }
 
@@ -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))
        ls.AddUint8(dwarf.DW_LNE_set_address)
 
-       s := textp[0]
+       s := unit.lib.Textp[0]
        pc := s.Value
        line := 1
        file := 1
@@ -1236,19 +1175,12 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo
        var pcfile Pciter
        var pcline Pciter
        var pcstmt Pciter
-       for i, s := range textp {
-               dsym := ctxt.Syms.Lookup(dwarf.InfoPrefix+s.Name, int(s.Version))
-               funcs = append(funcs, dsym)
-               absfuncs = collectAbstractFunctions(ctxt, s, dsym, absfuncs)
-
+       for i, s := range unit.lib.Textp {
                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, &pcline, &s.FuncInfo.Pcline)
-               pciterinit(ctxt, &pcstmt, &pctostmtData)
+               pciterinit(ctxt, &pcstmt, &sym.Pcdata{P: s.FuncInfo.IsStmtSym.P})
 
                if pcstmt.done != 0 {
                        // 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
                                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.
                        is_stmt = 1
                        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
        // DIE flavors (ex: variables) then those DIEs would need to
        // be included below.
        missing := make(map[int]interface{})
-       for _, f := range funcs {
+       for _, f := range unit.funcDIEs {
                for ri := range f.R {
                        r := &f.R[ri]
                        if r.Type != objabi.R_DWARFFILEREF {
@@ -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.
@@ -1516,24 +1448,6 @@ func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
        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
  */
@@ -1672,24 +1586,15 @@ func writegdbscript(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
 
 var prototypedies map[string]*dwarf.DWDie
 
-/*
- * 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) {
+func dwarfEnabled(ctxt *Link) bool {
        if *FlagW { // disable dwarf
-               return
+               return false
        }
        if *FlagS && ctxt.HeadType != objabi.Hdarwin {
-               return
+               return false
        }
        if ctxt.HeadType == objabi.Hplan9 || ctxt.HeadType == objabi.Hjs {
-               return
+               return false
        }
 
        if ctxt.LinkMode == LinkExternal {
@@ -1698,14 +1603,27 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
                case ctxt.HeadType == objabi.Hdarwin:
                case ctxt.HeadType == objabi.Hwindows:
                default:
-                       return
+                       return false
                }
        }
 
-       if ctxt.Debugvlog != 0 {
-               ctxt.Logf("%5.2f dwarf\n", Cputime())
+       return true
+}
+
+// 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.
        newattr(&dwtypes, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len("dwtypes")), "dwtypes")
 
@@ -1748,12 +1666,84 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
                defgotype(ctxt, lookupOrDiag(ctxt, typ))
        }
 
+       // Create DIEs for global variables and the types they use.
        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)
        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.
        debugLine := ctxt.Syms.Lookup(".debug_line", 0)
@@ -1762,16 +1752,11 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
        debugRanges.Type = sym.SDWARFRANGE
        debugRanges.Attr |= sym.AttrReachable
        syms = append(syms, debugLine)
-       for _, u := range units {
-               u.dwinfo, u.funcDIEs, u.absFnDIEs = writelines(ctxt, u.lib, u.lib.Textp, debugLine)
+       for _, u := range ctxt.compUnits {
+               u.dwinfo = writelines(ctxt, u, debugLine)
                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.
        // Now that we're done creating DIEs, reverse the trees so DIEs
        // appear in the order they were created.
@@ -1784,7 +1769,7 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
 
        // Need to reorder symbols so sym.SDWARFINFO is after all sym.SDWARFSECT
        // (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 = writepub(ctxt, ".debug_pubnames", ispubname, syms)
@@ -1793,9 +1778,11 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
        // Now we're done writing SDWARFSECT symbols, so we can write
        // other SDWARF* symbols.
        syms = append(syms, infosyms...)
-       syms = collectlocs(ctxt, syms, units)
+       syms = collectlocs(ctxt, syms, ctxt.compUnits)
        syms = append(syms, debugRanges)
-       syms = writeranges(ctxt, syms)
+       for _, unit := range ctxt.compUnits {
+               syms = append(syms, unit.rangeSyms...)
+       }
        dwarfp = syms
 }
 
@@ -2006,3 +1993,12 @@ func dwarfcompress(ctxt *Link) {
        }
        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
+}
index 331b6ca6145edd971e76f02cfacc47f5ed483bf7..5e99149d2549cf2340affd0ad0fcfc2c62fb2b51 100644 (file)
@@ -654,7 +654,6 @@ func (ctxt *Link) mangleTypeSym() {
                return
        }
 
-       *FlagW = true // disable DWARF generation
        for _, s := range ctxt.Syms.Allsym {
                newName := typeSymbolMangle(s.Name)
                if newName != s.Name {
index bf5754435786fa930ec20cedfc778449f1fd7698..48b92724b6fe075ede810f95b31f3049579d1f62 100644 (file)
@@ -89,6 +89,9 @@ type Link struct {
 
        // Used to implement field tracking.
        Reachparent map[*sym.Symbol]*sym.Symbol
+
+       compUnits         []*compilationUnit // DWARF compilation units
+       compUnitByPackage map[*sym.Library]*compilationUnit
 }
 
 type unresolvedSymKey struct {
index 0c5ac470438adbdbbd0fe4135fc9d73183f2aad1..905380a1dbfda2d17450f09c9ca7fcfc7e53d12b 100644 (file)
@@ -208,6 +208,7 @@ func Main(arch *sys.Arch, theArch Arch) {
 
        ctxt.dostrdata()
        deadcode(ctxt)
+       dwarfGenerateDebugInfo(ctxt)
        if objabi.Fieldtrack_enabled != 0 {
                fieldtrack(ctxt)
        }
index 67868be2a192611e1161f77311b766c380cd563e..e3800de30413b3e42d4e676c64475f5a99f93523 100644 (file)
@@ -318,6 +318,8 @@ overwrite:
                        pc.InlTree[i].Func = r.readSymIndex()
                }
 
+               s.FuncInfo.IsStmtSym = r.syms.Lookup(dwarf.IsStmtPrefix+s.Name, int(s.Version))
+
                s.Lib = r.lib
                if !dupok {
                        if s.Attr.OnList() {
index 95ad8654b5cef1d39a6a51720af08a4147747358..a6c2aaea778f573bed21961618b2eb5b49880a2b 100644 (file)
@@ -478,6 +478,7 @@ type FuncInfo struct {
        Pcline      Pcdata
        Pcinline    Pcdata
        Pcdata      []Pcdata
+       IsStmtSym   *Symbol
        Funcdata    []*Symbol
        Funcdataoff []int64
        File        []*Symbol