diff --git a/src/cmd/internal/dwarf/dwarf.go b/src/cmd/internal/dwarf/dwarf.go index 355091feda..21512a80bd 100644 --- a/src/cmd/internal/dwarf/dwarf.go +++ b/src/cmd/internal/dwarf/dwarf.go @@ -179,7 +179,7 @@ type Context interface { AddBytes(s Sym, b []byte) AddAddress(s Sym, t interface{}, ofs int64) AddSectionOffset(s Sym, size int, t interface{}, ofs int64) - AddDWARFSectionOffset(s Sym, size int, t interface{}, ofs int64) + AddDWARFAddrSectionOffset(s Sym, t interface{}, ofs int64) CurrentOffset(s Sym) int64 RecordDclReference(from Sym, to Sym, dclIdx int, inlIndex int) RecordChildDieOffsets(s Sym, vars []*Var, offsets []int32) @@ -895,7 +895,7 @@ func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, da case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr if cls == DW_CLS_PTR { // DW_AT_stmt_list and DW_AT_ranges - ctxt.AddDWARFSectionOffset(s, 4, data, value) + ctxt.AddDWARFAddrSectionOffset(s, data, value) break } ctxt.AddInt(s, 4, value) @@ -932,7 +932,7 @@ func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, da if data == nil { return fmt.Errorf("dwarf: null reference in %d", abbrev) } - ctxt.AddDWARFSectionOffset(s, 4, data, value) + ctxt.AddDWARFAddrSectionOffset(s, data, value) case DW_FORM_ref1, // reference within the compilation unit DW_FORM_ref2, // reference diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index ef9ce4c688..b6cfec3b3e 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -459,7 +459,12 @@ func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) { func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) { panic("should be used only in the linker") } -func (c dwCtxt) AddDWARFSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) { +func (c dwCtxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) { + size := 4 + if isDwarf64(c.Link) { + size = 8 + } + ls := s.(*LSym) rsym := t.(*LSym) ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs) @@ -500,6 +505,10 @@ func (c dwCtxt) Logf(format string, args ...interface{}) { c.Link.Logf(format, args...) } +func isDwarf64(ctxt *Link) bool { + return ctxt.Headtype == objabi.Haix +} + func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym, dwarfIsStmtSym *LSym) { if s.Type != objabi.STEXT { ctxt.Diag("dwarfSym of non-TEXT %v", s) diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 827a1d931a..7a20650d9c 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -67,7 +67,12 @@ func (c dwctxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64 r.Add = ofs } -func (c dwctxt) AddDWARFSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) { +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 @@ -95,6 +100,10 @@ func (c dwctxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets [] panic("should be used only in the compiler") } +func isDwarf64(ctxt *Link) bool { + return ctxt.HeadType == objabi.Haix +} + var gdbscript string var dwarfp []*sym.Symbol @@ -873,6 +882,33 @@ func defdwsymb(ctxt *Link, s *sym.Symbol, str string, t SymbolType, v int64, got } } +// 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) + } +} + // compilationUnit is per-compilation unit (equivalently, per-package) // debug-related data. type compilationUnit struct { @@ -1081,11 +1117,11 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { // Write .debug_line Line Number Program Header (sec 6.2.4) // Fields marked with (*) must be changed for 64-bit dwarf unitLengthOffset := ls.Size - ls.AddUint32(ctxt.Arch, 0) // unit_length (*), filled in at end. + 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 - ls.AddUint32(ctxt.Arch, 0) // header_length (*), filled in at end. + addDwarfAddrField(ctxt, ls, 0) // header_length (*), filled in at end headerstart = ls.Size // cpos == unitstart + 4 + 2 + 4 @@ -1238,8 +1274,16 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { dwarf.Uleb128put(dwarfctxt, ls, 1) ls.AddUint8(dwarf.DW_LNE_end_sequence) - ls.SetUint32(ctxt.Arch, unitLengthOffset, uint32(ls.Size-unitstart)) - ls.SetUint32(ctxt.Arch, headerLengthOffset, uint32(headerend-headerstart)) + if ctxt.HeadType == objabi.Haix { + saveDwsectCUSize(".debug_line", unit.lib.String(), 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)) + } // Apply any R_DWARFFILEREF relocations, since we now know the // line table file indices for this compilation unit. Note that @@ -1329,8 +1373,8 @@ func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol { if haslinkregister(ctxt) { cieReserve = 32 } - fs.AddUint32(ctxt.Arch, cieReserve) // initial length, must be multiple of thearch.ptrsize - fs.AddUint32(ctxt.Arch, 0xffffffff) // cid. + createUnitLength(ctxt, fs, uint64(cieReserve)) // initial length, must be multiple of thearch.ptrsize + addDwarfAddrField(ctxt, fs, 0xffffffff) // cid. fs.AddUint8(3) // dwarf version (appendix F) fs.AddUint8(0) // augmentation "" dwarf.Uleb128put(dwarfctxt, fs, 1) // code_alignment_factor @@ -1418,9 +1462,9 @@ func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol { // ptrsize: address range fs.AddUint32(ctxt.Arch, uint32(4+2*ctxt.Arch.PtrSize+len(deltaBuf))) // length (excludes itself) if ctxt.LinkMode == LinkExternal { - adddwarfref(ctxt, fs, fs, 4) + addDwarfAddrRef(ctxt, fs, fs) } else { - fs.AddUint32(ctxt.Arch, 0) // CIE offset + addDwarfAddrField(ctxt, fs, 0) // CIE offset } fs.AddAddr(ctxt.Arch, s) fs.AddUintXX(ctxt.Arch, uint64(s.Size), ctxt.Arch.PtrSize) // address range @@ -1455,11 +1499,11 @@ func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevs // 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. - s.AddUint32(ctxt.Arch, 0) // unit_length (*), will be filled in later. - s.AddUint16(ctxt.Arch, 4) // dwarf version (appendix F) + createUnitLength(ctxt, s, 0) // unit_length (*), will be filled in later. + s.AddUint16(ctxt.Arch, 4) // dwarf version (appendix F) // debug_abbrev_offset (*) - adddwarfref(ctxt, s, abbrevsym, 4) + addDwarfAddrRef(ctxt, s, abbrevsym) s.AddUint8(uint8(ctxt.Arch.PtrSize)) // address_size @@ -1477,8 +1521,17 @@ func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevs for _, child := range cu { cusize += child.Size } - cusize -= 4 // exclude the length field. - s.SetUint32(ctxt.Arch, 0, uint32(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)) + } // Leave a breadcrumb for writepub. This does not // appear in the DWARF output. newattr(compunit, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, cusize, 0) @@ -1519,10 +1572,10 @@ func writepub(ctxt *Link, sname string, ispub func(*dwarf.DWDie) bool, syms []*s culength := uint32(getattr(compunit, dwarf.DW_AT_byte_size).Value) + 4 // Write .debug_pubnames/types Header (sec 6.1.1) - s.AddUint32(ctxt.Arch, 0) // unit_length (*), will be filled in later. - s.AddUint16(ctxt.Arch, 2) // dwarf version (appendix F) - adddwarfref(ctxt, s, dtolsym(compunit.Sym), 4) // debug_info_offset (of the Comp unit Header) - s.AddUint32(ctxt.Arch, culength) // debug_info_length + createUnitLength(ctxt, s, 0) // unit_length (*), will be filled in later. + s.AddUint16(ctxt.Arch, 2) // dwarf version (appendix F) + addDwarfAddrRef(ctxt, s, dtolsym(compunit.Sym)) // debug_info_offset (of the Comp unit Header) + addDwarfAddrField(ctxt, s, uint64(culength)) // debug_info_length for die := compunit.Child; die != nil; die = die.Link { if !ispub(die) { @@ -1533,19 +1586,31 @@ func writepub(ctxt *Link, sname string, ispub func(*dwarf.DWDie) bool, syms []*s if die.Sym == nil { fmt.Println("Missing sym for ", name) } - adddwarfref(ctxt, s, dtolsym(die.Sym), 4) + addDwarfAddrRef(ctxt, s, dtolsym(die.Sym)) Addstring(s, name) } - s.AddUint32(ctxt.Arch, 0) + addDwarfAddrField(ctxt, s, 0) // Null offset - s.SetUint32(ctxt.Arch, sectionstart, uint32(s.Size-sectionstart)-4) // exclude the length field. + // On AIX, save the current size of this compilation unit. + if ctxt.HeadType == objabi.Haix { + saveDwsectCUSize(sname, getPkgFromCUSym(dtolsym(compunit.Sym)), uint64(s.Size-sectionstart)) + } + if isDwarf64(ctxt) { + s.SetUint(ctxt.Arch, sectionstart+4, uint64(s.Size-sectionstart)-12) // exclude the length field. + } else { + s.SetUint32(ctxt.Arch, sectionstart, uint32(s.Size-sectionstart)-4) // exclude the length field. + } } return syms } 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 @@ -2019,3 +2084,27 @@ func (v compilationUnitByStartPC) Less(i, j int) bool { return v[i].lib.Textp[0].Value < v[j].lib.Textp[0].Value } } + +// 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 +} + +// 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.") +}