// FuncInfo is serialized as a symbol (aux symbol). The symbol data is
// the binary encoding of the struct below.
-//
-// TODO: make each pcdata a separate symbol?
type FuncInfo struct {
Args uint32
Locals uint32
FuncID objabi.FuncID
FuncFlag objabi.FuncFlag
- Pcsp SymRef
- Pcfile SymRef
- Pcline SymRef
- Pcinline SymRef
- Pcdata []SymRef
Funcdataoff []uint32
File []CUFileIndex
binary.LittleEndian.PutUint32(b[:], x)
w.Write(b[:])
}
- writeSymRef := func(s SymRef) {
- writeUint32(s.PkgIdx)
- writeUint32(s.SymIdx)
- }
writeUint32(a.Args)
writeUint32(a.Locals)
writeUint8(uint8(a.FuncFlag))
writeUint8(0) // pad to uint32 boundary
writeUint8(0)
- writeSymRef(a.Pcsp)
- writeSymRef(a.Pcfile)
- writeSymRef(a.Pcline)
- writeSymRef(a.Pcinline)
- writeUint32(uint32(len(a.Pcdata)))
- for _, sym := range a.Pcdata {
- writeSymRef(sym)
- }
writeUint32(uint32(len(a.Funcdataoff)))
for _, x := range a.Funcdataoff {
// corresponding "off" field stores the byte offset of the start of
// the items in question.
type FuncInfoLengths struct {
- NumPcdata uint32
- PcdataOff uint32
NumFuncdataoff uint32
FuncdataoffOff uint32
NumFile uint32
func (*FuncInfo) ReadFuncInfoLengths(b []byte) FuncInfoLengths {
var result FuncInfoLengths
- // Offset to the number of pcdata values. This value is determined by counting
- // the number of bytes until we write pcdata to the file.
- const numpcdataOff = 44
- result.NumPcdata = binary.LittleEndian.Uint32(b[numpcdataOff:])
- result.PcdataOff = numpcdataOff + 4
-
- numfuncdataoffOff := result.PcdataOff + 8*result.NumPcdata
+ // Offset to the number of funcdataoff values. This value is determined by counting
+ // the number of bytes until we write funcdataoff to the file.
+ const numfuncdataoffOff = 12
result.NumFuncdataoff = binary.LittleEndian.Uint32(b[numfuncdataoffOff:])
result.FuncdataoffOff = numfuncdataoffOff + 4
func (*FuncInfo) ReadFuncFlag(b []byte) objabi.FuncFlag { return objabi.FuncFlag(b[9]) }
-func (*FuncInfo) ReadPcsp(b []byte) SymRef {
- return SymRef{binary.LittleEndian.Uint32(b[12:]), binary.LittleEndian.Uint32(b[16:])}
-}
-
-func (*FuncInfo) ReadPcfile(b []byte) SymRef {
- return SymRef{binary.LittleEndian.Uint32(b[20:]), binary.LittleEndian.Uint32(b[24:])}
-}
-
-func (*FuncInfo) ReadPcline(b []byte) SymRef {
- return SymRef{binary.LittleEndian.Uint32(b[28:]), binary.LittleEndian.Uint32(b[32:])}
-}
-
-func (*FuncInfo) ReadPcinline(b []byte) SymRef {
- return SymRef{binary.LittleEndian.Uint32(b[36:]), binary.LittleEndian.Uint32(b[40:])}
-}
-
-func (*FuncInfo) ReadPcdata(b []byte) []SymRef {
- syms := make([]SymRef, binary.LittleEndian.Uint32(b[44:]))
- for i := range syms {
- syms[i] = SymRef{binary.LittleEndian.Uint32(b[48+i*8:]), binary.LittleEndian.Uint32(b[52+i*8:])}
- }
- return syms
-}
-
func (*FuncInfo) ReadFuncdataoff(b []byte, funcdataofffoff uint32, k uint32) int64 {
return int64(binary.LittleEndian.Uint32(b[funcdataofffoff+4*k:]))
}
FuncFlag: fn.FuncFlag,
}
pc := &fn.Pcln
- o.Pcsp = makeSymRef(pc.Pcsp)
- o.Pcfile = makeSymRef(pc.Pcfile)
- o.Pcline = makeSymRef(pc.Pcline)
- o.Pcinline = makeSymRef(pc.Pcinline)
- o.Pcdata = make([]goobj.SymRef, len(pc.Pcdata))
- for i, pcSym := range pc.Pcdata {
- o.Pcdata[i] = makeSymRef(pcSym)
- }
o.Funcdataoff = make([]uint32, len(pc.Funcdataoff))
for i, x := range pc.Funcdataoff {
o.Funcdataoff[i] = uint32(x)
if !fi.Valid() {
continue
}
- fpcsp := fi.Pcsp()
+ fpcsp := d.ldr.Pcsp(s)
// Emit a FDE, Section 6.4.1.
// First build the section contents into a byte buffer.
var ch1 chain
pcsp := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
ri := 0
- for pcsp.Init(ldr.Data(info.Pcsp())); !pcsp.Done; pcsp.Next() {
+ for pcsp.Init(ldr.Data(ldr.Pcsp(s))); !pcsp.Done; pcsp.Next() {
// pcsp.value is in effect for [pcsp.pc, pcsp.nextpc).
// Check stack size in effect for this span.
seen[pcSym] = struct{}{}
}
}
+ var pcsp, pcline, pcfile, pcinline loader.Sym
+ var pcdata []loader.Sym
for _, s := range funcs {
fi := ldr.FuncInfo(s)
if !fi.Valid() {
continue
}
fi.Preload()
+ pcsp, pcfile, pcline, pcinline, pcdata = ldr.PcdataAuxs(s, pcdata)
- pcSyms := []loader.Sym{fi.Pcsp(), fi.Pcfile(), fi.Pcline()}
+ pcSyms := []loader.Sym{pcsp, pcfile, pcline}
for _, pcSym := range pcSyms {
saveOffset(pcSym)
}
- for _, pcSym := range fi.Pcdata() {
+ for _, pcSym := range pcdata {
saveOffset(pcSym)
}
if fi.NumInlTree() > 0 {
- saveOffset(fi.Pcinline())
+ saveOffset(pcinline)
}
}
// numPCData returns the number of PCData syms for the FuncInfo.
// NB: Preload must be called on valid FuncInfos before calling this function.
-func numPCData(fi loader.FuncInfo) uint32 {
+func numPCData(ldr *loader.Loader, s loader.Sym, fi loader.FuncInfo) uint32 {
if !fi.Valid() {
return 0
}
- numPCData := uint32(len(fi.Pcdata()))
+ numPCData := uint32(ldr.NumPcdata(s))
if fi.NumInlTree() > 0 {
if numPCData < objabi.PCDATA_InlTreeIndex+1 {
numPCData = objabi.PCDATA_InlTreeIndex + 1
numFuncData = objabi.FUNCDATA_InlTree + 1
}
}
- size += int64(numPCData(fi) * 4)
+ size += int64(numPCData(ldr, s, fi) * 4)
if numFuncData > 0 { // Func data is aligned.
size = Rnd(size, int64(ctxt.Arch.PtrSize))
}
// Missing funcdata will be 0 (nil pointer).
funcdata, funcdataoff := funcData(fi, inlSyms[s], funcdata, funcdataoff)
if len(funcdata) > 0 {
- off := int64(startLocations[i] + state.funcSize + numPCData(fi)*4)
+ off := int64(startLocations[i] + state.funcSize + numPCData(ldr, s, fi)*4)
off = Rnd(off, int64(ctxt.Arch.PtrSize))
for j := range funcdata {
dataoff := off + int64(ctxt.Arch.PtrSize*j)
ldr := ctxt.loader
deferReturnSym := ldr.Lookup("runtime.deferreturn", abiInternalVer)
funcdata, funcdataoff := []loader.Sym{}, []int64{}
+ var pcsp, pcfile, pcline, pcinline loader.Sym
+ var pcdata []loader.Sym
// Write the individual func objects.
for i, s := range funcs {
fi := ldr.FuncInfo(s)
if fi.Valid() {
fi.Preload()
+ pcsp, pcfile, pcline, pcinline, pcdata = ldr.PcdataAuxs(s, pcdata)
}
// Note we skip the space for the entry value -- that's handled in
// pcdata
if fi.Valid() {
- off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(ldr.SymValue(fi.Pcsp()))))
- off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(ldr.SymValue(fi.Pcfile()))))
- off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(ldr.SymValue(fi.Pcline()))))
+ off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(ldr.SymValue(pcsp))))
+ off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(ldr.SymValue(pcfile))))
+ off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(ldr.SymValue(pcline))))
} else {
off += 12
}
- off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(numPCData(fi))))
+ off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(numPCData(ldr, s, fi))))
// Store the offset to compilation unit's file table.
cuIdx := ^uint32(0)
// Output the pcdata.
if fi.Valid() {
- for j, pcSym := range fi.Pcdata() {
+ for j, pcSym := range pcdata {
sb.SetUint32(ctxt.Arch, int64(off+uint32(j*4)), uint32(ldr.SymValue(pcSym)))
}
if fi.NumInlTree() > 0 {
- sb.SetUint32(ctxt.Arch, int64(off+objabi.PCDATA_InlTreeIndex*4), uint32(ldr.SymValue(fi.Pcinline())))
+ sb.SetUint32(ctxt.Arch, int64(off+objabi.PCDATA_InlTreeIndex*4), uint32(ldr.SymValue(pcinline)))
}
}
}
// approach would be to check for gotype during preload and copy the
// results in to a map (might want to try this at some point and see
// if it helps speed things up).
-func (l *Loader) SymGoType(i Sym) Sym {
- var r *oReader
- var auxs []goobj.Aux
- if l.IsExternal(i) {
- pp := l.getPayload(i)
- r = l.objs[pp.objidx].r
- auxs = pp.auxs
- } else {
- var li uint32
- r, li = l.toLocal(i)
- auxs = r.Auxs(li)
- }
- for j := range auxs {
- a := &auxs[j]
- switch a.Type() {
- case goobj.AuxGotype:
- return l.resolve(r, a.Sym())
- }
- }
- return 0
-}
+func (l *Loader) SymGoType(i Sym) Sym { return l.aux1(i, goobj.AuxGotype) }
// SymUnit returns the compilation unit for a given symbol (which will
// typically be nil for external or linker-manufactured symbols).
}
}
+func (l *Loader) auxs(i Sym) (*oReader, []goobj.Aux) {
+ if l.IsExternal(i) {
+ pp := l.getPayload(i)
+ return l.objs[pp.objidx].r, pp.auxs
+ } else {
+ r, li := l.toLocal(i)
+ return r, r.Auxs(li)
+ }
+}
+
+// Returns a specific aux symbol of type t for symbol i.
+func (l *Loader) aux1(i Sym, t uint8) Sym {
+ r, auxs := l.auxs(i)
+ for j := range auxs {
+ a := &auxs[j]
+ if a.Type() == t {
+ return l.resolve(r, a.Sym())
+ }
+ }
+ return 0
+}
+
+func (l *Loader) Pcsp(i Sym) Sym { return l.aux1(i, goobj.AuxPcsp) }
+
+// Returns all aux symbols of per-PC data for symbol i.
+// tmp is a scratch space for the pcdata slice.
+func (l *Loader) PcdataAuxs(i Sym, tmp []Sym) (pcsp, pcfile, pcline, pcinline Sym, pcdata []Sym) {
+ pcdata = tmp[:0]
+ r, auxs := l.auxs(i)
+ for j := range auxs {
+ a := &auxs[j]
+ switch a.Type() {
+ case goobj.AuxPcsp:
+ pcsp = l.resolve(r, a.Sym())
+ case goobj.AuxPcline:
+ pcline = l.resolve(r, a.Sym())
+ case goobj.AuxPcfile:
+ pcfile = l.resolve(r, a.Sym())
+ case goobj.AuxPcinline:
+ pcinline = l.resolve(r, a.Sym())
+ case goobj.AuxPcdata:
+ pcdata = append(pcdata, l.resolve(r, a.Sym()))
+ }
+ }
+ return
+}
+
+// Returns the number of pcdata for symbol i.
+func (l *Loader) NumPcdata(i Sym) int {
+ n := 0
+ _, auxs := l.auxs(i)
+ for j := range auxs {
+ a := &auxs[j]
+ if a.Type() == goobj.AuxPcdata {
+ n++
+ }
+ }
+ return n
+}
+
// FuncInfo provides hooks to access goobj.FuncInfo in the objects.
type FuncInfo struct {
l *Loader
return (*goobj.FuncInfo)(nil).ReadFuncFlag(fi.data)
}
-func (fi *FuncInfo) Pcsp() Sym {
- sym := (*goobj.FuncInfo)(nil).ReadPcsp(fi.data)
- return fi.l.resolve(fi.r, sym)
-}
-
-func (fi *FuncInfo) Pcfile() Sym {
- sym := (*goobj.FuncInfo)(nil).ReadPcfile(fi.data)
- return fi.l.resolve(fi.r, sym)
-}
-
-func (fi *FuncInfo) Pcline() Sym {
- sym := (*goobj.FuncInfo)(nil).ReadPcline(fi.data)
- return fi.l.resolve(fi.r, sym)
-}
-
-func (fi *FuncInfo) Pcinline() Sym {
- sym := (*goobj.FuncInfo)(nil).ReadPcinline(fi.data)
- return fi.l.resolve(fi.r, sym)
-}
-
// Preload has to be called prior to invoking the various methods
// below related to pcdata, funcdataoff, files, and inltree nodes.
func (fi *FuncInfo) Preload() {
fi.lengths = (*goobj.FuncInfo)(nil).ReadFuncInfoLengths(fi.data)
}
-func (fi *FuncInfo) Pcdata() []Sym {
- if !fi.lengths.Initialized {
- panic("need to call Preload first")
- }
- syms := (*goobj.FuncInfo)(nil).ReadPcdata(fi.data)
- ret := make([]Sym, len(syms))
- for i := range ret {
- ret[i] = fi.l.resolve(fi.r, syms[i])
- }
- return ret
-}
-
func (fi *FuncInfo) NumFuncdataoff() uint32 {
if !fi.lengths.Initialized {
panic("need to call Preload first")
}
func (l *Loader) FuncInfo(i Sym) FuncInfo {
- var r *oReader
- var auxs []goobj.Aux
- if l.IsExternal(i) {
- pp := l.getPayload(i)
- if pp.objidx == 0 {
- return FuncInfo{}
- }
- r = l.objs[pp.objidx].r
- auxs = pp.auxs
- } else {
- var li uint32
- r, li = l.toLocal(i)
- auxs = r.Auxs(li)
- }
+ r, auxs := l.auxs(i)
for j := range auxs {
a := &auxs[j]
if a.Type() == goobj.AuxFuncInfo {