mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.link] cmd/internal/obj: combine objfile.go and objfile2.go
Combine objfile2.go into objfile.go. objfile.go has a lot of code for DWARF generation. Move them to dwarf.go. Change-Id: I2a27c672e9e9b8eea35d5e0a71433dcc80b7afa4 Reviewed-on: https://go-review.googlesource.com/c/go/+/247918 Run-TryBot: Cherry Zhang <cherryyz@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
parent
991adcd21b
commit
3fc2e6b0ce
3 changed files with 1138 additions and 1149 deletions
|
|
@ -8,8 +8,11 @@ package obj
|
|||
|
||||
import (
|
||||
"cmd/internal/dwarf"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/src"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Generate a sequence of opcodes that is as short as possible.
|
||||
|
|
@ -196,3 +199,492 @@ func putpclcdelta(linkctxt *Link, dctxt dwCtxt, s *LSym, deltaPC uint64, deltaLC
|
|||
// Output the special opcode.
|
||||
dctxt.AddUint8(s, uint8(opcode))
|
||||
}
|
||||
|
||||
// implement dwarf.Context
|
||||
type dwCtxt struct{ *Link }
|
||||
|
||||
func (c dwCtxt) PtrSize() int {
|
||||
return c.Arch.PtrSize
|
||||
}
|
||||
func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) {
|
||||
ls := s.(*LSym)
|
||||
ls.WriteInt(c.Link, ls.Size, size, i)
|
||||
}
|
||||
func (c dwCtxt) AddUint16(s dwarf.Sym, i uint16) {
|
||||
c.AddInt(s, 2, int64(i))
|
||||
}
|
||||
func (c dwCtxt) AddUint8(s dwarf.Sym, i uint8) {
|
||||
b := []byte{byte(i)}
|
||||
c.AddBytes(s, b)
|
||||
}
|
||||
func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) {
|
||||
ls := s.(*LSym)
|
||||
ls.WriteBytes(c.Link, ls.Size, b)
|
||||
}
|
||||
func (c dwCtxt) AddString(s dwarf.Sym, v string) {
|
||||
ls := s.(*LSym)
|
||||
ls.WriteString(c.Link, ls.Size, len(v), v)
|
||||
ls.WriteInt(c.Link, ls.Size, 1, 0)
|
||||
}
|
||||
func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
|
||||
ls := s.(*LSym)
|
||||
size := c.PtrSize()
|
||||
if data != nil {
|
||||
rsym := data.(*LSym)
|
||||
ls.WriteAddr(c.Link, ls.Size, size, rsym, value)
|
||||
} else {
|
||||
ls.WriteInt(c.Link, ls.Size, size, value)
|
||||
}
|
||||
}
|
||||
func (c dwCtxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) {
|
||||
ls := s.(*LSym)
|
||||
rsym := data.(*LSym)
|
||||
ls.WriteCURelativeAddr(c.Link, ls.Size, rsym, value)
|
||||
}
|
||||
func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
|
||||
panic("should be used only in the linker")
|
||||
}
|
||||
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)
|
||||
r := &ls.R[len(ls.R)-1]
|
||||
r.Type = objabi.R_DWARFSECREF
|
||||
}
|
||||
|
||||
func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) {
|
||||
ls := s.(*LSym)
|
||||
rsym := f.(*LSym)
|
||||
fidx := c.Link.PosTable.FileIndex(rsym.Name)
|
||||
// Note the +1 here -- the value we're writing is going to be an
|
||||
// index into the DWARF line table file section, whose entries
|
||||
// are numbered starting at 1, not 0.
|
||||
ls.WriteInt(c.Link, ls.Size, 4, int64(fidx+1))
|
||||
}
|
||||
|
||||
func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 {
|
||||
ls := s.(*LSym)
|
||||
return ls.Size
|
||||
}
|
||||
|
||||
// Here "from" is a symbol corresponding to an inlined or concrete
|
||||
// function, "to" is the symbol for the corresponding abstract
|
||||
// function, and "dclIdx" is the index of the symbol of interest with
|
||||
// respect to the Dcl slice of the original pre-optimization version
|
||||
// of the inlined function.
|
||||
func (c dwCtxt) RecordDclReference(from dwarf.Sym, to dwarf.Sym, dclIdx int, inlIndex int) {
|
||||
ls := from.(*LSym)
|
||||
tls := to.(*LSym)
|
||||
ridx := len(ls.R) - 1
|
||||
c.Link.DwFixups.ReferenceChildDIE(ls, ridx, tls, dclIdx, inlIndex)
|
||||
}
|
||||
|
||||
func (c dwCtxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) {
|
||||
ls := s.(*LSym)
|
||||
c.Link.DwFixups.RegisterChildDIEOffsets(ls, vars, offsets)
|
||||
}
|
||||
|
||||
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, dwarfDebugLines *LSym) {
|
||||
if s.Type != objabi.STEXT {
|
||||
ctxt.Diag("dwarfSym of non-TEXT %v", s)
|
||||
}
|
||||
if s.Func.dwarfInfoSym == nil {
|
||||
s.Func.dwarfInfoSym = &LSym{
|
||||
Type: objabi.SDWARFFCN,
|
||||
}
|
||||
if ctxt.Flag_locationlists {
|
||||
s.Func.dwarfLocSym = &LSym{
|
||||
Type: objabi.SDWARFLOC,
|
||||
}
|
||||
}
|
||||
s.Func.dwarfRangesSym = &LSym{
|
||||
Type: objabi.SDWARFRANGE,
|
||||
}
|
||||
s.Func.dwarfDebugLinesSym = &LSym{
|
||||
Type: objabi.SDWARFLINES,
|
||||
}
|
||||
if s.WasInlined() {
|
||||
s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
|
||||
}
|
||||
}
|
||||
return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym, s.Func.dwarfAbsFnSym, s.Func.dwarfDebugLinesSym
|
||||
}
|
||||
|
||||
func (s *LSym) Length(dwarfContext interface{}) 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 various DWARF symbols must already have been
|
||||
// initialized in InitTextSym.
|
||||
func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym, myimportpath string) {
|
||||
info, loc, ranges, absfunc, lines := ctxt.dwarfSym(s)
|
||||
if info.Size != 0 {
|
||||
ctxt.Diag("makeFuncDebugEntry double process %v", s)
|
||||
}
|
||||
var scopes []dwarf.Scope
|
||||
var inlcalls dwarf.InlCalls
|
||||
if ctxt.DebugInfo != nil {
|
||||
scopes, inlcalls = ctxt.DebugInfo(s, info, curfn)
|
||||
}
|
||||
var err error
|
||||
dwctxt := dwCtxt{ctxt}
|
||||
filesym := ctxt.fileSymbol(s)
|
||||
fnstate := &dwarf.FnState{
|
||||
Name: s.Name,
|
||||
Importpath: myimportpath,
|
||||
Info: info,
|
||||
Filesym: filesym,
|
||||
Loc: loc,
|
||||
Ranges: ranges,
|
||||
Absfn: absfunc,
|
||||
StartPC: s,
|
||||
Size: s.Size,
|
||||
External: !s.Static(),
|
||||
Scopes: scopes,
|
||||
InlCalls: inlcalls,
|
||||
UseBASEntries: ctxt.UseBASEntries,
|
||||
}
|
||||
if absfunc != nil {
|
||||
err = dwarf.PutAbstractFunc(dwctxt, fnstate)
|
||||
if err != nil {
|
||||
ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
|
||||
}
|
||||
err = dwarf.PutConcreteFunc(dwctxt, fnstate)
|
||||
} else {
|
||||
err = dwarf.PutDefaultFunc(dwctxt, fnstate)
|
||||
}
|
||||
if err != nil {
|
||||
ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
|
||||
}
|
||||
// Fill in the debug lines symbol.
|
||||
ctxt.generateDebugLinesSymbol(s, lines)
|
||||
}
|
||||
|
||||
// DwarfIntConst creates a link symbol for an integer constant with the
|
||||
// given name, type and value.
|
||||
func (ctxt *Link) DwarfIntConst(myimportpath, name, typename string, val int64) {
|
||||
if myimportpath == "" {
|
||||
return
|
||||
}
|
||||
s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) {
|
||||
s.Type = objabi.SDWARFCONST
|
||||
ctxt.Data = append(ctxt.Data, s)
|
||||
})
|
||||
dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val)
|
||||
}
|
||||
|
||||
func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath string) {
|
||||
absfn := ctxt.DwFixups.AbsFuncDwarfSym(s)
|
||||
if absfn.Size != 0 {
|
||||
ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s)
|
||||
}
|
||||
if s.Func == nil {
|
||||
s.Func = new(FuncInfo)
|
||||
}
|
||||
scopes, _ := ctxt.DebugInfo(s, absfn, curfn)
|
||||
dwctxt := dwCtxt{ctxt}
|
||||
filesym := ctxt.fileSymbol(s)
|
||||
fnstate := dwarf.FnState{
|
||||
Name: s.Name,
|
||||
Importpath: myimportpath,
|
||||
Info: absfn,
|
||||
Filesym: filesym,
|
||||
Absfn: absfn,
|
||||
External: !s.Static(),
|
||||
Scopes: scopes,
|
||||
UseBASEntries: ctxt.UseBASEntries,
|
||||
}
|
||||
if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil {
|
||||
ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
// This table is designed to aid in the creation of references between
|
||||
// DWARF subprogram DIEs.
|
||||
//
|
||||
// In most cases when one DWARF DIE has to refer to another DWARF DIE,
|
||||
// the target of the reference has an LSym, which makes it easy to use
|
||||
// the existing relocation mechanism. For DWARF inlined routine DIEs,
|
||||
// however, the subprogram DIE has to refer to a child
|
||||
// parameter/variable DIE of the abstract subprogram. This child DIE
|
||||
// doesn't have an LSym, and also of interest is the fact that when
|
||||
// DWARF generation is happening for inlined function F within caller
|
||||
// G, it's possible that DWARF generation hasn't happened yet for F,
|
||||
// so there is no way to know the offset of a child DIE within F's
|
||||
// abstract function. Making matters more complex, each inlined
|
||||
// instance of F may refer to a subset of the original F's variables
|
||||
// (depending on what happens with optimization, some vars may be
|
||||
// eliminated).
|
||||
//
|
||||
// The fixup table below helps overcome this hurdle. At the point
|
||||
// where a parameter/variable reference is made (via a call to
|
||||
// "ReferenceChildDIE"), a fixup record is generate that records
|
||||
// the relocation that is targeting that child variable. At a later
|
||||
// point when the abstract function DIE is emitted, there will be
|
||||
// a call to "RegisterChildDIEOffsets", at which point the offsets
|
||||
// needed to apply fixups are captured. Finally, once the parallel
|
||||
// portion of the compilation is done, fixups can actually be applied
|
||||
// during the "Finalize" method (this can't be done during the
|
||||
// parallel portion of the compile due to the possibility of data
|
||||
// races).
|
||||
//
|
||||
// This table is also used to record the "precursor" function node for
|
||||
// each function that is the target of an inline -- child DIE references
|
||||
// have to be made with respect to the original pre-optimization
|
||||
// version of the function (to allow for the fact that each inlined
|
||||
// body may be optimized differently).
|
||||
type DwarfFixupTable struct {
|
||||
ctxt *Link
|
||||
mu sync.Mutex
|
||||
symtab map[*LSym]int // maps abstract fn LSYM to index in svec
|
||||
svec []symFixups
|
||||
precursor map[*LSym]fnState // maps fn Lsym to precursor Node, absfn sym
|
||||
}
|
||||
|
||||
type symFixups struct {
|
||||
fixups []relFixup
|
||||
doffsets []declOffset
|
||||
inlIndex int32
|
||||
defseen bool
|
||||
}
|
||||
|
||||
type declOffset struct {
|
||||
// Index of variable within DCL list of pre-optimization function
|
||||
dclIdx int32
|
||||
// Offset of var's child DIE with respect to containing subprogram DIE
|
||||
offset int32
|
||||
}
|
||||
|
||||
type relFixup struct {
|
||||
refsym *LSym
|
||||
relidx int32
|
||||
dclidx int32
|
||||
}
|
||||
|
||||
type fnState struct {
|
||||
// precursor function (really *gc.Node)
|
||||
precursor interface{}
|
||||
// abstract function symbol
|
||||
absfn *LSym
|
||||
}
|
||||
|
||||
func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable {
|
||||
return &DwarfFixupTable{
|
||||
ctxt: ctxt,
|
||||
symtab: make(map[*LSym]int),
|
||||
precursor: make(map[*LSym]fnState),
|
||||
}
|
||||
}
|
||||
|
||||
func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) interface{} {
|
||||
if fnstate, found := ft.precursor[s]; found {
|
||||
return fnstate.precursor
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) {
|
||||
if _, found := ft.precursor[s]; found {
|
||||
ft.ctxt.Diag("internal error: DwarfFixupTable.SetPrecursorFunc double call on %v", s)
|
||||
}
|
||||
|
||||
// initialize abstract function symbol now. This is done here so
|
||||
// as to avoid data races later on during the parallel portion of
|
||||
// the back end.
|
||||
absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix)
|
||||
absfn.Set(AttrDuplicateOK, true)
|
||||
absfn.Type = objabi.SDWARFABSFCN
|
||||
ft.ctxt.Data = append(ft.ctxt.Data, absfn)
|
||||
|
||||
// In the case of "late" inlining (inlines that happen during
|
||||
// wrapper generation as opposed to the main inlining phase) it's
|
||||
// possible that we didn't cache the abstract function sym for the
|
||||
// text symbol -- do so now if needed. See issue 38068.
|
||||
if s.Func != nil && s.Func.dwarfAbsFnSym == nil {
|
||||
s.Func.dwarfAbsFnSym = absfn
|
||||
}
|
||||
|
||||
ft.precursor[s] = fnState{precursor: fn, absfn: absfn}
|
||||
}
|
||||
|
||||
// Make a note of a child DIE reference: relocation 'ridx' within symbol 's'
|
||||
// is targeting child 'c' of DIE with symbol 'tgt'.
|
||||
func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) {
|
||||
// Protect against concurrent access if multiple backend workers
|
||||
ft.mu.Lock()
|
||||
defer ft.mu.Unlock()
|
||||
|
||||
// Create entry for symbol if not already present.
|
||||
idx, found := ft.symtab[tgt]
|
||||
if !found {
|
||||
ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)})
|
||||
idx = len(ft.svec) - 1
|
||||
ft.symtab[tgt] = idx
|
||||
}
|
||||
|
||||
// Do we have child DIE offsets available? If so, then apply them,
|
||||
// otherwise create a fixup record.
|
||||
sf := &ft.svec[idx]
|
||||
if len(sf.doffsets) > 0 {
|
||||
found := false
|
||||
for _, do := range sf.doffsets {
|
||||
if do.dclIdx == int32(dclidx) {
|
||||
off := do.offset
|
||||
s.R[ridx].Add += int64(off)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
ft.ctxt.Diag("internal error: DwarfFixupTable.ReferenceChildDIE unable to locate child DIE offset for dclIdx=%d src=%v tgt=%v", dclidx, s, tgt)
|
||||
}
|
||||
} else {
|
||||
sf.fixups = append(sf.fixups, relFixup{s, int32(ridx), int32(dclidx)})
|
||||
}
|
||||
}
|
||||
|
||||
// Called once DWARF generation is complete for a given abstract function,
|
||||
// whose children might have been referenced via a call above. Stores
|
||||
// the offsets for any child DIEs (vars, params) so that they can be
|
||||
// consumed later in on DwarfFixupTable.Finalize, which applies any
|
||||
// outstanding fixups.
|
||||
func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) {
|
||||
// Length of these two slices should agree
|
||||
if len(vars) != len(coffsets) {
|
||||
ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch")
|
||||
return
|
||||
}
|
||||
|
||||
// Generate the slice of declOffset's based in vars/coffsets
|
||||
doffsets := make([]declOffset, len(coffsets))
|
||||
for i := range coffsets {
|
||||
doffsets[i].dclIdx = vars[i].ChildIndex
|
||||
doffsets[i].offset = coffsets[i]
|
||||
}
|
||||
|
||||
ft.mu.Lock()
|
||||
defer ft.mu.Unlock()
|
||||
|
||||
// Store offsets for this symbol.
|
||||
idx, found := ft.symtab[s]
|
||||
if !found {
|
||||
sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets}
|
||||
ft.svec = append(ft.svec, sf)
|
||||
ft.symtab[s] = len(ft.svec) - 1
|
||||
} else {
|
||||
sf := &ft.svec[idx]
|
||||
sf.doffsets = doffsets
|
||||
sf.defseen = true
|
||||
}
|
||||
}
|
||||
|
||||
func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) {
|
||||
sf := &ft.svec[slot]
|
||||
for _, f := range sf.fixups {
|
||||
dfound := false
|
||||
for _, doffset := range sf.doffsets {
|
||||
if doffset.dclIdx == f.dclidx {
|
||||
f.refsym.R[f.relidx].Add += int64(doffset.offset)
|
||||
dfound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !dfound {
|
||||
ft.ctxt.Diag("internal error: DwarfFixupTable has orphaned fixup on %v targeting %v relidx=%d dclidx=%d", f.refsym, s, f.relidx, f.dclidx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return the LSym corresponding to the 'abstract subprogram' DWARF
|
||||
// info entry for a function.
|
||||
func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym {
|
||||
// Protect against concurrent access if multiple backend workers
|
||||
ft.mu.Lock()
|
||||
defer ft.mu.Unlock()
|
||||
|
||||
if fnstate, found := ft.precursor[fnsym]; found {
|
||||
return fnstate.absfn
|
||||
}
|
||||
ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Called after all functions have been compiled; the main job of this
|
||||
// function is to identify cases where there are outstanding fixups.
|
||||
// This scenario crops up when we have references to variables of an
|
||||
// inlined routine, but that routine is defined in some other package.
|
||||
// This helper walks through and locate these fixups, then invokes a
|
||||
// helper to create an abstract subprogram DIE for each one.
|
||||
func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) {
|
||||
if trace {
|
||||
ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath)
|
||||
}
|
||||
|
||||
// Collect up the keys from the precursor map, then sort the
|
||||
// resulting list (don't want to rely on map ordering here).
|
||||
fns := make([]*LSym, len(ft.precursor))
|
||||
idx := 0
|
||||
for fn := range ft.precursor {
|
||||
fns[idx] = fn
|
||||
idx++
|
||||
}
|
||||
sort.Sort(BySymName(fns))
|
||||
|
||||
// Should not be called during parallel portion of compilation.
|
||||
if ft.ctxt.InParallel {
|
||||
ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend")
|
||||
}
|
||||
|
||||
// Generate any missing abstract functions.
|
||||
for _, s := range fns {
|
||||
absfn := ft.AbsFuncDwarfSym(s)
|
||||
slot, found := ft.symtab[absfn]
|
||||
if !found || !ft.svec[slot].defseen {
|
||||
ft.ctxt.GenAbstractFunc(s)
|
||||
}
|
||||
}
|
||||
|
||||
// Apply fixups.
|
||||
for _, s := range fns {
|
||||
absfn := ft.AbsFuncDwarfSym(s)
|
||||
slot, found := ft.symtab[absfn]
|
||||
if !found {
|
||||
ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s)
|
||||
} else {
|
||||
ft.processFixups(slot, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type BySymName []*LSym
|
||||
|
||||
func (s BySymName) Len() int { return len(s) }
|
||||
func (s BySymName) Less(i, j int) bool { return s[i].Name < s[j].Name }
|
||||
func (s BySymName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,658 +0,0 @@
|
|||
// Copyright 2019 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.
|
||||
|
||||
// Writing Go object files.
|
||||
|
||||
package obj
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/goobj"
|
||||
"cmd/internal/objabi"
|
||||
"crypto/sha1"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Entry point of writing new object file.
|
||||
func WriteObjFile(ctxt *Link, b *bio.Writer) {
|
||||
|
||||
debugAsmEmit(ctxt)
|
||||
|
||||
genFuncInfoSyms(ctxt)
|
||||
|
||||
w := writer{
|
||||
Writer: goobj.NewWriter(b),
|
||||
ctxt: ctxt,
|
||||
pkgpath: objabi.PathToPrefix(ctxt.Pkgpath),
|
||||
}
|
||||
|
||||
start := b.Offset()
|
||||
w.init()
|
||||
|
||||
// Header
|
||||
// We just reserve the space. We'll fill in the offsets later.
|
||||
flags := uint32(0)
|
||||
if ctxt.Flag_shared {
|
||||
flags |= goobj.ObjFlagShared
|
||||
}
|
||||
if w.pkgpath == "" {
|
||||
flags |= goobj.ObjFlagNeedNameExpansion
|
||||
}
|
||||
if ctxt.IsAsm {
|
||||
flags |= goobj.ObjFlagFromAssembly
|
||||
}
|
||||
h := goobj.Header{
|
||||
Magic: goobj.Magic,
|
||||
Fingerprint: ctxt.Fingerprint,
|
||||
Flags: flags,
|
||||
}
|
||||
h.Write(w.Writer)
|
||||
|
||||
// String table
|
||||
w.StringTable()
|
||||
|
||||
// Autolib
|
||||
h.Offsets[goobj.BlkAutolib] = w.Offset()
|
||||
for i := range ctxt.Imports {
|
||||
ctxt.Imports[i].Write(w.Writer)
|
||||
}
|
||||
|
||||
// Package references
|
||||
h.Offsets[goobj.BlkPkgIdx] = w.Offset()
|
||||
for _, pkg := range w.pkglist {
|
||||
w.StringRef(pkg)
|
||||
}
|
||||
|
||||
// File table (for DWARF and pcln generation).
|
||||
h.Offsets[goobj.BlkFile] = w.Offset()
|
||||
for _, f := range ctxt.PosTable.FileTable() {
|
||||
w.StringRef(filepath.ToSlash(f))
|
||||
}
|
||||
|
||||
// Symbol definitions
|
||||
h.Offsets[goobj.BlkSymdef] = w.Offset()
|
||||
for _, s := range ctxt.defs {
|
||||
w.Sym(s)
|
||||
}
|
||||
|
||||
// Short hashed symbol definitions
|
||||
h.Offsets[goobj.BlkHashed64def] = w.Offset()
|
||||
for _, s := range ctxt.hashed64defs {
|
||||
w.Sym(s)
|
||||
}
|
||||
|
||||
// Hashed symbol definitions
|
||||
h.Offsets[goobj.BlkHasheddef] = w.Offset()
|
||||
for _, s := range ctxt.hasheddefs {
|
||||
w.Sym(s)
|
||||
}
|
||||
|
||||
// Non-pkg symbol definitions
|
||||
h.Offsets[goobj.BlkNonpkgdef] = w.Offset()
|
||||
for _, s := range ctxt.nonpkgdefs {
|
||||
w.Sym(s)
|
||||
}
|
||||
|
||||
// Non-pkg symbol references
|
||||
h.Offsets[goobj.BlkNonpkgref] = w.Offset()
|
||||
for _, s := range ctxt.nonpkgrefs {
|
||||
w.Sym(s)
|
||||
}
|
||||
|
||||
// Referenced package symbol flags
|
||||
h.Offsets[goobj.BlkRefFlags] = w.Offset()
|
||||
w.refFlags()
|
||||
|
||||
// Hashes
|
||||
h.Offsets[goobj.BlkHash64] = w.Offset()
|
||||
for _, s := range ctxt.hashed64defs {
|
||||
w.Hash64(s)
|
||||
}
|
||||
h.Offsets[goobj.BlkHash] = w.Offset()
|
||||
for _, s := range ctxt.hasheddefs {
|
||||
w.Hash(s)
|
||||
}
|
||||
// TODO: hashedrefs unused/unsupported for now
|
||||
|
||||
// Reloc indexes
|
||||
h.Offsets[goobj.BlkRelocIdx] = w.Offset()
|
||||
nreloc := uint32(0)
|
||||
lists := [][]*LSym{ctxt.defs, ctxt.hashed64defs, ctxt.hasheddefs, ctxt.nonpkgdefs}
|
||||
for _, list := range lists {
|
||||
for _, s := range list {
|
||||
w.Uint32(nreloc)
|
||||
nreloc += uint32(len(s.R))
|
||||
}
|
||||
}
|
||||
w.Uint32(nreloc)
|
||||
|
||||
// Symbol Info indexes
|
||||
h.Offsets[goobj.BlkAuxIdx] = w.Offset()
|
||||
naux := uint32(0)
|
||||
for _, list := range lists {
|
||||
for _, s := range list {
|
||||
w.Uint32(naux)
|
||||
naux += uint32(nAuxSym(s))
|
||||
}
|
||||
}
|
||||
w.Uint32(naux)
|
||||
|
||||
// Data indexes
|
||||
h.Offsets[goobj.BlkDataIdx] = w.Offset()
|
||||
dataOff := uint32(0)
|
||||
for _, list := range lists {
|
||||
for _, s := range list {
|
||||
w.Uint32(dataOff)
|
||||
dataOff += uint32(len(s.P))
|
||||
}
|
||||
}
|
||||
w.Uint32(dataOff)
|
||||
|
||||
// Relocs
|
||||
h.Offsets[goobj.BlkReloc] = w.Offset()
|
||||
for _, list := range lists {
|
||||
for _, s := range list {
|
||||
for i := range s.R {
|
||||
w.Reloc(&s.R[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Aux symbol info
|
||||
h.Offsets[goobj.BlkAux] = w.Offset()
|
||||
for _, list := range lists {
|
||||
for _, s := range list {
|
||||
w.Aux(s)
|
||||
}
|
||||
}
|
||||
|
||||
// Data
|
||||
h.Offsets[goobj.BlkData] = w.Offset()
|
||||
for _, list := range lists {
|
||||
for _, s := range list {
|
||||
w.Bytes(s.P)
|
||||
}
|
||||
}
|
||||
|
||||
// Pcdata
|
||||
h.Offsets[goobj.BlkPcdata] = w.Offset()
|
||||
for _, s := range ctxt.Text { // iteration order must match genFuncInfoSyms
|
||||
if s.Func != nil {
|
||||
pc := &s.Func.Pcln
|
||||
w.Bytes(pc.Pcsp.P)
|
||||
w.Bytes(pc.Pcfile.P)
|
||||
w.Bytes(pc.Pcline.P)
|
||||
w.Bytes(pc.Pcinline.P)
|
||||
for i := range pc.Pcdata {
|
||||
w.Bytes(pc.Pcdata[i].P)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Blocks used only by tools (objdump, nm).
|
||||
|
||||
// Referenced symbol names from other packages
|
||||
h.Offsets[goobj.BlkRefName] = w.Offset()
|
||||
w.refNames()
|
||||
|
||||
h.Offsets[goobj.BlkEnd] = w.Offset()
|
||||
|
||||
// Fix up block offsets in the header
|
||||
end := start + int64(w.Offset())
|
||||
b.MustSeek(start, 0)
|
||||
h.Write(w.Writer)
|
||||
b.MustSeek(end, 0)
|
||||
}
|
||||
|
||||
type writer struct {
|
||||
*goobj.Writer
|
||||
ctxt *Link
|
||||
pkgpath string // the package import path (escaped), "" if unknown
|
||||
pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx
|
||||
}
|
||||
|
||||
// prepare package index list
|
||||
func (w *writer) init() {
|
||||
w.pkglist = make([]string, len(w.ctxt.pkgIdx)+1)
|
||||
w.pkglist[0] = "" // dummy invalid package for index 0
|
||||
for pkg, i := range w.ctxt.pkgIdx {
|
||||
w.pkglist[i] = pkg
|
||||
}
|
||||
}
|
||||
|
||||
func (w *writer) StringTable() {
|
||||
w.AddString("")
|
||||
for _, p := range w.ctxt.Imports {
|
||||
w.AddString(p.Pkg)
|
||||
}
|
||||
for _, pkg := range w.pkglist {
|
||||
w.AddString(pkg)
|
||||
}
|
||||
w.ctxt.traverseSyms(traverseAll, func(s *LSym) {
|
||||
// TODO: this includes references of indexed symbols from other packages,
|
||||
// for which the linker doesn't need the name. Consider moving them to
|
||||
// a separate block (for tools only).
|
||||
if w.pkgpath != "" {
|
||||
s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
|
||||
}
|
||||
// Don't put names of builtins into the string table (to save
|
||||
// space).
|
||||
if s.PkgIdx == goobj.PkgIdxBuiltin {
|
||||
return
|
||||
}
|
||||
w.AddString(s.Name)
|
||||
})
|
||||
|
||||
// All filenames are in the postable.
|
||||
for _, f := range w.ctxt.PosTable.FileTable() {
|
||||
w.AddString(filepath.ToSlash(f))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *writer) Sym(s *LSym) {
|
||||
abi := uint16(s.ABI())
|
||||
if s.Static() {
|
||||
abi = goobj.SymABIstatic
|
||||
}
|
||||
flag := uint8(0)
|
||||
if s.DuplicateOK() {
|
||||
flag |= goobj.SymFlagDupok
|
||||
}
|
||||
if s.Local() {
|
||||
flag |= goobj.SymFlagLocal
|
||||
}
|
||||
if s.MakeTypelink() {
|
||||
flag |= goobj.SymFlagTypelink
|
||||
}
|
||||
if s.Leaf() {
|
||||
flag |= goobj.SymFlagLeaf
|
||||
}
|
||||
if s.NoSplit() {
|
||||
flag |= goobj.SymFlagNoSplit
|
||||
}
|
||||
if s.ReflectMethod() {
|
||||
flag |= goobj.SymFlagReflectMethod
|
||||
}
|
||||
if s.TopFrame() {
|
||||
flag |= goobj.SymFlagTopFrame
|
||||
}
|
||||
if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' && s.Type == objabi.SRODATA {
|
||||
flag |= goobj.SymFlagGoType
|
||||
}
|
||||
flag2 := uint8(0)
|
||||
if s.UsedInIface() {
|
||||
flag2 |= goobj.SymFlagUsedInIface
|
||||
}
|
||||
if strings.HasPrefix(s.Name, "go.itab.") && s.Type == objabi.SRODATA {
|
||||
flag2 |= goobj.SymFlagItab
|
||||
}
|
||||
name := s.Name
|
||||
if strings.HasPrefix(name, "gofile..") {
|
||||
name = filepath.ToSlash(name)
|
||||
}
|
||||
var align uint32
|
||||
if s.Func != nil {
|
||||
align = uint32(s.Func.Align)
|
||||
}
|
||||
if s.ContentAddressable() {
|
||||
// We generally assume data symbols are natually aligned,
|
||||
// except for strings. If we dedup a string symbol and a
|
||||
// non-string symbol with the same content, we should keep
|
||||
// the largest alignment.
|
||||
// TODO: maybe the compiler could set the alignment for all
|
||||
// data symbols more carefully.
|
||||
if s.Size != 0 && !strings.HasPrefix(s.Name, "go.string.") {
|
||||
switch {
|
||||
case w.ctxt.Arch.PtrSize == 8 && s.Size%8 == 0:
|
||||
align = 8
|
||||
case s.Size%4 == 0:
|
||||
align = 4
|
||||
case s.Size%2 == 0:
|
||||
align = 2
|
||||
}
|
||||
// don't bother setting align to 1.
|
||||
}
|
||||
}
|
||||
var o goobj.Sym
|
||||
o.SetName(name, w.Writer)
|
||||
o.SetABI(abi)
|
||||
o.SetType(uint8(s.Type))
|
||||
o.SetFlag(flag)
|
||||
o.SetFlag2(flag2)
|
||||
o.SetSiz(uint32(s.Size))
|
||||
o.SetAlign(align)
|
||||
o.Write(w.Writer)
|
||||
}
|
||||
|
||||
func (w *writer) Hash64(s *LSym) {
|
||||
if !s.ContentAddressable() || len(s.R) != 0 {
|
||||
panic("Hash of non-content-addresable symbol")
|
||||
}
|
||||
b := contentHash64(s)
|
||||
w.Bytes(b[:])
|
||||
}
|
||||
|
||||
func (w *writer) Hash(s *LSym) {
|
||||
if !s.ContentAddressable() {
|
||||
panic("Hash of non-content-addresable symbol")
|
||||
}
|
||||
b := w.contentHash(s)
|
||||
w.Bytes(b[:])
|
||||
}
|
||||
|
||||
func contentHash64(s *LSym) goobj.Hash64Type {
|
||||
var b goobj.Hash64Type
|
||||
copy(b[:], s.P)
|
||||
return b
|
||||
}
|
||||
|
||||
// Compute the content hash for a content-addressable symbol.
|
||||
// We build a content hash based on its content and relocations.
|
||||
// Depending on the category of the referenced symbol, we choose
|
||||
// different hash algorithms such that the hash is globally
|
||||
// consistent.
|
||||
// - For referenced content-addressable symbol, its content hash
|
||||
// is globally consistent.
|
||||
// - For package symbol and builtin symbol, its local index is
|
||||
// globally consistent.
|
||||
// - For non-package symbol, its fully-expanded name is globally
|
||||
// consistent. For now, we require we know the current package
|
||||
// path so we can always expand symbol names. (Otherwise,
|
||||
// symbols with relocations are not considered hashable.)
|
||||
//
|
||||
// For now, we assume there is no circular dependencies among
|
||||
// hashed symbols.
|
||||
func (w *writer) contentHash(s *LSym) goobj.HashType {
|
||||
h := sha1.New()
|
||||
// The compiler trims trailing zeros _sometimes_. We just do
|
||||
// it always.
|
||||
h.Write(bytes.TrimRight(s.P, "\x00"))
|
||||
var tmp [14]byte
|
||||
for i := range s.R {
|
||||
r := &s.R[i]
|
||||
binary.LittleEndian.PutUint32(tmp[:4], uint32(r.Off))
|
||||
tmp[4] = r.Siz
|
||||
tmp[5] = uint8(r.Type)
|
||||
binary.LittleEndian.PutUint64(tmp[6:14], uint64(r.Add))
|
||||
h.Write(tmp[:])
|
||||
rs := r.Sym
|
||||
switch rs.PkgIdx {
|
||||
case goobj.PkgIdxHashed64:
|
||||
h.Write([]byte{0})
|
||||
t := contentHash64(rs)
|
||||
h.Write(t[:])
|
||||
case goobj.PkgIdxHashed:
|
||||
h.Write([]byte{1})
|
||||
t := w.contentHash(rs)
|
||||
h.Write(t[:])
|
||||
case goobj.PkgIdxNone:
|
||||
h.Write([]byte{2})
|
||||
io.WriteString(h, rs.Name) // name is already expanded at this point
|
||||
case goobj.PkgIdxBuiltin:
|
||||
h.Write([]byte{3})
|
||||
binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
|
||||
h.Write(tmp[:4])
|
||||
case goobj.PkgIdxSelf:
|
||||
io.WriteString(h, w.pkgpath)
|
||||
binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
|
||||
h.Write(tmp[:4])
|
||||
default:
|
||||
io.WriteString(h, rs.Pkg)
|
||||
binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
|
||||
h.Write(tmp[:4])
|
||||
}
|
||||
}
|
||||
var b goobj.HashType
|
||||
copy(b[:], h.Sum(nil))
|
||||
return b
|
||||
}
|
||||
|
||||
func makeSymRef(s *LSym) goobj.SymRef {
|
||||
if s == nil {
|
||||
return goobj.SymRef{}
|
||||
}
|
||||
if s.PkgIdx == 0 || !s.Indexed() {
|
||||
fmt.Printf("unindexed symbol reference: %v\n", s)
|
||||
panic("unindexed symbol reference")
|
||||
}
|
||||
return goobj.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)}
|
||||
}
|
||||
|
||||
func (w *writer) Reloc(r *Reloc) {
|
||||
var o goobj.Reloc
|
||||
o.SetOff(r.Off)
|
||||
o.SetSiz(r.Siz)
|
||||
o.SetType(uint8(r.Type))
|
||||
o.SetAdd(r.Add)
|
||||
o.SetSym(makeSymRef(r.Sym))
|
||||
o.Write(w.Writer)
|
||||
}
|
||||
|
||||
func (w *writer) aux1(typ uint8, rs *LSym) {
|
||||
var o goobj.Aux
|
||||
o.SetType(typ)
|
||||
o.SetSym(makeSymRef(rs))
|
||||
o.Write(w.Writer)
|
||||
}
|
||||
|
||||
func (w *writer) Aux(s *LSym) {
|
||||
if s.Gotype != nil {
|
||||
w.aux1(goobj.AuxGotype, s.Gotype)
|
||||
}
|
||||
if s.Func != nil {
|
||||
w.aux1(goobj.AuxFuncInfo, s.Func.FuncInfoSym)
|
||||
|
||||
for _, d := range s.Func.Pcln.Funcdata {
|
||||
w.aux1(goobj.AuxFuncdata, d)
|
||||
}
|
||||
|
||||
if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
|
||||
w.aux1(goobj.AuxDwarfInfo, s.Func.dwarfInfoSym)
|
||||
}
|
||||
if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
|
||||
w.aux1(goobj.AuxDwarfLoc, s.Func.dwarfLocSym)
|
||||
}
|
||||
if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
|
||||
w.aux1(goobj.AuxDwarfRanges, s.Func.dwarfRangesSym)
|
||||
}
|
||||
if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
|
||||
w.aux1(goobj.AuxDwarfLines, s.Func.dwarfDebugLinesSym)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Emits flags of referenced indexed symbols.
|
||||
func (w *writer) refFlags() {
|
||||
seen := make(map[*LSym]bool)
|
||||
w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
|
||||
switch rs.PkgIdx {
|
||||
case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
|
||||
return
|
||||
case goobj.PkgIdxInvalid:
|
||||
panic("unindexed symbol reference")
|
||||
}
|
||||
if seen[rs] {
|
||||
return
|
||||
}
|
||||
seen[rs] = true
|
||||
symref := makeSymRef(rs)
|
||||
flag2 := uint8(0)
|
||||
if rs.UsedInIface() {
|
||||
flag2 |= goobj.SymFlagUsedInIface
|
||||
}
|
||||
if flag2 == 0 {
|
||||
return // no need to write zero flags
|
||||
}
|
||||
var o goobj.RefFlags
|
||||
o.SetSym(symref)
|
||||
o.SetFlag2(flag2)
|
||||
o.Write(w.Writer)
|
||||
})
|
||||
}
|
||||
|
||||
// Emits names of referenced indexed symbols, used by tools (objdump, nm)
|
||||
// only.
|
||||
func (w *writer) refNames() {
|
||||
seen := make(map[*LSym]bool)
|
||||
w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
|
||||
switch rs.PkgIdx {
|
||||
case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
|
||||
return
|
||||
case goobj.PkgIdxInvalid:
|
||||
panic("unindexed symbol reference")
|
||||
}
|
||||
if seen[rs] {
|
||||
return
|
||||
}
|
||||
seen[rs] = true
|
||||
symref := makeSymRef(rs)
|
||||
var o goobj.RefName
|
||||
o.SetSym(symref)
|
||||
o.SetName(rs.Name, w.Writer)
|
||||
o.Write(w.Writer)
|
||||
})
|
||||
// TODO: output in sorted order?
|
||||
// Currently tools (cmd/internal/goobj package) doesn't use mmap,
|
||||
// and it just read it into a map in memory upfront. If it uses
|
||||
// mmap, if the output is sorted, it probably could avoid reading
|
||||
// into memory and just do lookups in the mmap'd object file.
|
||||
}
|
||||
|
||||
// return the number of aux symbols s have.
|
||||
func nAuxSym(s *LSym) int {
|
||||
n := 0
|
||||
if s.Gotype != nil {
|
||||
n++
|
||||
}
|
||||
if s.Func != nil {
|
||||
// FuncInfo is an aux symbol, each Funcdata is an aux symbol
|
||||
n += 1 + len(s.Func.Pcln.Funcdata)
|
||||
if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
|
||||
n++
|
||||
}
|
||||
if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
|
||||
n++
|
||||
}
|
||||
if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
|
||||
n++
|
||||
}
|
||||
if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// generate symbols for FuncInfo.
|
||||
func genFuncInfoSyms(ctxt *Link) {
|
||||
infosyms := make([]*LSym, 0, len(ctxt.Text))
|
||||
var pcdataoff uint32
|
||||
var b bytes.Buffer
|
||||
symidx := int32(len(ctxt.defs))
|
||||
for _, s := range ctxt.Text {
|
||||
if s.Func == nil {
|
||||
continue
|
||||
}
|
||||
o := goobj.FuncInfo{
|
||||
Args: uint32(s.Func.Args),
|
||||
Locals: uint32(s.Func.Locals),
|
||||
FuncID: objabi.FuncID(s.Func.FuncID),
|
||||
}
|
||||
pc := &s.Func.Pcln
|
||||
o.Pcsp = pcdataoff
|
||||
pcdataoff += uint32(len(pc.Pcsp.P))
|
||||
o.Pcfile = pcdataoff
|
||||
pcdataoff += uint32(len(pc.Pcfile.P))
|
||||
o.Pcline = pcdataoff
|
||||
pcdataoff += uint32(len(pc.Pcline.P))
|
||||
o.Pcinline = pcdataoff
|
||||
pcdataoff += uint32(len(pc.Pcinline.P))
|
||||
o.Pcdata = make([]uint32, len(pc.Pcdata))
|
||||
for i, pcd := range pc.Pcdata {
|
||||
o.Pcdata[i] = pcdataoff
|
||||
pcdataoff += uint32(len(pcd.P))
|
||||
}
|
||||
o.PcdataEnd = pcdataoff
|
||||
o.Funcdataoff = make([]uint32, len(pc.Funcdataoff))
|
||||
for i, x := range pc.Funcdataoff {
|
||||
o.Funcdataoff[i] = uint32(x)
|
||||
}
|
||||
i := 0
|
||||
o.File = make([]goobj.CUFileIndex, len(pc.UsedFiles))
|
||||
for f := range pc.UsedFiles {
|
||||
o.File[i] = f
|
||||
i++
|
||||
}
|
||||
sort.Slice(o.File, func(i, j int) bool { return o.File[i] < o.File[j] })
|
||||
o.InlTree = make([]goobj.InlTreeNode, len(pc.InlTree.nodes))
|
||||
for i, inl := range pc.InlTree.nodes {
|
||||
f, l := getFileIndexAndLine(ctxt, inl.Pos)
|
||||
o.InlTree[i] = goobj.InlTreeNode{
|
||||
Parent: int32(inl.Parent),
|
||||
File: goobj.CUFileIndex(f),
|
||||
Line: l,
|
||||
Func: makeSymRef(inl.Func),
|
||||
ParentPC: inl.ParentPC,
|
||||
}
|
||||
}
|
||||
|
||||
o.Write(&b)
|
||||
isym := &LSym{
|
||||
Type: objabi.SDATA, // for now, I don't think it matters
|
||||
PkgIdx: goobj.PkgIdxSelf,
|
||||
SymIdx: symidx,
|
||||
P: append([]byte(nil), b.Bytes()...),
|
||||
}
|
||||
isym.Set(AttrIndexed, true)
|
||||
symidx++
|
||||
infosyms = append(infosyms, isym)
|
||||
s.Func.FuncInfoSym = isym
|
||||
b.Reset()
|
||||
|
||||
dwsyms := []*LSym{s.Func.dwarfRangesSym, s.Func.dwarfLocSym, s.Func.dwarfDebugLinesSym, s.Func.dwarfInfoSym}
|
||||
for _, s := range dwsyms {
|
||||
if s == nil || s.Size == 0 {
|
||||
continue
|
||||
}
|
||||
s.PkgIdx = goobj.PkgIdxSelf
|
||||
s.SymIdx = symidx
|
||||
s.Set(AttrIndexed, true)
|
||||
symidx++
|
||||
infosyms = append(infosyms, s)
|
||||
}
|
||||
}
|
||||
ctxt.defs = append(ctxt.defs, infosyms...)
|
||||
}
|
||||
|
||||
// debugDumpAux is a dumper for selected aux symbols.
|
||||
func writeAuxSymDebug(ctxt *Link, par *LSym, aux *LSym) {
|
||||
// Most aux symbols (ex: funcdata) are not interesting--
|
||||
// pick out just the DWARF ones for now.
|
||||
if aux.Type != objabi.SDWARFLOC &&
|
||||
aux.Type != objabi.SDWARFFCN &&
|
||||
aux.Type != objabi.SDWARFABSFCN &&
|
||||
aux.Type != objabi.SDWARFLINES &&
|
||||
aux.Type != objabi.SDWARFRANGE {
|
||||
return
|
||||
}
|
||||
ctxt.writeSymDebugNamed(aux, "aux for "+par.Name)
|
||||
}
|
||||
|
||||
func debugAsmEmit(ctxt *Link) {
|
||||
if ctxt.Debugasm > 0 {
|
||||
ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
|
||||
if ctxt.Debugasm > 1 {
|
||||
fn := func(par *LSym, aux *LSym) {
|
||||
writeAuxSymDebug(ctxt, par, aux)
|
||||
}
|
||||
ctxt.traverseAuxSyms(traverseAux, fn)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue