From: Than McIntosh Date: Tue, 24 Oct 2017 20:08:46 +0000 (-0400) Subject: cmd/compile, cmd/link: support for DWARF file reference relocations X-Git-Tag: go1.10beta1~565 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=b52b77cb953430b76242724394bb66e79fda9f10;p=gostls13.git cmd/compile, cmd/link: support for DWARF file reference relocations 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 TryBot-Result: Gobot Gobot Reviewed-by: Austin Clements --- diff --git a/src/cmd/internal/dwarf/dwarf.go b/src/cmd/internal/dwarf/dwarf.go index aab8000792..8f7049df09 100644 --- a/src/cmd/internal/dwarf/dwarf.go +++ b/src/cmd/internal/dwarf/dwarf.go @@ -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 diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index 04178bd479..7098d203dd 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -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) } diff --git a/src/cmd/internal/objabi/reloctype.go b/src/cmd/internal/objabi/reloctype.go index 179f049de7..82e3161cf4 100644 --- a/src/cmd/internal/objabi/reloctype.go +++ b/src/cmd/internal/objabi/reloctype.go @@ -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 diff --git a/src/cmd/internal/objabi/reloctype_string.go b/src/cmd/internal/objabi/reloctype_string.go index 182d03f78c..792d631486 100644 --- a/src/cmd/internal/objabi/reloctype_string.go +++ b/src/cmd/internal/objabi/reloctype_string.go @@ -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 diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go index 4f426d7bb6..aad3c53cb6 100644 --- a/src/cmd/link/internal/amd64/asm.go +++ b/src/cmd/link/internal/amd64/asm.go @@ -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: diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 459a75e8ac..92ca33972a 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -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 diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index df19e82760..f92169b30f 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -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 diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go index 00ee8a0565..06e3fd6fa1 100644 --- a/src/cmd/link/internal/ld/dwarf_test.go +++ b/src/cmd/link/internal/ld/dwarf_test.go @@ -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) + } } diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go index 56d502c2dd..c76c2a5d0e 100644 --- a/src/cmd/link/internal/x86/asm.go +++ b/src/cmd/link/internal/x86/asm.go @@ -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: