From: Than McIntosh Date: Tue, 10 Mar 2020 14:36:20 +0000 (-0400) Subject: [dev.link] cmd/link: remove legacy DWARF gen code X-Git-Tag: go1.15beta1~679^2~86 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=cdc1b195139ecb8d1cfed028cf5b50f11d591f2e;p=gostls13.git [dev.link] cmd/link: remove legacy DWARF gen code Remove the temporary "-newdw2" linker command line option, along with the remainder of the legacy sym.Symbol based DWARF generation code. Change-Id: I86c0581dd021cd4e2209ca9bc45f34037d42323c Reviewed-on: https://go-review.googlesource.com/c/go/+/222766 Run-TryBot: Than McIntosh TryBot-Result: Gobot Gobot Reviewed-by: Cherry Zhang --- diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 5e89b3897e..6d387def98 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -2064,93 +2064,10 @@ func dwarfGenerateDebugInfo(ctxt *Link) { // every DIE constructed and convert the symbols. } -// dwarfConvertSymbols is invoked around the time that loader.LoadFull -// runs (converting all loader.Sym's into sym.Symbols); it walks -// through dwarf DIE objects and rewrites loader.Sym refs to -// sym.Symbol there as well. This is obviously a temporary function. -func dwarfConvertSymbols(ctxt *Link) { - if !dwarfEnabled(ctxt) { - return - } - if *FlagNewDw2 { - // don't convert since we're running phase 2 with loader - return - } - convdies := make(map[*dwarf.DWDie]bool) - for _, lib := range ctxt.Library { - for _, unit := range lib.Units { - convertSymbolsInDIE(ctxt, unit.DWInfo, convdies) - } - } - convertSymbolsInDIE(ctxt, &dwtypes, convdies) - - // Convert over the unit function DIE and abstract function DIE lists. - for _, lib := range ctxt.Library { - for _, unit := range lib.Units { - for _, fd := range unit.FuncDIEs2 { - ds := ctxt.loader.Syms[fd] - if ds == nil { - panic("bad") - } - unit.FuncDIEs = append(unit.FuncDIEs, ds) - } - for _, fd := range unit.RangeSyms2 { - ds := ctxt.loader.Syms[fd] - if ds == nil { - panic("bad") - } - unit.RangeSyms = append(unit.RangeSyms, ds) - } - for _, fd := range unit.AbsFnDIEs2 { - ds := ctxt.loader.Syms[fd] - if ds == nil { - panic("bad") - } - unit.AbsFnDIEs = append(unit.AbsFnDIEs, ds) - } - if unit.Consts2 != 0 { - ds := ctxt.loader.Syms[unit.Consts2] - if ds == nil { - panic("bad") - } - unit.Consts = ds - } - } - } -} - -func convertSymbolsInDIE(ctxt *Link, die *dwarf.DWDie, convdies map[*dwarf.DWDie]bool) { - if die == nil { - return - } - if convdies[die] { - return - } - convdies[die] = true - if die.Sym != nil { - ds, ok := die.Sym.(dwSym) - if !ok { - panic("bad die sym field") - } - symIdx := loader.Sym(ds) - if symIdx == 0 { - panic("zero loader sym for die") - } - die.Sym = ctxt.loader.Syms[symIdx] - } - for a := die.Attr; a != nil; a = a.Link { - if attrSym, ok := a.Data.(dwSym); ok { - a.Data = ctxt.loader.Syms[loader.Sym(attrSym)] - } - } - convertSymbolsInDIE(ctxt, die.Child, convdies) - convertSymbolsInDIE(ctxt, die.Link, convdies) -} - // 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 dwarfGenerateDebugInfo2. -func dwarfGenerateDebugSyms2(ctxt *Link) { +func dwarfGenerateDebugSyms(ctxt *Link) { if !dwarfEnabled(ctxt) { return } @@ -2295,3 +2212,23 @@ func (d *dwctxt2) dwarfcompress(ctxt *Link) { func (d *dwctxt2) getPkgFromCUSym(s loader.Sym) string { return strings.TrimPrefix(d.ldr.SymName(s), dwarf.InfoPrefix+".pkg.") } + +// On AIX, the symbol table needs to know where are the compilation units parts +// for a specific package in each .dw section. +// dwsectCUSize map will save the size of a compilation unit for +// the corresponding .dw section. +// This size can later be retrieved with the index "sectionName.pkgName". +var dwsectCUSize map[string]uint64 + +// getDwsectCUSize retrieves the corresponding package size inside the current section. +func getDwsectCUSize(sname string, pkgname string) uint64 { + return dwsectCUSize[sname+"."+pkgname] +} + +func saveDwsectCUSize(sname string, pkgname string, size uint64) { + dwsectCUSize[sname+"."+pkgname] = size +} + +func addDwsectCUSize(sname string, pkgname string, size uint64) { + dwsectCUSize[sname+"."+pkgname] += size +} diff --git a/src/cmd/link/internal/ld/dwarf2.go b/src/cmd/link/internal/ld/dwarf2.go index cc344d8680..1dce5d7195 100644 --- a/src/cmd/link/internal/ld/dwarf2.go +++ b/src/cmd/link/internal/ld/dwarf2.go @@ -15,111 +15,18 @@ package ld import ( "cmd/internal/dwarf" - "cmd/internal/obj" "cmd/internal/objabi" - "cmd/internal/src" "cmd/link/internal/sym" "fmt" "log" - "sort" - "strings" ) -type dwctxt struct { - linkctxt *Link -} - -func (c dwctxt) PtrSize() int { - return c.linkctxt.Arch.PtrSize -} -func (c dwctxt) AddInt(s dwarf.Sym, size int, i int64) { - ls := s.(*sym.Symbol) - ls.AddUintXX(c.linkctxt.Arch, uint64(i), size) -} -func (c dwctxt) AddBytes(s dwarf.Sym, b []byte) { - ls := s.(*sym.Symbol) - ls.AddBytes(b) -} -func (c dwctxt) AddString(s dwarf.Sym, v string) { - Addstring(s.(*sym.Symbol), v) -} - -func (c dwctxt) AddAddress(s dwarf.Sym, data interface{}, value int64) { - if value != 0 { - value -= (data.(*sym.Symbol)).Value - } - s.(*sym.Symbol).AddAddrPlus(c.linkctxt.Arch, data.(*sym.Symbol), value) -} - -func (c dwctxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) { - if value != 0 { - value -= (data.(*sym.Symbol)).Value - } - s.(*sym.Symbol).AddCURelativeAddrPlus(c.linkctxt.Arch, data.(*sym.Symbol), value) -} - -func (c dwctxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) { - ls := s.(*sym.Symbol) - switch size { - default: - Errorf(ls, "invalid size %d in adddwarfref\n", size) - fallthrough - case c.linkctxt.Arch.PtrSize: - ls.AddAddr(c.linkctxt.Arch, t.(*sym.Symbol)) - case 4: - ls.AddAddrPlus4(t.(*sym.Symbol), 0) - } - r := &ls.R[len(ls.R)-1] - r.Type = objabi.R_ADDROFF - r.Add = ofs -} - -func (c dwctxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) { - size := 4 - if isDwarf64(c.linkctxt) { - size = 8 - } - - c.AddSectionOffset(s, size, t, ofs) - ls := s.(*sym.Symbol) - ls.R[len(ls.R)-1].Type = objabi.R_DWARFSECREF -} - -func (c dwctxt) Logf(format string, args ...interface{}) { - c.linkctxt.Logf(format, args...) -} - -// At the moment these interfaces are only used in the compiler. - -func (c dwctxt) AddFileRef(s dwarf.Sym, f interface{}) { - panic("should be used only in the compiler") -} - -func (c dwctxt) CurrentOffset(s dwarf.Sym) int64 { - panic("should be used only in the compiler") -} - -func (c dwctxt) RecordDclReference(s dwarf.Sym, t dwarf.Sym, dclIdx int, inlIndex int) { - panic("should be used only in the compiler") -} - -func (c dwctxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) { - panic("should be used only in the compiler") -} - func isDwarf64(ctxt *Link) bool { return ctxt.HeadType == objabi.Haix } var dwarfp []*sym.Symbol -func writeabbrev(ctxt *Link) *sym.Symbol { - s := ctxt.Syms.Lookup(".debug_abbrev", 0) - s.Type = sym.SDWARFSECT - s.AddBytes(dwarf.GetAbbrev()) - return s -} - // Every DIE manufactured by the linker has at least an AT_name // attribute (but it will only be written out if it is listed in the abbrev). // The compiler does create nameless DWARF DIEs (ex: concrete subprogram @@ -148,742 +55,6 @@ func newdie(ctxt *Link, parent *dwarf.DWDie, abbrev int, name string, version in return die } -func adddwarfref(ctxt *Link, s *sym.Symbol, t *sym.Symbol, size int) int64 { - var result int64 - switch size { - default: - Errorf(s, "invalid size %d in adddwarfref\n", size) - fallthrough - case ctxt.Arch.PtrSize: - result = s.AddAddr(ctxt.Arch, t) - case 4: - result = s.AddAddrPlus4(t, 0) - } - r := &s.R[len(s.R)-1] - r.Type = objabi.R_DWARFSECREF - return result -} - -func newrefattr(die *dwarf.DWDie, attr uint16, ref *sym.Symbol) *dwarf.DWAttr { - if ref == nil { - return nil - } - return newattr(die, attr, dwarf.DW_CLS_REFERENCE, 0, ref) -} - -func dtolsym(s dwarf.Sym) *sym.Symbol { - if s == nil { - return nil - } - return s.(*sym.Symbol) -} - -func putdie(linkctxt *Link, ctxt dwarf.Context, syms []*sym.Symbol, die *dwarf.DWDie) []*sym.Symbol { - s := dtolsym(die.Sym) - if s == nil { - s = syms[len(syms)-1] - } else { - if s.Attr.OnList() { - log.Fatalf("symbol %s listed multiple times", s.Name) - } - s.Attr |= sym.AttrOnList - syms = append(syms, s) - } - dwarf.Uleb128put(ctxt, s, int64(die.Abbrev)) - dwarf.PutAttrs(ctxt, s, die.Abbrev, die.Attr) - if dwarf.HasChildren(die) { - for die := die.Child; die != nil; die = die.Link { - syms = putdie(linkctxt, ctxt, syms, die) - } - syms[len(syms)-1].AddUint8(0) - } - return syms -} - -// dwarfFuncSym looks up a DWARF metadata symbol for function symbol s. -// If the symbol does not exist, it creates it if create is true, -// or returns nil otherwise. -func dwarfFuncSym(ctxt *Link, s *sym.Symbol, meta string, create bool) *sym.Symbol { - // All function ABIs use symbol version 0 for the DWARF data. - // - // TODO(austin): It may be useful to have DWARF info for ABI - // wrappers, in which case we may want these versions to - // align. Better yet, replace these name lookups with a - // general way to attach metadata to a symbol. - ver := 0 - if s.IsFileLocal() { - ver = int(s.Version) - } - if create { - return ctxt.Syms.Lookup(meta+s.Name, ver) - } - return ctxt.Syms.ROLookup(meta+s.Name, ver) -} - -// createUnitLength creates the initial length field with value v and update -// offset of unit_length if needed. -func createUnitLength(ctxt *Link, s *sym.Symbol, v uint64) { - if isDwarf64(ctxt) { - s.AddUint32(ctxt.Arch, 0xFFFFFFFF) - } - addDwarfAddrField(ctxt, s, v) -} - -// addDwarfAddrField adds a DWARF field in DWARF 64bits or 32bits. -func addDwarfAddrField(ctxt *Link, s *sym.Symbol, v uint64) { - if isDwarf64(ctxt) { - s.AddUint(ctxt.Arch, v) - } else { - s.AddUint32(ctxt.Arch, uint32(v)) - } -} - -// addDwarfAddrRef adds a DWARF pointer in DWARF 64bits or 32bits. -func addDwarfAddrRef(ctxt *Link, s *sym.Symbol, t *sym.Symbol) { - if isDwarf64(ctxt) { - adddwarfref(ctxt, s, t, 8) - } else { - adddwarfref(ctxt, s, t, 4) - } -} - -// calcCompUnitRanges calculates the PC ranges of the compilation units. -func calcCompUnitRanges(ctxt *Link) { - var prevUnit *sym.CompilationUnit - for _, s := range ctxt.Textp { - if s.FuncInfo == nil { - continue - } - // Skip linker-created functions (ex: runtime.addmoduledata), since they - // don't have DWARF to begin with. - if s.Unit == nil { - continue - } - unit := s.Unit - // Update PC ranges. - // - // We don't simply compare the end of the previous - // symbol with the start of the next because there's - // often a little padding between them. Instead, we - // only create boundaries between symbols from - // different units. - if prevUnit != unit { - unit.PCs = append(unit.PCs, dwarf.Range{Start: s.Value - unit.Textp[0].Value}) - prevUnit = unit - } - unit.PCs[len(unit.PCs)-1].End = s.Value - unit.Textp[0].Value + s.Size - } -} - -// If the pcln table contains runtime/proc.go, use that to set gdbscript path. -func finddebugruntimepath(s *sym.Symbol) { - if gdbscript != "" { - return - } - - for i := range s.FuncInfo.File { - f := s.FuncInfo.File[i] - // We can't use something that may be dead-code - // eliminated from a binary here. proc.go contains - // main and the scheduler, so it's not going anywhere. - if i := strings.Index(f.Name, "runtime/proc.go"); i >= 0 { - gdbscript = f.Name[:i] + "runtime/runtime-gdb.py" - break - } - } -} - -func writelines(ctxt *Link, unit *sym.CompilationUnit, ls *sym.Symbol) { - - var dwarfctxt dwarf.Context = dwctxt{ctxt} - is_stmt := uint8(1) // initially = recommended default_is_stmt = 1, tracks is_stmt toggles. - - unitstart := int64(-1) - headerstart := int64(-1) - headerend := int64(-1) - - 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 - unitLengthOffset := ls.Size - createUnitLength(ctxt, ls, 0) // unit_length (*), filled in at end - unitstart = ls.Size - ls.AddUint16(ctxt.Arch, 2) // dwarf version (appendix F) -- version 3 is incompatible w/ XCode 9.0's dsymutil, latest supported on OSX 10.12 as of 2018-05 - headerLengthOffset := ls.Size - addDwarfAddrField(ctxt, ls, 0) // header_length (*), filled in at end - headerstart = ls.Size - - // cpos == unitstart + 4 + 2 + 4 - ls.AddUint8(1) // minimum_instruction_length - ls.AddUint8(is_stmt) // default_is_stmt - ls.AddUint8(LINE_BASE & 0xFF) // line_base - ls.AddUint8(LINE_RANGE) // line_range - ls.AddUint8(OPCODE_BASE) // opcode_base - ls.AddUint8(0) // standard_opcode_lengths[1] - ls.AddUint8(1) // standard_opcode_lengths[2] - ls.AddUint8(1) // standard_opcode_lengths[3] - ls.AddUint8(1) // standard_opcode_lengths[4] - ls.AddUint8(1) // standard_opcode_lengths[5] - ls.AddUint8(0) // standard_opcode_lengths[6] - ls.AddUint8(0) // standard_opcode_lengths[7] - ls.AddUint8(0) // standard_opcode_lengths[8] - ls.AddUint8(1) // standard_opcode_lengths[9] - ls.AddUint8(0) // standard_opcode_lengths[10] - ls.AddUint8(0) // include_directories (empty) - - // Copy over the file table. - fileNums := make(map[string]int) - for i, name := range unit.DWARFFileTable { - if len(name) != 0 { - if strings.HasPrefix(name, src.FileSymPrefix) { - name = name[len(src.FileSymPrefix):] - } - name = expandGoroot(name) - } else { - // Can't have empty filenames, and having a unique filename is quite useful - // for debugging. - name = fmt.Sprintf("_%d", i) - } - fileNums[name] = i + 1 - dwarfctxt.AddString(ls, name) - ls.AddUint8(0) - ls.AddUint8(0) - ls.AddUint8(0) - } - // Grab files for inlined functions. - // TODO: With difficulty, this could be moved into the compiler. - for _, s := range unit.Textp { - dsym := dwarfFuncSym(ctxt, s, dwarf.InfoPrefix, true) - for ri := 0; ri < len(dsym.R); ri++ { - r := &dsym.R[ri] - if r.Type != objabi.R_DWARFFILEREF { - continue - } - name := r.Sym.Name - if _, ok := fileNums[name]; ok { - continue - } - fileNums[name] = len(fileNums) + 1 - dwarfctxt.AddString(ls, name) - ls.AddUint8(0) - ls.AddUint8(0) - ls.AddUint8(0) - } - } - - // 4 zeros: the string termination + 3 fields. - ls.AddUint8(0) - // terminate file_names. - headerend = ls.Size - - // Output the state machine for each function remaining. - var lastAddr int64 - for _, s := range unit.Textp { - finddebugruntimepath(s) - - // Set the PC. - ls.AddUint8(0) - dwarf.Uleb128put(dwarfctxt, ls, 1+int64(ctxt.Arch.PtrSize)) - ls.AddUint8(dwarf.DW_LNE_set_address) - addr := ls.AddAddr(ctxt.Arch, s) - // Make sure the units are sorted. - if addr < lastAddr { - Errorf(s, "address wasn't increasing %x < %x", addr, lastAddr) - } - lastAddr = addr - - // Output the line table. - // TODO: Now that we have all the debug information in separate - // symbols, it would make sense to use a rope, and concatenate them all - // together rather then the append() below. This would allow us to have - // the compiler emit the DW_LNE_set_address and a rope data structure - // to concat them all together in the output. - lines := dwarfFuncSym(ctxt, s, dwarf.DebugLinesPrefix, false) - if lines != nil { - ls.P = append(ls.P, lines.P...) - } - } - - ls.AddUint8(0) // start extended opcode - dwarf.Uleb128put(dwarfctxt, ls, 1) - ls.AddUint8(dwarf.DW_LNE_end_sequence) - - if ctxt.HeadType == objabi.Haix { - saveDwsectCUSize(".debug_line", unit.Lib.Pkg, uint64(ls.Size-unitLengthOffset)) - } - if isDwarf64(ctxt) { - ls.SetUint(ctxt.Arch, unitLengthOffset+4, uint64(ls.Size-unitstart)) // +4 because of 0xFFFFFFFF - ls.SetUint(ctxt.Arch, headerLengthOffset, uint64(headerend-headerstart)) - } else { - ls.SetUint32(ctxt.Arch, unitLengthOffset, uint32(ls.Size-unitstart)) - ls.SetUint32(ctxt.Arch, headerLengthOffset, uint32(headerend-headerstart)) - } - - // Process 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. - missing := make(map[int]interface{}) - s := unit.Textp[0] - for _, f := range unit.FuncDIEs { - for ri := range f.R { - r := &f.R[ri] - if r.Type != objabi.R_DWARFFILEREF { - continue - } - idx, ok := fileNums[r.Sym.Name] - 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 - } - if r.Add != 0 { - Errorf(f, "bad R_DWARFFILEREF relocation: addend not zero") - } - r.Sym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable - r.Add = int64(idx) // record the index in r.Add, we'll apply it in the reloc phase. - } else { - _, found := missing[int(r.Sym.Value)] - if !found { - Errorf(f, "R_DWARFFILEREF relocation file missing: %v idx %d", r.Sym, r.Sym.Value) - missing[int(r.Sym.Value)] = nil - } - } - } - } -} - -// writepcranges generates the DW_AT_ranges table for compilation unit cu. -func writepcranges(ctxt *Link, unit *sym.CompilationUnit, base *sym.Symbol, pcs []dwarf.Range, ranges *sym.Symbol) { - var dwarfctxt dwarf.Context = dwctxt{ctxt} - - unitLengthOffset := ranges.Size - - // Create PC ranges for this CU. - newattr(unit.DWInfo, dwarf.DW_AT_ranges, dwarf.DW_CLS_PTR, ranges.Size, ranges) - newattr(unit.DWInfo, dwarf.DW_AT_low_pc, dwarf.DW_CLS_ADDRESS, base.Value, base) - dwarf.PutBasedRanges(dwarfctxt, ranges, pcs) - - if ctxt.HeadType == objabi.Haix { - addDwsectCUSize(".debug_ranges", unit.Lib.Pkg, uint64(ranges.Size-unitLengthOffset)) - } - -} - -func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol { - var dwarfctxt dwarf.Context = dwctxt{ctxt} - fs := ctxt.Syms.Lookup(".debug_frame", 0) - fs.Type = sym.SDWARFSECT - syms = append(syms, fs) - - // Length field is 4 bytes on Dwarf32 and 12 bytes on Dwarf64 - lengthFieldSize := int64(4) - if isDwarf64(ctxt) { - lengthFieldSize += 8 - } - - // Emit the CIE, Section 6.4.1 - cieReserve := uint32(16) - if haslinkregister(ctxt) { - cieReserve = 32 - } - if isDwarf64(ctxt) { - cieReserve += 4 // 4 bytes added for cid - } - createUnitLength(ctxt, fs, uint64(cieReserve)) // initial length, must be multiple of thearch.ptrsize - addDwarfAddrField(ctxt, fs, ^uint64(0)) // cid - fs.AddUint8(3) // dwarf version (appendix F) - fs.AddUint8(0) // augmentation "" - dwarf.Uleb128put(dwarfctxt, fs, 1) // code_alignment_factor - dwarf.Sleb128put(dwarfctxt, fs, dataAlignmentFactor) // all CFI offset calculations include multiplication with this factor - dwarf.Uleb128put(dwarfctxt, fs, int64(thearch.Dwarfreglr)) // return_address_register - - fs.AddUint8(dwarf.DW_CFA_def_cfa) // Set the current frame address.. - dwarf.Uleb128put(dwarfctxt, fs, int64(thearch.Dwarfregsp)) // ...to use the value in the platform's SP register (defined in l.go)... - if haslinkregister(ctxt) { - dwarf.Uleb128put(dwarfctxt, fs, int64(0)) // ...plus a 0 offset. - - fs.AddUint8(dwarf.DW_CFA_same_value) // The platform's link register is unchanged during the prologue. - dwarf.Uleb128put(dwarfctxt, fs, int64(thearch.Dwarfreglr)) - - fs.AddUint8(dwarf.DW_CFA_val_offset) // The previous value... - dwarf.Uleb128put(dwarfctxt, fs, int64(thearch.Dwarfregsp)) // ...of the platform's SP register... - dwarf.Uleb128put(dwarfctxt, fs, int64(0)) // ...is CFA+0. - } else { - dwarf.Uleb128put(dwarfctxt, fs, int64(ctxt.Arch.PtrSize)) // ...plus the word size (because the call instruction implicitly adds one word to the frame). - - fs.AddUint8(dwarf.DW_CFA_offset_extended) // The previous value... - dwarf.Uleb128put(dwarfctxt, fs, int64(thearch.Dwarfreglr)) // ...of the return address... - dwarf.Uleb128put(dwarfctxt, fs, int64(-ctxt.Arch.PtrSize)/dataAlignmentFactor) // ...is saved at [CFA - (PtrSize/4)]. - } - - pad := int64(cieReserve) + lengthFieldSize - fs.Size - - if pad < 0 { - Exitf("dwarf: cieReserve too small by %d bytes.", -pad) - } - - fs.AddBytes(zeros[:pad]) - - var deltaBuf []byte - pcsp := obj.NewPCIter(uint32(ctxt.Arch.MinLC)) - for _, s := range ctxt.Textp { - if s.FuncInfo == nil { - continue - } - - // Emit a FDE, Section 6.4.1. - // First build the section contents into a byte buffer. - deltaBuf = deltaBuf[:0] - if haslinkregister(ctxt) && s.Attr.TopFrame() { - // Mark the link register as having an undefined value. - // This stops call stack unwinders progressing any further. - // TODO: similar mark on non-LR architectures. - deltaBuf = append(deltaBuf, dwarf.DW_CFA_undefined) - deltaBuf = dwarf.AppendUleb128(deltaBuf, uint64(thearch.Dwarfreglr)) - } - for pcsp.Init(s.FuncInfo.Pcsp.P); !pcsp.Done; pcsp.Next() { - nextpc := pcsp.NextPC - - // pciterinit goes up to the end of the function, - // but DWARF expects us to stop just before the end. - if int64(nextpc) == s.Size { - nextpc-- - if nextpc < pcsp.PC { - continue - } - } - - spdelta := int64(pcsp.Value) - if !haslinkregister(ctxt) { - // Return address has been pushed onto stack. - spdelta += int64(ctxt.Arch.PtrSize) - } - - if haslinkregister(ctxt) && !s.Attr.TopFrame() { - // TODO(bryanpkc): This is imprecise. In general, the instruction - // that stores the return address to the stack frame is not the - // same one that allocates the frame. - if pcsp.Value > 0 { - // The return address is preserved at (CFA-frame_size) - // after a stack frame has been allocated. - deltaBuf = append(deltaBuf, dwarf.DW_CFA_offset_extended_sf) - deltaBuf = dwarf.AppendUleb128(deltaBuf, uint64(thearch.Dwarfreglr)) - deltaBuf = dwarf.AppendSleb128(deltaBuf, -spdelta/dataAlignmentFactor) - } else { - // The return address is restored into the link register - // when a stack frame has been de-allocated. - deltaBuf = append(deltaBuf, dwarf.DW_CFA_same_value) - deltaBuf = dwarf.AppendUleb128(deltaBuf, uint64(thearch.Dwarfreglr)) - } - } - - deltaBuf = appendPCDeltaCFA(ctxt.Arch, deltaBuf, int64(nextpc)-int64(pcsp.PC), spdelta) - } - pad := int(Rnd(int64(len(deltaBuf)), int64(ctxt.Arch.PtrSize))) - len(deltaBuf) - deltaBuf = append(deltaBuf, zeros[:pad]...) - - // Emit the FDE header, Section 6.4.1. - // 4 bytes: length, must be multiple of thearch.ptrsize - // 4/8 bytes: Pointer to the CIE above, at offset 0 - // ptrsize: initial location - // ptrsize: address range - - fdeLength := uint64(4 + 2*ctxt.Arch.PtrSize + len(deltaBuf)) - if isDwarf64(ctxt) { - fdeLength += 4 // 4 bytes added for CIE pointer - } - createUnitLength(ctxt, fs, fdeLength) - - if ctxt.LinkMode == LinkExternal { - addDwarfAddrRef(ctxt, fs, fs) - } else { - addDwarfAddrField(ctxt, fs, 0) // CIE offset - } - fs.AddAddr(ctxt.Arch, s) - fs.AddUintXX(ctxt.Arch, uint64(s.Size), ctxt.Arch.PtrSize) // address range - fs.AddBytes(deltaBuf) - - if ctxt.HeadType == objabi.Haix { - addDwsectCUSize(".debug_frame", s.File, fdeLength+uint64(lengthFieldSize)) - } - } - return syms -} - -/* - * Walk DWarfDebugInfoEntries, and emit .debug_info - */ - -func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*sym.CompilationUnit, abbrevsym *sym.Symbol, pubNames, pubTypes *pubWriter) []*sym.Symbol { - infosec := ctxt.Syms.Lookup(".debug_info", 0) - infosec.Type = sym.SDWARFINFO - infosec.Attr |= sym.AttrReachable - syms = append(syms, infosec) - - var dwarfctxt dwarf.Context = dwctxt{ctxt} - - for _, u := range units { - compunit := u.DWInfo - s := dtolsym(compunit.Sym) - - if len(u.Textp) == 0 && u.DWInfo.Child == nil { - continue - } - - pubNames.beginCompUnit(compunit) - pubTypes.beginCompUnit(compunit) - - // Write .debug_info Compilation Unit Header (sec 7.5.1) - // Fields marked with (*) must be changed for 64-bit dwarf - // This must match COMPUNITHEADERSIZE above. - createUnitLength(ctxt, s, 0) // unit_length (*), will be filled in later. - s.AddUint16(ctxt.Arch, 4) // dwarf version (appendix F) - - // debug_abbrev_offset (*) - addDwarfAddrRef(ctxt, s, abbrevsym) - - s.AddUint8(uint8(ctxt.Arch.PtrSize)) // address_size - - dwarf.Uleb128put(dwarfctxt, s, int64(compunit.Abbrev)) - dwarf.PutAttrs(dwarfctxt, s, compunit.Abbrev, compunit.Attr) - - cu := []*sym.Symbol{s} - cu = append(cu, u.AbsFnDIEs...) - cu = append(cu, u.FuncDIEs...) - if u.Consts != nil { - cu = append(cu, u.Consts) - } - var cusize int64 - for _, child := range cu { - cusize += child.Size - } - - for die := compunit.Child; die != nil; die = die.Link { - l := len(cu) - lastSymSz := cu[l-1].Size - cu = putdie(ctxt, dwarfctxt, cu, die) - if ispubname(die) { - pubNames.add(die, cusize) - } - if ispubtype(die) { - pubTypes.add(die, cusize) - } - if lastSymSz != cu[l-1].Size { - // putdie will sometimes append directly to the last symbol of the list - cusize = cusize - lastSymSz + cu[l-1].Size - } - for _, child := range cu[l:] { - cusize += child.Size - } - } - cu[len(cu)-1].AddUint8(0) // closes compilation unit DIE - cusize++ - - // Save size for AIX symbol table. - if ctxt.HeadType == objabi.Haix { - saveDwsectCUSize(".debug_info", getPkgFromCUSym(s), uint64(cusize)) - } - if isDwarf64(ctxt) { - cusize -= 12 // exclude the length field. - s.SetUint(ctxt.Arch, 4, uint64(cusize)) // 4 because of 0XFFFFFFFF - } else { - cusize -= 4 // exclude the length field. - s.SetUint32(ctxt.Arch, 0, uint32(cusize)) - } - pubNames.endCompUnit(compunit, uint32(cusize)+4) - pubTypes.endCompUnit(compunit, uint32(cusize)+4) - syms = append(syms, cu...) - } - return syms -} - -type pubWriter struct { - ctxt *Link - s *sym.Symbol - sname string - - sectionstart int64 - culengthOff int64 -} - -func newPubWriter(ctxt *Link, sname string) *pubWriter { - s := ctxt.Syms.Lookup(sname, 0) - s.Type = sym.SDWARFSECT - return &pubWriter{ctxt: ctxt, s: s, sname: sname} -} - -func (pw *pubWriter) beginCompUnit(compunit *dwarf.DWDie) { - pw.sectionstart = pw.s.Size - - // Write .debug_pubnames/types Header (sec 6.1.1) - createUnitLength(pw.ctxt, pw.s, 0) // unit_length (*), will be filled in later. - pw.s.AddUint16(pw.ctxt.Arch, 2) // dwarf version (appendix F) - addDwarfAddrRef(pw.ctxt, pw.s, dtolsym(compunit.Sym)) // debug_info_offset (of the Comp unit Header) - pw.culengthOff = pw.s.Size - addDwarfAddrField(pw.ctxt, pw.s, uint64(0)) // debug_info_length, will be filled in later. - -} - -func (pw *pubWriter) add(die *dwarf.DWDie, offset int64) { - dwa := getattr(die, dwarf.DW_AT_name) - name := dwa.Data.(string) - if die.Sym == nil { - fmt.Println("Missing sym for ", name) - } - addDwarfAddrField(pw.ctxt, pw.s, uint64(offset)) - Addstring(pw.s, name) -} - -func (pw *pubWriter) endCompUnit(compunit *dwarf.DWDie, culength uint32) { - addDwarfAddrField(pw.ctxt, pw.s, 0) // Null offset - - // On AIX, save the current size of this compilation unit. - if pw.ctxt.HeadType == objabi.Haix { - saveDwsectCUSize(pw.sname, getPkgFromCUSym(dtolsym(compunit.Sym)), uint64(pw.s.Size-pw.sectionstart)) - } - if isDwarf64(pw.ctxt) { - pw.s.SetUint(pw.ctxt.Arch, pw.sectionstart+4, uint64(pw.s.Size-pw.sectionstart)-12) // exclude the length field. - pw.s.SetUint(pw.ctxt.Arch, pw.culengthOff, uint64(culength)) - } else { - pw.s.SetUint32(pw.ctxt.Arch, pw.sectionstart, uint32(pw.s.Size-pw.sectionstart)-4) // exclude the length field. - pw.s.SetUint32(pw.ctxt.Arch, pw.culengthOff, culength) - } -} - -func writegdbscript(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol { - // TODO (aix): make it available - if ctxt.HeadType == objabi.Haix { - return syms - } - if ctxt.LinkMode == LinkExternal && ctxt.HeadType == objabi.Hwindows && ctxt.BuildMode == BuildModeCArchive { - // gcc on Windows places .debug_gdb_scripts in the wrong location, which - // causes the program not to run. See https://golang.org/issue/20183 - // Non c-archives can avoid this issue via a linker script - // (see fix near writeGDBLinkerScript). - // c-archive users would need to specify the linker script manually. - // For UX it's better not to deal with this. - return syms - } - - if gdbscript != "" { - s := ctxt.Syms.Lookup(".debug_gdb_scripts", 0) - s.Type = sym.SDWARFSECT - syms = append(syms, s) - s.AddUint8(1) // magic 1 byte? - Addstring(s, gdbscript) - } - - return syms -} - -// 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 *FlagNewDw2 { - dwarfGenerateDebugSyms2(ctxt) - return - } - - abbrev := writeabbrev(ctxt) - syms := []*sym.Symbol{abbrev} - - 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) - debugLine.Type = sym.SDWARFSECT - debugRanges := ctxt.Syms.Lookup(".debug_ranges", 0) - debugRanges.Type = sym.SDWARFRANGE - debugRanges.Attr |= sym.AttrReachable - syms = append(syms, debugLine) - for _, u := range ctxt.compUnits { - reversetree(&u.DWInfo.Child) - if u.DWInfo.Abbrev == dwarf.DW_ABRV_COMPUNIT_TEXTLESS { - continue - } - writelines(ctxt, u, debugLine) - writepcranges(ctxt, u, u.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(&dwtypes.Child) - movetomodule(ctxt, &dwtypes) - - pubNames := newPubWriter(ctxt, ".debug_pubnames") - pubTypes := newPubWriter(ctxt, ".debug_pubtypes") - - // Need to reorder symbols so sym.SDWARFINFO is after all sym.SDWARFSECT - infosyms := writeinfo(ctxt, nil, ctxt.compUnits, abbrev, pubNames, pubTypes) - - syms = writeframes(ctxt, syms) - syms = append(syms, pubNames.s, pubTypes.s) - syms = writegdbscript(ctxt, syms) - // Now we're done writing SDWARFSECT symbols, so we can write - // other SDWARF* symbols. - syms = append(syms, infosyms...) - syms = collectlocs(ctxt, syms, ctxt.compUnits) - syms = append(syms, debugRanges) - for _, unit := range ctxt.compUnits { - syms = append(syms, unit.RangeSyms...) - } - dwarfp = syms -} - -func collectlocs(ctxt *Link, syms []*sym.Symbol, units []*sym.CompilationUnit) []*sym.Symbol { - empty := true - for _, u := range units { - for _, fn := range u.FuncDIEs { - for i := range fn.R { - reloc := &fn.R[i] // Copying sym.Reloc has measurable impact on performance - 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 - // One location list entry per function, but many relocations to it. Don't duplicate. - break - } - } - } - } - // Don't emit .debug_loc if it's empty -- it makes the ARM linker mad. - if !empty { - locsym := ctxt.Syms.Lookup(".debug_loc", 0) - locsym.Type = sym.SDWARFLOC - locsym.Attr |= sym.AttrReachable - syms = append(syms, locsym) - } - return syms -} - -// Read a pointer-sized uint from the beginning of buf. -func readPtr(ctxt *Link, buf []byte) uint64 { - switch ctxt.Arch.PtrSize { - case 4: - return uint64(ctxt.Arch.ByteOrder.Uint32(buf)) - case 8: - return ctxt.Arch.ByteOrder.Uint64(buf) - default: - panic("unexpected pointer size") - } -} - /* * Elf. */ @@ -1008,31 +179,3 @@ func (v compilationUnitByStartPC) Less(i, j int) bool { return v[i].PCs[0].Start < v[j].PCs[0].Start } } - -// On AIX, the symbol table needs to know where are the compilation units parts -// for a specific package in each .dw section. -// dwsectCUSize map will save the size of a compilation unit for -// the corresponding .dw section. -// This size can later be retrieved with the index "sectionName.pkgName". -var dwsectCUSize map[string]uint64 - -// getDwsectCUSize retrieves the corresponding package size inside the current section. -func getDwsectCUSize(sname string, pkgname string) uint64 { - return dwsectCUSize[sname+"."+pkgname] -} - -func saveDwsectCUSize(sname string, pkgname string, size uint64) { - dwsectCUSize[sname+"."+pkgname] = size -} - -func addDwsectCUSize(sname string, pkgname string, size uint64) { - dwsectCUSize[sname+"."+pkgname] += size -} - -// getPkgFromCUSym returns the package name for the compilation unit -// represented by s. -// The prefix dwarf.InfoPrefix+".pkg." needs to be removed in order to get -// the package name. -func getPkgFromCUSym(s *sym.Symbol) string { - return strings.TrimPrefix(s.Name, dwarf.InfoPrefix+".pkg.") -} diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 6ef0ac3ca6..e1948ecfc5 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -2682,11 +2682,6 @@ func (ctxt *Link) loadlibfull() { ctxt.loader.ExtractSymbols(ctxt.Syms, ctxt.Reachparent) ctxt.lookup = ctxt.Syms.ROLookup - // When we generated dwarf DIE objects, we created them - // with embedded loader.Sym refs as opposed to sym.Symbol refs. - // Call a helper to rewrite the former to the latter in all DIEs. - dwarfConvertSymbols(ctxt) - setupdynexp(ctxt) // Drop the cgodata reference. diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 7f66d27179..8e7b9b8113 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -88,7 +88,6 @@ var ( flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker") FlagDebugTramp = flag.Int("debugtramp", 0, "debug trampolines") FlagStrictDups = flag.Int("strictdups", 0, "sanity check duplicate symbol contents during object file reading (1=warn 2=err).") - FlagNewDw2 = flag.Bool("newdw2", true, "DWARF gen phase 2 new loader") FlagRound = flag.Int("R", -1, "set address rounding `quantum`") FlagTextAddr = flag.Int64("T", -1, "set text segment `address`") flagEntrySymbol = flag.String("E", "", "set `entry` symbol name")