cmd/link: access pcdata via aux symbols

Pcdata are now separate aux symbols. Read them from aux, instead
of using funcinfo.

Now we can remove pcdata fields from funcinfo.

Change-Id: Ie65e3962edecc0f39127a5f6963dc59d1f141e67
Reviewed-on: https://go-review.googlesource.com/c/go/+/352893
Trust: Cherry Mui <cherryyz@google.com>
Run-TryBot: Cherry Mui <cherryyz@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
Cherry Mui 2021-09-28 16:20:29 -04:00
parent 435718edd9
commit 587b3c1192
6 changed files with 86 additions and 142 deletions

View file

@ -16,19 +16,12 @@ type CUFileIndex uint32
// 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
@ -44,10 +37,6 @@ func (a *FuncInfo) Write(w *bytes.Buffer) {
binary.LittleEndian.PutUint32(b[:], x)
w.Write(b[:])
}
writeSymRef := func(s SymRef) {
writeUint32(s.PkgIdx)
writeUint32(s.SymIdx)
}
writeUint32(a.Args)
writeUint32(a.Locals)
@ -55,14 +44,6 @@ func (a *FuncInfo) Write(w *bytes.Buffer) {
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 {
@ -84,8 +65,6 @@ func (a *FuncInfo) Write(w *bytes.Buffer) {
// 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
@ -98,13 +77,9 @@ type FuncInfoLengths struct {
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
@ -129,30 +104,6 @@ func (*FuncInfo) ReadFuncID(b []byte) objabi.FuncID { return objabi.FuncID(b[8])
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:]))
}

View file

@ -671,14 +671,6 @@ func genFuncInfoSyms(ctxt *Link) {
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)

View file

@ -1417,7 +1417,7 @@ func (d *dwctxt) writeframes(fs loader.Sym) dwarfSecInfo {
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.

View file

@ -2310,7 +2310,7 @@ func (sc *stkChk) check(up *chain, depth int) int {
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.

View file

@ -485,22 +485,25 @@ func (state *pclntab) generatePctab(ctxt *Link, funcs []loader.Sym) {
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)
}
}
@ -521,11 +524,11 @@ func (state *pclntab) generatePctab(ctxt *Link, funcs []loader.Sym) {
// 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
@ -676,7 +679,7 @@ func (state pclntab) calculateFunctabSize(ctxt *Link, funcs []loader.Sym) (int64
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))
}
@ -747,7 +750,7 @@ func (state *pclntab) writeFuncData(ctxt *Link, sb *loader.SymbolBuilder, funcs
// 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)
@ -767,12 +770,15 @@ func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSym
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
@ -801,13 +807,13 @@ func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSym
// 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)
@ -838,11 +844,11 @@ func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSym
// 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)))
}
}
}

View file

@ -1532,27 +1532,7 @@ func (l *Loader) DynidSyms() []Sym {
// 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).
@ -1890,6 +1870,66 @@ func (l *Loader) relocs(r *oReader, li uint32) Relocs {
}
}
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
@ -1917,44 +1957,12 @@ func (fi *FuncInfo) FuncFlag() objabi.FuncFlag {
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")
@ -2038,20 +2046,7 @@ func (fi *FuncInfo) InlTree(k int) InlTreeNode {
}
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 {