]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile, cmd/link: support for DWARF file reference relocations
authorThan McIntosh <thanm@google.com>
Tue, 24 Oct 2017 20:08:46 +0000 (16:08 -0400)
committerThan McIntosh <thanm@google.com>
Fri, 27 Oct 2017 17:53:52 +0000 (17:53 +0000)
New relocation flavor R_DWARFFILEREF, to be applied to DWARF attribute
values that correspond to file references (ex: DW_AT_decl_file,
DW_AT_call_file). The LSym for this relocation is the file itself; the
linker replaces the relocation target with the index of the specified
file in the line table's file section.

Note: for testing purposes this patch changes the DWARF function
subprogram DIE abbrev to include DW_AT_decl_file (allowed by DWARF
but not especially useful) so as to have a way to test this
functionality. This attribute will be removed once there are other
file reference attributes (coming as part of inlining support).

Change-Id: Icf676beb60fcc33f06d78e747ef717532daaa3ba
Reviewed-on: https://go-review.googlesource.com/73330
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
src/cmd/internal/dwarf/dwarf.go
src/cmd/internal/obj/objfile.go
src/cmd/internal/objabi/reloctype.go
src/cmd/internal/objabi/reloctype_string.go
src/cmd/link/internal/amd64/asm.go
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/dwarf.go
src/cmd/link/internal/ld/dwarf_test.go
src/cmd/link/internal/x86/asm.go

index aab8000792c67bd1450d2e79491057d4ae353fce..8f7049df09f5334a85ed1133183ca1674841f727 100644 (file)
@@ -123,6 +123,7 @@ type Context interface {
        AddAddress(s Sym, t interface{}, ofs int64)
        AddSectionOffset(s Sym, size int, t interface{}, ofs int64)
        AddString(s Sym, v string)
+       AddFileRef(s Sym, f interface{})
 }
 
 // AppendUleb128 appends v to b using DWARF's unsigned LEB128 encoding.
@@ -303,6 +304,7 @@ var abbrevs = [DW_NABRV]dwAbbrev{
                        {DW_AT_low_pc, DW_FORM_addr},
                        {DW_AT_high_pc, DW_FORM_addr},
                        {DW_AT_frame_base, DW_FORM_block1},
+                       {DW_AT_decl_file, DW_FORM_data4},
                        {DW_AT_external, DW_FORM_flag},
                },
        },
@@ -788,12 +790,14 @@ func PutRanges(ctxt Context, sym Sym, base Sym, ranges []Range) {
 
 // PutFunc writes a DIE for a function to s.
 // It also writes child DIEs for each variable in vars.
-func PutFunc(ctxt Context, info, loc, ranges Sym, name string, external bool, startPC Sym, size int64, scopes []Scope) error {
+func PutFunc(ctxt Context, info, loc, ranges, filesym Sym, name string, external bool, startPC Sym, size int64, scopes []Scope) error {
        Uleb128put(ctxt, info, DW_ABRV_FUNCTION)
        putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
        putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, 0, startPC)
        putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, size, startPC)
        putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
+       // DW_AT_decl_file attribute
+       ctxt.AddFileRef(info, filesym)
        var ev int64
        if external {
                ev = 1
index 04178bd479366dffbf338afaa3d5778426bbe48e..7098d203dd3c4a63bd630b4729bf53a036c7d3df 100644 (file)
@@ -458,7 +458,14 @@ func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64
        rsym := t.(*LSym)
        ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
        r := &ls.R[len(ls.R)-1]
-       r.Type = objabi.R_DWARFREF
+       r.Type = objabi.R_DWARFSECREF
+}
+func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) {
+       ls := s.(*LSym)
+       rsym := f.(*LSym)
+       ls.WriteAddr(c.Link, ls.Size, 4, rsym, 0)
+       r := &ls.R[len(ls.R)-1]
+       r.Type = objabi.R_DWARFFILEREF
 }
 
 // dwarfSym returns the DWARF symbols for TEXT symbol.
@@ -480,6 +487,19 @@ func (s *LSym) Len() int64 {
        return s.Size
 }
 
+// fileSymbol returns a symbol corresponding to the source file of the
+// first instruction (prog) of the specified function. This will
+// presumably be the file in which the function is defined.
+func (ctxt *Link) fileSymbol(fn *LSym) *LSym {
+       p := fn.Func.Text
+       if p != nil {
+               f, _ := linkgetlineFromPos(ctxt, p.Pos)
+               fsym := ctxt.Lookup(f)
+               return fsym
+       }
+       return nil
+}
+
 // populateDWARF fills in the DWARF Debugging Information Entries for TEXT symbol s.
 // The DWARFs symbol must already have been initialized in InitTextSym.
 func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym) {
@@ -491,7 +511,9 @@ func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym) {
        if ctxt.DebugInfo != nil {
                scopes = ctxt.DebugInfo(s, curfn)
        }
-       err := dwarf.PutFunc(dwCtxt{ctxt}, info, loc, ranges, s.Name, !s.Static(), s, s.Size, scopes)
+
+       fs := ctxt.fileSymbol(s)
+       err := dwarf.PutFunc(dwCtxt{ctxt}, info, loc, ranges, fs, s.Name, !s.Static(), s, s.Size, scopes)
        if err != nil {
                ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
        }
index 179f049de7d6ffa0c25432d2e4cadc059091e400..82e3161cf4aa895ddbb8556dc981df11342a91ca 100644 (file)
@@ -99,8 +99,15 @@ const (
        // of a JMP instruction, by encoding the address into the instruction.
        // The stack nosplit check ignores this since it is not a function call.
        R_JMPMIPS
-       // R_DWARFREF resolves to the offset of the symbol from its section.
-       R_DWARFREF
+
+       // R_DWARFSECREF resolves to the offset of the symbol from its section.
+       // Target of relocation must be size 4 (in current implementation).
+       R_DWARFSECREF
+
+       // R_DWARFFILEREF resolves to an index into the DWARF .debug_line
+       // file table for the specified file symbol. Must be applied to an
+       // attribute of form DW_FORM_data4.
+       R_DWARFFILEREF
 
        // Platform dependent relocations. Architectures with fixed width instructions
        // have the inherent issue that a 32-bit (or 64-bit!) displacement cannot be
index 182d03f78c1260233e8f660feb25535709f169c7..792d6314860664bcade81f988d80730d1d006f95 100644 (file)
@@ -4,9 +4,9 @@ package objabi
 
 import "fmt"
 
-const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLS"
+const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLS"
 
-var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 129, 136, 144, 152, 160, 166, 172, 178, 188, 197, 208, 219, 229, 238, 248, 262, 276, 292, 306, 320, 331, 345, 360, 377, 395, 416, 426, 437, 450}
+var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 129, 136, 144, 152, 160, 166, 172, 178, 188, 197, 208, 219, 229, 238, 251, 265, 279, 293, 309, 323, 337, 348, 362, 377, 394, 412, 433, 443, 454, 467}
 
 func (i RelocType) String() string {
        i -= 1
index 4f426d7bb6f473a36dd56c86e7c4284b2a47ef48..aad3c53cb619dc1bc87c0a919e4336b0f2584d4a 100644 (file)
@@ -507,7 +507,7 @@ func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, secto
        default:
                return false
 
-       case objabi.R_DWARFREF:
+       case objabi.R_DWARFSECREF:
                v = ld.IMAGE_REL_AMD64_SECREL
 
        case objabi.R_ADDR:
index 459a75e8acb116a58e377905601843bf99dafc4c..92ca33972aad45b792b2aaeb38763af90861c3ca 100644 (file)
@@ -110,6 +110,10 @@ func trampoline(ctxt *Link, s *sym.Symbol) {
 func relocsym(ctxt *Link, s *sym.Symbol) {
        for ri := int32(0); ri < int32(len(s.R)); ri++ {
                r := &s.R[ri]
+               if r.Done {
+                       // Relocation already processed by an earlier phase.
+                       continue
+               }
                r.Done = true
                off := r.Off
                siz := int32(r.Siz)
@@ -145,6 +149,12 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
                if r.Siz == 0 { // informational relocation - no work to do
                        continue
                }
+               if r.Type == objabi.R_DWARFFILEREF {
+                       // These should have been processed previously during
+                       // line table writing.
+                       Errorf(s, "orphan R_DWARFFILEREF reloc to %v", r.Sym.Name)
+                       continue
+               }
 
                // We need to be able to reference dynimport symbols when linking against
                // shared libraries, and Solaris needs it always
@@ -306,7 +316,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
                                Errorf(s, "non-pc-relative relocation address for %s is too big: %#x (%#x + %#x)", r.Sym.Name, uint64(o), Symaddr(r.Sym), r.Add)
                                errorexit()
                        }
-               case objabi.R_DWARFREF:
+               case objabi.R_DWARFSECREF:
                        if r.Sym.Sect == nil {
                                Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name)
                        }
@@ -324,9 +334,9 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
                                }
 
                                // PE code emits IMAGE_REL_I386_SECREL and IMAGE_REL_AMD64_SECREL
-                               // for R_DWARFREF relocations, while R_ADDR is replaced with
+                               // for R_DWARFSECREF relocations, while R_ADDR is replaced with
                                // IMAGE_REL_I386_DIR32, IMAGE_REL_AMD64_ADDR64 and IMAGE_REL_AMD64_ADDR32.
-                               // Do not replace R_DWARFREF with R_ADDR for windows -
+                               // Do not replace R_DWARFSECREF with R_ADDR for windows -
                                // let PE code emit correct relocations.
                                if ctxt.HeadType != objabi.Hwindows {
                                        r.Type = objabi.R_ADDR
index df19e8276059262f5d2cb15ac7b087140f561350..f92169b30f1c691c6e273833d7bf449808174148 100644 (file)
@@ -62,10 +62,14 @@ func (c dwctxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64
                ls.AddAddrPlus4(t.(*sym.Symbol), 0)
        }
        r := &ls.R[len(ls.R)-1]
-       r.Type = objabi.R_DWARFREF
+       r.Type = objabi.R_DWARFSECREF
        r.Add = ofs
 }
 
+func (c dwctxt) AddFileRef(s dwarf.Sym, f interface{}) {
+       panic("should be used only in the compiler")
+}
+
 var gdbscript string
 
 var dwarfp []*sym.Symbol
@@ -220,7 +224,7 @@ func adddwarfref(ctxt *Link, s *sym.Symbol, t *sym.Symbol, size int) int64 {
                result = s.AddAddrPlus4(t, 0)
        }
        r := &s.R[len(s.R)-1]
-       r.Type = objabi.R_DWARFREF
+       r.Type = objabi.R_DWARFSECREF
        return result
 }
 
@@ -1030,7 +1034,7 @@ func importInfoSymbol(ctxt *Link, dsym *sym.Symbol) {
        dsym.Attr |= sym.AttrNotInSymbolTable | sym.AttrReachable
        dsym.Type = sym.SDWARFINFO
        for _, r := range dsym.R {
-               if r.Type == objabi.R_DWARFREF && 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
@@ -1184,6 +1188,40 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo
        ls.SetUint32(ctxt.Arch, unitLengthOffset, uint32(ls.Size-unitstart))
        ls.SetUint32(ctxt.Arch, headerLengthOffset, uint32(headerend-headerstart))
 
+       // Apply any R_DWARFFILEREF relocations, since we now know the
+       // line table file indices for this compilation unit. Note that
+       // this loop visits only subprogram DIEs: if the compiler is
+       // changed to generate DW_AT_decl_file attributes for other
+       // DIE flavors (ex: variables) then those DIEs would need to
+       // be included below.
+       for fidx := 0; fidx < len(funcs); fidx++ {
+               f := funcs[fidx]
+               for ri := 0; ri < len(f.R); ri++ {
+                       r := &f.R[ri]
+                       if r.Type != objabi.R_DWARFFILEREF {
+                               continue
+                       }
+                       // Mark relocation as applied (signal to relocsym)
+                       r.Done = true
+                       idx, ok := fileNums[int(r.Sym.Value)]
+                       if ok {
+                               if int(int32(idx)) != idx {
+                                       Errorf(f, "bad R_DWARFFILEREF relocation: file index overflow")
+                               }
+                               if r.Siz != 4 {
+                                       Errorf(f, "bad R_DWARFFILEREF relocation: has size %d, expected 4", r.Siz)
+                               }
+                               if r.Off < 0 || r.Off+4 > int32(len(f.P)) {
+                                       Errorf(f, "bad R_DWARFFILEREF relocation offset %d + 4 would write past length %d", r.Off, len(s.P))
+                                       continue
+                               }
+                               ctxt.Arch.ByteOrder.PutUint32(f.P[r.Off:r.Off+4], uint32(idx))
+                       } else {
+                               Errorf(f, "R_DWARFFILEREF relocation file missing: %v", r.Sym)
+                       }
+               }
+       }
+
        return dwinfo, funcs
 }
 
@@ -1617,7 +1655,7 @@ func collectlocs(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit) []*sy
        for _, u := range units {
                for _, fn := range u.funcDIEs {
                        for _, reloc := range fn.R {
-                               if reloc.Type == objabi.R_DWARFREF && strings.HasPrefix(reloc.Sym.Name, dwarf.LocPrefix) {
+                               if reloc.Type == objabi.R_DWARFSECREF && strings.HasPrefix(reloc.Sym.Name, dwarf.LocPrefix) {
                                        reloc.Sym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable
                                        syms = append(syms, reloc.Sym)
                                        empty = false
index 00ee8a05652a866ded8ce5fce79deb81a6e4c386..06e3fd6fa1eb89b70aa66fb4cb557973d2d3982d 100644 (file)
@@ -299,7 +299,7 @@ func main() {
        }
 }
 
-func TestVarDeclCoords(t *testing.T) {
+func TestVarDeclCoordsAndSubrogramDeclFile(t *testing.T) {
        testenv.MustHaveGoBuild(t)
 
        if runtime.GOOS == "plan9" {
@@ -329,6 +329,7 @@ func main() {
 
        rdr := d.Reader()
        var iEntry *dwarf.Entry
+       var pEntry *dwarf.Entry
        foundMain := false
        for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
                if err != nil {
@@ -336,6 +337,7 @@ func main() {
                }
                if entry.Tag == dwarf.TagSubprogram && entry.Val(dwarf.AttrName).(string) == "main.main" {
                        foundMain = true
+                       pEntry = entry
                        continue
                }
                if !foundMain {
@@ -354,4 +356,9 @@ func main() {
        if line == nil || line.(int64) != 5 {
                t.Errorf("DW_AT_decl_line for i is %v, want 5", line)
        }
+
+       file := pEntry.Val(dwarf.AttrDeclFile)
+       if file == nil || file.(int64) != 1 {
+               t.Errorf("DW_AT_decl_file for main is %v, want 1", file)
+       }
 }
index 56d502c2dd1c3e5c93056e2775cb3f8658912cb5..c76c2a5d0ef00539b5953eeacea562f8e5f1bd8e 100644 (file)
@@ -471,7 +471,7 @@ func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, secto
        default:
                return false
 
-       case objabi.R_DWARFREF:
+       case objabi.R_DWARFSECREF:
                v = ld.IMAGE_REL_I386_SECREL
 
        case objabi.R_ADDR: