mirror of
https://github.com/golang/go
synced 2024-11-23 09:10:08 -07:00
cmd/link: merge branch 'dev.link' into master
no conflicts. Change-Id: Ic40ad81f1e491d6ceb72fbb66ad7919ad2b34a3e
This commit is contained in:
commit
97b46b4ade
@ -23,12 +23,11 @@ type FuncInfo struct {
|
||||
Locals uint32
|
||||
FuncID objabi.FuncID
|
||||
|
||||
Pcsp uint32
|
||||
Pcfile uint32
|
||||
Pcline uint32
|
||||
Pcinline uint32
|
||||
Pcdata []uint32
|
||||
PcdataEnd uint32
|
||||
Pcsp SymRef
|
||||
Pcfile SymRef
|
||||
Pcline SymRef
|
||||
Pcinline SymRef
|
||||
Pcdata []SymRef
|
||||
Funcdataoff []uint32
|
||||
File []CUFileIndex
|
||||
|
||||
@ -41,20 +40,24 @@ 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)
|
||||
writeUint32(uint32(a.FuncID))
|
||||
|
||||
writeUint32(a.Pcsp)
|
||||
writeUint32(a.Pcfile)
|
||||
writeUint32(a.Pcline)
|
||||
writeUint32(a.Pcinline)
|
||||
writeSymRef(a.Pcsp)
|
||||
writeSymRef(a.Pcfile)
|
||||
writeSymRef(a.Pcline)
|
||||
writeSymRef(a.Pcinline)
|
||||
writeUint32(uint32(len(a.Pcdata)))
|
||||
for _, x := range a.Pcdata {
|
||||
writeUint32(x)
|
||||
for _, sym := range a.Pcdata {
|
||||
writeSymRef(sym)
|
||||
}
|
||||
writeUint32(a.PcdataEnd)
|
||||
|
||||
writeUint32(uint32(len(a.Funcdataoff)))
|
||||
for _, x := range a.Funcdataoff {
|
||||
writeUint32(x)
|
||||
@ -75,21 +78,23 @@ func (a *FuncInfo) Read(b []byte) {
|
||||
b = b[4:]
|
||||
return x
|
||||
}
|
||||
readSymIdx := func() SymRef {
|
||||
return SymRef{readUint32(), readUint32()}
|
||||
}
|
||||
|
||||
a.Args = readUint32()
|
||||
a.Locals = readUint32()
|
||||
a.FuncID = objabi.FuncID(readUint32())
|
||||
|
||||
a.Pcsp = readUint32()
|
||||
a.Pcfile = readUint32()
|
||||
a.Pcline = readUint32()
|
||||
a.Pcinline = readUint32()
|
||||
pcdatalen := readUint32()
|
||||
a.Pcdata = make([]uint32, pcdatalen)
|
||||
a.Pcsp = readSymIdx()
|
||||
a.Pcfile = readSymIdx()
|
||||
a.Pcline = readSymIdx()
|
||||
a.Pcinline = readSymIdx()
|
||||
a.Pcdata = make([]SymRef, readUint32())
|
||||
for i := range a.Pcdata {
|
||||
a.Pcdata[i] = readUint32()
|
||||
a.Pcdata[i] = readSymIdx()
|
||||
}
|
||||
a.PcdataEnd = readUint32()
|
||||
|
||||
funcdataofflen := readUint32()
|
||||
a.Funcdataoff = make([]uint32, funcdataofflen)
|
||||
for i := range a.Funcdataoff {
|
||||
@ -127,11 +132,13 @@ type FuncInfoLengths struct {
|
||||
func (*FuncInfo) ReadFuncInfoLengths(b []byte) FuncInfoLengths {
|
||||
var result FuncInfoLengths
|
||||
|
||||
const numpcdataOff = 28
|
||||
// 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 + 4*(result.NumPcdata+1)
|
||||
numfuncdataoffOff := result.PcdataOff + 8*result.NumPcdata
|
||||
result.NumFuncdataoff = binary.LittleEndian.Uint32(b[numfuncdataoffOff:])
|
||||
result.FuncdataoffOff = numfuncdataoffOff + 4
|
||||
|
||||
@ -154,29 +161,28 @@ func (*FuncInfo) ReadLocals(b []byte) uint32 { return binary.LittleEndian.Uint32
|
||||
|
||||
func (*FuncInfo) ReadFuncID(b []byte) uint32 { return binary.LittleEndian.Uint32(b[8:]) }
|
||||
|
||||
// return start and end offsets.
|
||||
func (*FuncInfo) ReadPcsp(b []byte) (uint32, uint32) {
|
||||
return binary.LittleEndian.Uint32(b[12:]), binary.LittleEndian.Uint32(b[16:])
|
||||
func (*FuncInfo) ReadPcsp(b []byte) SymRef {
|
||||
return SymRef{binary.LittleEndian.Uint32(b[12:]), binary.LittleEndian.Uint32(b[16:])}
|
||||
}
|
||||
|
||||
// return start and end offsets.
|
||||
func (*FuncInfo) ReadPcfile(b []byte) (uint32, uint32) {
|
||||
return binary.LittleEndian.Uint32(b[16:]), binary.LittleEndian.Uint32(b[20:])
|
||||
func (*FuncInfo) ReadPcfile(b []byte) SymRef {
|
||||
return SymRef{binary.LittleEndian.Uint32(b[20:]), binary.LittleEndian.Uint32(b[24:])}
|
||||
}
|
||||
|
||||
// return start and end offsets.
|
||||
func (*FuncInfo) ReadPcline(b []byte) (uint32, uint32) {
|
||||
return 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:])}
|
||||
}
|
||||
|
||||
// return start and end offsets.
|
||||
func (*FuncInfo) ReadPcinline(b []byte, pcdataoffset uint32) (uint32, uint32) {
|
||||
return binary.LittleEndian.Uint32(b[24:]), binary.LittleEndian.Uint32(b[pcdataoffset:])
|
||||
func (*FuncInfo) ReadPcinline(b []byte) SymRef {
|
||||
return SymRef{binary.LittleEndian.Uint32(b[36:]), binary.LittleEndian.Uint32(b[40:])}
|
||||
}
|
||||
|
||||
// return start and end offsets.
|
||||
func (*FuncInfo) ReadPcdata(b []byte, pcdataoffset uint32, k uint32) (uint32, uint32) {
|
||||
return binary.LittleEndian.Uint32(b[pcdataoffset+4*k:]), binary.LittleEndian.Uint32(b[pcdataoffset+4+4*k:])
|
||||
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 {
|
||||
|
@ -433,8 +433,11 @@ const (
|
||||
AuxDwarfLoc
|
||||
AuxDwarfRanges
|
||||
AuxDwarfLines
|
||||
|
||||
// TODO: more. Pcdata?
|
||||
AuxPcsp
|
||||
AuxPcfile
|
||||
AuxPcline
|
||||
AuxPcinline
|
||||
AuxPcdata
|
||||
)
|
||||
|
||||
func (a *Aux) Type() uint8 { return a[0] }
|
||||
@ -839,11 +842,6 @@ func (r *Reader) Data(i uint32) []byte {
|
||||
return r.BytesAt(base+off, int(end-off))
|
||||
}
|
||||
|
||||
// AuxDataBase returns the base offset of the aux data block.
|
||||
func (r *Reader) PcdataBase() uint32 {
|
||||
return r.h.Offsets[BlkPcdata]
|
||||
}
|
||||
|
||||
// NRefName returns the number of referenced symbol names.
|
||||
func (r *Reader) NRefName() int {
|
||||
return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize
|
||||
|
@ -634,11 +634,12 @@ func (s *LSym) CanBeAnSSASym() {
|
||||
}
|
||||
|
||||
type Pcln struct {
|
||||
Pcsp Pcdata
|
||||
Pcfile Pcdata
|
||||
Pcline Pcdata
|
||||
Pcinline Pcdata
|
||||
Pcdata []Pcdata
|
||||
// Aux symbols for pcln
|
||||
Pcsp *LSym
|
||||
Pcfile *LSym
|
||||
Pcline *LSym
|
||||
Pcinline *LSym
|
||||
Pcdata []*LSym
|
||||
Funcdata []*LSym
|
||||
Funcdataoff []int64
|
||||
UsedFiles map[goobj.CUFileIndex]struct{} // file indices used while generating pcfile
|
||||
@ -660,10 +661,6 @@ type Auto struct {
|
||||
Gotype *LSym
|
||||
}
|
||||
|
||||
type Pcdata struct {
|
||||
P []byte
|
||||
}
|
||||
|
||||
// Link holds the context for writing object code from a compiler
|
||||
// to be linker input or for reading that input into the linker.
|
||||
type Link struct {
|
||||
|
@ -185,7 +185,11 @@ func WriteObjFile(ctxt *Link, b *bio.Writer) {
|
||||
// Pcdata
|
||||
h.Offsets[goobj.BlkPcdata] = w.Offset()
|
||||
for _, s := range ctxt.Text { // iteration order must match genFuncInfoSyms
|
||||
if s.Func != nil {
|
||||
// Because of the phase order, it's possible that we try to write an invalid
|
||||
// object file, and the Pcln variables haven't been filled in. As such, we
|
||||
// need to check that Pcsp exists, and assume the other pcln variables exist
|
||||
// as well. Tests like test/fixedbugs/issue22200.go demonstrate this issue.
|
||||
if s.Func != nil && s.Func.Pcln.Pcsp != nil {
|
||||
pc := &s.Func.Pcln
|
||||
w.Bytes(pc.Pcsp.P)
|
||||
w.Bytes(pc.Pcfile.P)
|
||||
@ -372,6 +376,19 @@ func contentHash64(s *LSym) goobj.Hash64Type {
|
||||
// hashed symbols.
|
||||
func (w *writer) contentHash(s *LSym) goobj.HashType {
|
||||
h := sha1.New()
|
||||
var tmp [14]byte
|
||||
|
||||
// Include the size of the symbol in the hash.
|
||||
// This preserves the length of symbols, preventing the following two symbols
|
||||
// from hashing the same:
|
||||
//
|
||||
// [2]int{1,2} ≠ [10]int{1,2,0,0,0...}
|
||||
//
|
||||
// In this case, if the smaller symbol is alive, the larger is not kept unless
|
||||
// needed.
|
||||
binary.LittleEndian.PutUint64(tmp[:8], uint64(s.Size))
|
||||
h.Write(tmp[:8])
|
||||
|
||||
// Don't dedup type symbols with others, as they are in a different
|
||||
// section.
|
||||
if strings.HasPrefix(s.Name, "type.") {
|
||||
@ -382,7 +399,6 @@ func (w *writer) contentHash(s *LSym) goobj.HashType {
|
||||
// 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))
|
||||
@ -473,6 +489,22 @@ func (w *writer) Aux(s *LSym) {
|
||||
if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
|
||||
w.aux1(goobj.AuxDwarfLines, s.Func.dwarfDebugLinesSym)
|
||||
}
|
||||
if s.Func.Pcln.Pcsp != nil && s.Func.Pcln.Pcsp.Size != 0 {
|
||||
w.aux1(goobj.AuxPcsp, s.Func.Pcln.Pcsp)
|
||||
}
|
||||
if s.Func.Pcln.Pcfile != nil && s.Func.Pcln.Pcfile.Size != 0 {
|
||||
w.aux1(goobj.AuxPcfile, s.Func.Pcln.Pcfile)
|
||||
}
|
||||
if s.Func.Pcln.Pcline != nil && s.Func.Pcln.Pcline.Size != 0 {
|
||||
w.aux1(goobj.AuxPcline, s.Func.Pcln.Pcline)
|
||||
}
|
||||
if s.Func.Pcln.Pcinline != nil && s.Func.Pcln.Pcinline.Size != 0 {
|
||||
w.aux1(goobj.AuxPcinline, s.Func.Pcln.Pcinline)
|
||||
}
|
||||
for _, pcSym := range s.Func.Pcln.Pcdata {
|
||||
w.aux1(goobj.AuxPcdata, pcSym)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -554,6 +586,19 @@ func nAuxSym(s *LSym) int {
|
||||
if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
|
||||
n++
|
||||
}
|
||||
if s.Func.Pcln.Pcsp != nil && s.Func.Pcln.Pcsp.Size != 0 {
|
||||
n++
|
||||
}
|
||||
if s.Func.Pcln.Pcfile != nil && s.Func.Pcln.Pcfile.Size != 0 {
|
||||
n++
|
||||
}
|
||||
if s.Func.Pcln.Pcline != nil && s.Func.Pcln.Pcline.Size != 0 {
|
||||
n++
|
||||
}
|
||||
if s.Func.Pcln.Pcinline != nil && s.Func.Pcln.Pcinline.Size != 0 {
|
||||
n++
|
||||
}
|
||||
n += len(s.Func.Pcln.Pcdata)
|
||||
}
|
||||
return n
|
||||
}
|
||||
@ -561,7 +606,17 @@ func nAuxSym(s *LSym) int {
|
||||
// generate symbols for FuncInfo.
|
||||
func genFuncInfoSyms(ctxt *Link) {
|
||||
infosyms := make([]*LSym, 0, len(ctxt.Text))
|
||||
var pcdataoff uint32
|
||||
hashedsyms := make([]*LSym, 0, 4*len(ctxt.Text))
|
||||
preparePcSym := func(s *LSym) *LSym {
|
||||
if s == nil {
|
||||
return s
|
||||
}
|
||||
s.PkgIdx = goobj.PkgIdxHashed
|
||||
s.SymIdx = int32(len(hashedsyms) + len(ctxt.hasheddefs))
|
||||
s.Set(AttrIndexed, true)
|
||||
hashedsyms = append(hashedsyms, s)
|
||||
return s
|
||||
}
|
||||
var b bytes.Buffer
|
||||
symidx := int32(len(ctxt.defs))
|
||||
for _, s := range ctxt.Text {
|
||||
@ -574,20 +629,14 @@ func genFuncInfoSyms(ctxt *Link) {
|
||||
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.Pcsp = makeSymRef(preparePcSym(pc.Pcsp))
|
||||
o.Pcfile = makeSymRef(preparePcSym(pc.Pcfile))
|
||||
o.Pcline = makeSymRef(preparePcSym(pc.Pcline))
|
||||
o.Pcinline = makeSymRef(preparePcSym(pc.Pcinline))
|
||||
o.Pcdata = make([]goobj.SymRef, len(pc.Pcdata))
|
||||
for i, pcSym := range pc.Pcdata {
|
||||
o.Pcdata[i] = makeSymRef(preparePcSym(pcSym))
|
||||
}
|
||||
o.PcdataEnd = pcdataoff
|
||||
o.Funcdataoff = make([]uint32, len(pc.Funcdataoff))
|
||||
for i, x := range pc.Funcdataoff {
|
||||
o.Funcdataoff[i] = uint32(x)
|
||||
@ -637,9 +686,9 @@ func genFuncInfoSyms(ctxt *Link) {
|
||||
}
|
||||
}
|
||||
ctxt.defs = append(ctxt.defs, infosyms...)
|
||||
ctxt.hasheddefs = append(ctxt.hasheddefs, hashedsyms...)
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
@ -6,6 +6,7 @@ package obj
|
||||
|
||||
import (
|
||||
"cmd/internal/goobj"
|
||||
"cmd/internal/objabi"
|
||||
"encoding/binary"
|
||||
"log"
|
||||
)
|
||||
@ -14,16 +15,19 @@ import (
|
||||
// returned by valfunc parameterized by arg. The invocation of valfunc to update the
|
||||
// current value is, for each p,
|
||||
//
|
||||
// val = valfunc(func, val, p, 0, arg);
|
||||
// record val as value at p->pc;
|
||||
// val = valfunc(func, val, p, 1, arg);
|
||||
// sym = valfunc(func, p, 0, arg);
|
||||
// record sym.P as value at p->pc;
|
||||
// sym = valfunc(func, p, 1, arg);
|
||||
//
|
||||
// where func is the function, val is the current value, p is the instruction being
|
||||
// considered, and arg can be used to further parameterize valfunc.
|
||||
func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*Link, *LSym, int32, *Prog, int32, interface{}) int32, arg interface{}) {
|
||||
func funcpctab(ctxt *Link, func_ *LSym, desc string, valfunc func(*Link, *LSym, int32, *Prog, int32, interface{}) int32, arg interface{}) *LSym {
|
||||
dbg := desc == ctxt.Debugpcln
|
||||
|
||||
dst.P = dst.P[:0]
|
||||
dst := []byte{}
|
||||
sym := &LSym{
|
||||
Type: objabi.SRODATA,
|
||||
Attribute: AttrContentAddressable,
|
||||
}
|
||||
|
||||
if dbg {
|
||||
ctxt.Logf("funcpctab %s [valfunc=%s]\n", func_.Name, desc)
|
||||
@ -32,7 +36,8 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
|
||||
val := int32(-1)
|
||||
oldval := val
|
||||
if func_.Func.Text == nil {
|
||||
return
|
||||
// Return the emtpy symbol we've built so far.
|
||||
return sym
|
||||
}
|
||||
|
||||
pc := func_.Func.Text.Pc
|
||||
@ -88,13 +93,13 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
|
||||
if started {
|
||||
pcdelta := (p.Pc - pc) / int64(ctxt.Arch.MinLC)
|
||||
n := binary.PutUvarint(buf, uint64(pcdelta))
|
||||
dst.P = append(dst.P, buf[:n]...)
|
||||
dst = append(dst, buf[:n]...)
|
||||
pc = p.Pc
|
||||
}
|
||||
|
||||
delta := val - oldval
|
||||
n := binary.PutVarint(buf, int64(delta))
|
||||
dst.P = append(dst.P, buf[:n]...)
|
||||
dst = append(dst, buf[:n]...)
|
||||
oldval = val
|
||||
started = true
|
||||
val = valfunc(ctxt, func_, val, p, 1, arg)
|
||||
@ -109,18 +114,22 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
|
||||
ctxt.Diag("negative pc offset: %v", v)
|
||||
}
|
||||
n := binary.PutUvarint(buf, uint64(v))
|
||||
dst.P = append(dst.P, buf[:n]...)
|
||||
dst = append(dst, buf[:n]...)
|
||||
// add terminating varint-encoded 0, which is just 0
|
||||
dst.P = append(dst.P, 0)
|
||||
dst = append(dst, 0)
|
||||
}
|
||||
|
||||
if dbg {
|
||||
ctxt.Logf("wrote %d bytes to %p\n", len(dst.P), dst)
|
||||
for _, p := range dst.P {
|
||||
ctxt.Logf("wrote %d bytes to %p\n", len(dst), dst)
|
||||
for _, p := range dst {
|
||||
ctxt.Logf(" %02x", p)
|
||||
}
|
||||
ctxt.Logf("\n")
|
||||
}
|
||||
|
||||
sym.Size = int64(len(dst))
|
||||
sym.P = dst
|
||||
return sym
|
||||
}
|
||||
|
||||
// pctofileline computes either the file number (arg == 0)
|
||||
@ -268,15 +277,14 @@ func linkpcln(ctxt *Link, cursym *LSym) {
|
||||
}
|
||||
}
|
||||
|
||||
pcln.Pcdata = make([]Pcdata, npcdata)
|
||||
pcln.Pcdata = pcln.Pcdata[:npcdata]
|
||||
pcln.Pcdata = make([]*LSym, npcdata)
|
||||
pcln.Funcdata = make([]*LSym, nfuncdata)
|
||||
pcln.Funcdataoff = make([]int64, nfuncdata)
|
||||
pcln.Funcdataoff = pcln.Funcdataoff[:nfuncdata]
|
||||
|
||||
funcpctab(ctxt, &pcln.Pcsp, cursym, "pctospadj", pctospadj, nil)
|
||||
funcpctab(ctxt, &pcln.Pcfile, cursym, "pctofile", pctofileline, pcln)
|
||||
funcpctab(ctxt, &pcln.Pcline, cursym, "pctoline", pctofileline, nil)
|
||||
pcln.Pcsp = funcpctab(ctxt, cursym, "pctospadj", pctospadj, nil)
|
||||
pcln.Pcfile = funcpctab(ctxt, cursym, "pctofile", pctofileline, pcln)
|
||||
pcln.Pcline = funcpctab(ctxt, cursym, "pctoline", pctofileline, nil)
|
||||
|
||||
// Check that all the Progs used as inline markers are still reachable.
|
||||
// See issue #40473.
|
||||
@ -294,7 +302,7 @@ func linkpcln(ctxt *Link, cursym *LSym) {
|
||||
}
|
||||
|
||||
pcinlineState := new(pcinlineState)
|
||||
funcpctab(ctxt, &pcln.Pcinline, cursym, "pctoinline", pcinlineState.pctoinline, nil)
|
||||
pcln.Pcinline = funcpctab(ctxt, cursym, "pctoinline", pcinlineState.pctoinline, nil)
|
||||
for _, inlMark := range cursym.Func.InlMarks {
|
||||
pcinlineState.setParentPC(ctxt, int(inlMark.id), int32(inlMark.p.Pc))
|
||||
}
|
||||
@ -324,9 +332,14 @@ func linkpcln(ctxt *Link, cursym *LSym) {
|
||||
// pcdata.
|
||||
for i := 0; i < npcdata; i++ {
|
||||
if (havepc[i/32]>>uint(i%32))&1 == 0 {
|
||||
continue
|
||||
// use an empty symbol.
|
||||
pcln.Pcdata[i] = &LSym{
|
||||
Type: objabi.SRODATA,
|
||||
Attribute: AttrContentAddressable,
|
||||
}
|
||||
} else {
|
||||
pcln.Pcdata[i] = funcpctab(ctxt, cursym, "pctopcdata", pctopcdata, interface{}(uint32(i)))
|
||||
}
|
||||
funcpctab(ctxt, &pcln.Pcdata[i], cursym, "pctopcdata", pctopcdata, interface{}(uint32(i)))
|
||||
}
|
||||
|
||||
// funcdata
|
||||
|
@ -234,7 +234,15 @@ func (f *goobjFile) PCToLine(pc uint64) (string, int, *gosym.Func) {
|
||||
if f.arch == nil {
|
||||
return "", 0, nil
|
||||
}
|
||||
pcdataBase := r.PcdataBase()
|
||||
getSymData := func(s goobj.SymRef) []byte {
|
||||
if s.PkgIdx != goobj.PkgIdxHashed {
|
||||
// We don't need the data for non-hashed symbols, yet.
|
||||
panic("not supported")
|
||||
}
|
||||
i := uint32(s.SymIdx + uint32(r.NSym()+r.NHashed64def()))
|
||||
return r.BytesAt(r.DataOff(i), r.DataSize(i))
|
||||
}
|
||||
|
||||
ndef := uint32(r.NSym() + r.NHashed64def() + r.NHasheddef() + r.NNonpkgdef())
|
||||
for i := uint32(0); i < ndef; i++ {
|
||||
osym := r.Sym(i)
|
||||
@ -260,11 +268,9 @@ func (f *goobjFile) PCToLine(pc uint64) (string, int, *gosym.Func) {
|
||||
b := r.BytesAt(r.DataOff(isym), r.DataSize(isym))
|
||||
var info *goobj.FuncInfo
|
||||
lengths := info.ReadFuncInfoLengths(b)
|
||||
off, end := info.ReadPcline(b)
|
||||
pcline := r.BytesAt(pcdataBase+off, int(end-off))
|
||||
pcline := getSymData(info.ReadPcline(b))
|
||||
line := int(pcValue(pcline, pc-addr, f.arch))
|
||||
off, end = info.ReadPcfile(b)
|
||||
pcfile := r.BytesAt(pcdataBase+off, int(end-off))
|
||||
pcfile := getSymData(info.ReadPcfile(b))
|
||||
fileID := pcValue(pcfile, pc-addr, f.arch)
|
||||
globalFileID := info.ReadFile(b, lengths.FileOff, uint32(fileID))
|
||||
fileName := r.File(int(globalFileID))
|
||||
|
@ -1941,7 +1941,10 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
|
||||
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.pclntab", 0), sect)
|
||||
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.pcheader", 0), sect)
|
||||
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.funcnametab", 0), sect)
|
||||
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.pclntab_old", 0), sect)
|
||||
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.cutab", 0), sect)
|
||||
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.filetab", 0), sect)
|
||||
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.pctab", 0), sect)
|
||||
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.functab", 0), sect)
|
||||
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.epclntab", 0), sect)
|
||||
if ctxt.HeadType == objabi.Haix {
|
||||
xcoffUpdateOuterSize(ctxt, int64(sect.Length), sym.SPCLNTAB)
|
||||
@ -2525,7 +2528,10 @@ func (ctxt *Link) address() []*sym.Segment {
|
||||
ctxt.xdefine("runtime.pclntab", sym.SRODATA, int64(pclntab.Vaddr))
|
||||
ctxt.defineInternal("runtime.pcheader", sym.SRODATA)
|
||||
ctxt.defineInternal("runtime.funcnametab", sym.SRODATA)
|
||||
ctxt.defineInternal("runtime.pclntab_old", sym.SRODATA)
|
||||
ctxt.defineInternal("runtime.cutab", sym.SRODATA)
|
||||
ctxt.defineInternal("runtime.filetab", sym.SRODATA)
|
||||
ctxt.defineInternal("runtime.pctab", sym.SRODATA)
|
||||
ctxt.defineInternal("runtime.functab", sym.SRODATA)
|
||||
ctxt.xdefine("runtime.epclntab", sym.SRODATA, int64(pclntab.Vaddr+pclntab.Length))
|
||||
ctxt.xdefine("runtime.noptrdata", sym.SNOPTRDATA, int64(noptr.Vaddr))
|
||||
ctxt.xdefine("runtime.enoptrdata", sym.SNOPTRDATA, int64(noptr.Vaddr+noptr.Length))
|
||||
|
@ -1421,7 +1421,7 @@ func (d *dwctxt) writeframes(fs loader.Sym) dwarfSecInfo {
|
||||
deltaBuf = dwarf.AppendUleb128(deltaBuf, uint64(thearch.Dwarfreglr))
|
||||
}
|
||||
|
||||
for pcsp.Init(fpcsp); !pcsp.Done; pcsp.Next() {
|
||||
for pcsp.Init(d.linkctxt.loader.Data(fpcsp)); !pcsp.Done; pcsp.Next() {
|
||||
nextpc := pcsp.NextPC
|
||||
|
||||
// pciterinit goes up to the end of the function,
|
||||
|
@ -543,7 +543,7 @@ func (ctxt *Link) loadlib() {
|
||||
}
|
||||
|
||||
// Add non-package symbols and references of externally defined symbols.
|
||||
ctxt.loader.LoadNonpkgSyms(ctxt.Arch)
|
||||
ctxt.loader.LoadSyms(ctxt.Arch)
|
||||
|
||||
// Load symbols from shared libraries, after all Go object symbols are loaded.
|
||||
for _, lib := range ctxt.Library {
|
||||
@ -2259,7 +2259,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(info.Pcsp()); !pcsp.Done; pcsp.Next() {
|
||||
for pcsp.Init(ldr.Data(info.Pcsp())); !pcsp.Done; pcsp.Next() {
|
||||
// pcsp.value is in effect for [pcsp.pc, pcsp.nextpc).
|
||||
|
||||
// Check stack size in effect for this span.
|
||||
|
@ -71,7 +71,6 @@ type Link struct {
|
||||
LibraryByPkg map[string]*sym.Library
|
||||
Shlibs []Shlib
|
||||
Textp []loader.Sym
|
||||
NumFilesyms int
|
||||
Moduledata loader.Sym
|
||||
|
||||
PackageFile map[string]string
|
||||
|
@ -36,12 +36,14 @@ import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/benchmark"
|
||||
"cmd/link/internal/loader"
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -324,9 +326,15 @@ func Main(arch *sys.Arch, theArch Arch) {
|
||||
bench.Start("Asmb")
|
||||
asmb(ctxt)
|
||||
// Generate large symbols.
|
||||
var wg sync.WaitGroup
|
||||
for s, f := range ctxt.generatorSyms {
|
||||
f(ctxt, s)
|
||||
wg.Add(1)
|
||||
go func(f generatorFunc, s loader.Sym) {
|
||||
defer wg.Done()
|
||||
f(ctxt, s)
|
||||
}(f, s)
|
||||
}
|
||||
wg.Wait()
|
||||
bench.Start("Asmb2")
|
||||
asmb2(ctxt)
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -619,6 +619,18 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind {
|
||||
moduledata.AddAddr(ctxt.Arch, pcln.funcnametab)
|
||||
moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.funcnametab)))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.funcnametab)))
|
||||
// The cutab slice
|
||||
moduledata.AddAddr(ctxt.Arch, pcln.cutab)
|
||||
moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.cutab)))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.cutab)))
|
||||
// The filetab slice
|
||||
moduledata.AddAddr(ctxt.Arch, pcln.filetab)
|
||||
moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.filetab)))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.filetab)))
|
||||
// The pctab slice
|
||||
moduledata.AddAddr(ctxt.Arch, pcln.pctab)
|
||||
moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.pctab)))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.pctab)))
|
||||
// The pclntab slice
|
||||
moduledata.AddAddr(ctxt.Arch, pcln.pclntab)
|
||||
moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.pclntab)))
|
||||
@ -627,10 +639,6 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind {
|
||||
moduledata.AddAddr(ctxt.Arch, pcln.pclntab)
|
||||
moduledata.AddUint(ctxt.Arch, uint64(pcln.nfunc+1))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(pcln.nfunc+1))
|
||||
// The filetab slice
|
||||
moduledata.AddAddrPlus(ctxt.Arch, pcln.pclntab, int64(pcln.filetabOffset))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(ctxt.NumFilesyms)+1)
|
||||
moduledata.AddUint(ctxt.Arch, uint64(ctxt.NumFilesyms)+1)
|
||||
// findfunctab
|
||||
moduledata.AddAddr(ctxt.Arch, pcln.findfunctab)
|
||||
// minpc, maxpc
|
||||
|
@ -330,7 +330,7 @@ func NewLoader(flags uint32, elfsetstring elfsetstringFunc, reporter *ErrorRepor
|
||||
ldr := &Loader{
|
||||
start: make(map[*oReader]Sym),
|
||||
objs: []objIdx{{}, {extReader, 0}}, // reserve index 0 for nil symbol, 1 for external symbols
|
||||
objSyms: make([]objSym, 1, 100000), // reserve index 0 for nil symbol
|
||||
objSyms: make([]objSym, 1, 1), // This will get overwritten later.
|
||||
extReader: extReader,
|
||||
symsByName: [2]map[string]Sym{make(map[string]Sym, 80000), make(map[string]Sym, 50000)}, // preallocate ~2MB for ABI0 and ~1MB for ABI1 symbols
|
||||
objByPkg: make(map[string]uint32),
|
||||
@ -1875,19 +1875,24 @@ func (fi *FuncInfo) FuncID() objabi.FuncID {
|
||||
return objabi.FuncID((*goobj.FuncInfo)(nil).ReadFuncID(fi.data))
|
||||
}
|
||||
|
||||
func (fi *FuncInfo) Pcsp() []byte {
|
||||
pcsp, end := (*goobj.FuncInfo)(nil).ReadPcsp(fi.data)
|
||||
return fi.r.BytesAt(fi.r.PcdataBase()+pcsp, int(end-pcsp))
|
||||
func (fi *FuncInfo) Pcsp() Sym {
|
||||
sym := (*goobj.FuncInfo)(nil).ReadPcsp(fi.data)
|
||||
return fi.l.resolve(fi.r, sym)
|
||||
}
|
||||
|
||||
func (fi *FuncInfo) Pcfile() []byte {
|
||||
pcf, end := (*goobj.FuncInfo)(nil).ReadPcfile(fi.data)
|
||||
return fi.r.BytesAt(fi.r.PcdataBase()+pcf, int(end-pcf))
|
||||
func (fi *FuncInfo) Pcfile() Sym {
|
||||
sym := (*goobj.FuncInfo)(nil).ReadPcfile(fi.data)
|
||||
return fi.l.resolve(fi.r, sym)
|
||||
}
|
||||
|
||||
func (fi *FuncInfo) Pcline() []byte {
|
||||
pcln, end := (*goobj.FuncInfo)(nil).ReadPcline(fi.data)
|
||||
return fi.r.BytesAt(fi.r.PcdataBase()+pcln, int(end-pcln))
|
||||
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
|
||||
@ -1896,27 +1901,16 @@ func (fi *FuncInfo) Preload() {
|
||||
fi.lengths = (*goobj.FuncInfo)(nil).ReadFuncInfoLengths(fi.data)
|
||||
}
|
||||
|
||||
func (fi *FuncInfo) Pcinline() []byte {
|
||||
func (fi *FuncInfo) Pcdata() []Sym {
|
||||
if !fi.lengths.Initialized {
|
||||
panic("need to call Preload first")
|
||||
}
|
||||
pcinl, end := (*goobj.FuncInfo)(nil).ReadPcinline(fi.data, fi.lengths.PcdataOff)
|
||||
return fi.r.BytesAt(fi.r.PcdataBase()+pcinl, int(end-pcinl))
|
||||
}
|
||||
|
||||
func (fi *FuncInfo) NumPcdata() uint32 {
|
||||
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 fi.lengths.NumPcdata
|
||||
}
|
||||
|
||||
func (fi *FuncInfo) Pcdata(k int) []byte {
|
||||
if !fi.lengths.Initialized {
|
||||
panic("need to call Preload first")
|
||||
}
|
||||
pcdat, end := (*goobj.FuncInfo)(nil).ReadPcdata(fi.data, fi.lengths.PcdataOff, uint32(k))
|
||||
return fi.r.BytesAt(fi.r.PcdataBase()+pcdat, int(end-pcdat))
|
||||
return ret
|
||||
}
|
||||
|
||||
func (fi *FuncInfo) NumFuncdataoff() uint32 {
|
||||
@ -2019,8 +2013,9 @@ func (l *Loader) FuncInfo(i Sym) FuncInfo {
|
||||
return FuncInfo{}
|
||||
}
|
||||
|
||||
// Preload a package: add autolibs, add defined package symbols to the symbol table.
|
||||
// Does not add non-package symbols yet, which will be done in LoadNonpkgSyms.
|
||||
// Preload a package: adds autolib.
|
||||
// Does not add defined package or non-packaged symbols to the symbol table.
|
||||
// These are done in LoadSyms.
|
||||
// Does not read symbol data.
|
||||
// Returns the fingerprint of the object.
|
||||
func (l *Loader) Preload(localSymVersion int, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64) goobj.FingerprintType {
|
||||
@ -2063,8 +2058,6 @@ func (l *Loader) Preload(localSymVersion int, f *bio.Reader, lib *sym.Library, u
|
||||
}
|
||||
|
||||
l.addObj(lib.Pkg, or)
|
||||
st := loadState{l: l}
|
||||
st.preloadSyms(or, pkgDef)
|
||||
|
||||
// The caller expects us consuming all the data
|
||||
f.MustSeek(length, os.SEEK_CUR)
|
||||
@ -2147,17 +2140,30 @@ func (st *loadState) preloadSyms(r *oReader, kind int) {
|
||||
}
|
||||
}
|
||||
|
||||
// Add hashed (content-addressable) symbols, non-package symbols, and
|
||||
// Add syms, hashed (content-addressable) symbols, non-package symbols, and
|
||||
// references to external symbols (which are always named).
|
||||
func (l *Loader) LoadNonpkgSyms(arch *sys.Arch) {
|
||||
func (l *Loader) LoadSyms(arch *sys.Arch) {
|
||||
// Allocate space for symbols, making a guess as to how much space we need.
|
||||
// This function was determined empirically by looking at the cmd/compile on
|
||||
// Darwin, and picking factors for hashed and hashed64 syms.
|
||||
var symSize, hashedSize, hashed64Size int
|
||||
for _, o := range l.objs[goObjStart:] {
|
||||
symSize += o.r.ndef + o.r.nhasheddef/2 + o.r.nhashed64def/2 + o.r.NNonpkgdef()
|
||||
hashedSize += o.r.nhasheddef / 2
|
||||
hashed64Size += o.r.nhashed64def / 2
|
||||
}
|
||||
// Index 0 is invalid for symbols.
|
||||
l.objSyms = make([]objSym, 1, symSize)
|
||||
|
||||
l.npkgsyms = l.NSym()
|
||||
// Preallocate some space (a few hundreds KB) for some symbols.
|
||||
// As of Go 1.15, linking cmd/compile has ~8000 hashed64 symbols and
|
||||
// ~27000 hashed symbols.
|
||||
st := loadState{
|
||||
l: l,
|
||||
hashed64Syms: make(map[uint64]symAndSize, 10000),
|
||||
hashedSyms: make(map[goobj.HashType]symAndSize, 30000),
|
||||
hashed64Syms: make(map[uint64]symAndSize, hashed64Size),
|
||||
hashedSyms: make(map[goobj.HashType]symAndSize, hashedSize),
|
||||
}
|
||||
|
||||
for _, o := range l.objs[goObjStart:] {
|
||||
st.preloadSyms(o.r, pkgDef)
|
||||
}
|
||||
for _, o := range l.objs[goObjStart:] {
|
||||
st.preloadSyms(o.r, hashed64Def)
|
||||
|
@ -336,6 +336,15 @@ func (sb *SymbolBuilder) Addstring(str string) int64 {
|
||||
return r
|
||||
}
|
||||
|
||||
func (sb *SymbolBuilder) SetBytesAt(off int64, b []byte) int64 {
|
||||
datLen := int64(len(b))
|
||||
if off+datLen > int64(len(sb.data)) {
|
||||
panic("attempt to write past end of buffer")
|
||||
}
|
||||
copy(sb.data[off:off+datLen], b)
|
||||
return off + datLen
|
||||
}
|
||||
|
||||
func (sb *SymbolBuilder) addSymRef(tgt Sym, add int64, typ objabi.RelocType, rsize int) int64 {
|
||||
if sb.kind == 0 {
|
||||
sb.kind = sym.SDATA
|
||||
|
@ -33,7 +33,3 @@ func VersionToABI(v int) (obj.ABI, bool) {
|
||||
}
|
||||
return ^obj.ABI(0), false
|
||||
}
|
||||
|
||||
type Pcdata struct {
|
||||
P []byte
|
||||
}
|
||||
|
@ -53,14 +53,19 @@ type LineTable struct {
|
||||
quantum uint32
|
||||
ptrsize uint32
|
||||
funcnametab []byte
|
||||
cutab []byte
|
||||
funcdata []byte
|
||||
functab []byte
|
||||
nfunctab uint32
|
||||
filetab []byte
|
||||
pctab []byte // points to the pctables.
|
||||
nfiletab uint32
|
||||
fileMap map[string]uint32
|
||||
funcNames map[uint32]string // cache the function names
|
||||
strings map[uint32]string // interned substrings of Data, keyed by offset
|
||||
// fileMap varies depending on the version of the object file.
|
||||
// For ver12, it maps the name to the index in the file table.
|
||||
// For ver116, it maps the name to the offset in filetab.
|
||||
fileMap map[string]uint32
|
||||
}
|
||||
|
||||
// NOTE(rsc): This is wrong for GOARCH=arm, which uses a quantum of 4,
|
||||
@ -223,22 +228,26 @@ func (t *LineTable) parsePclnTab() {
|
||||
switch possibleVersion {
|
||||
case ver116:
|
||||
t.nfunctab = uint32(t.uintptr(t.Data[8:]))
|
||||
offset := t.uintptr(t.Data[8+t.ptrsize:])
|
||||
t.nfiletab = uint32(t.uintptr(t.Data[8+t.ptrsize:]))
|
||||
offset := t.uintptr(t.Data[8+2*t.ptrsize:])
|
||||
t.funcnametab = t.Data[offset:]
|
||||
offset = t.uintptr(t.Data[8+2*t.ptrsize:])
|
||||
offset = t.uintptr(t.Data[8+3*t.ptrsize:])
|
||||
t.cutab = t.Data[offset:]
|
||||
offset = t.uintptr(t.Data[8+4*t.ptrsize:])
|
||||
t.filetab = t.Data[offset:]
|
||||
offset = t.uintptr(t.Data[8+5*t.ptrsize:])
|
||||
t.pctab = t.Data[offset:]
|
||||
offset = t.uintptr(t.Data[8+6*t.ptrsize:])
|
||||
t.funcdata = t.Data[offset:]
|
||||
t.functab = t.Data[offset:]
|
||||
functabsize := t.nfunctab*2*t.ptrsize + t.ptrsize
|
||||
fileoff := t.binary.Uint32(t.functab[functabsize:])
|
||||
t.filetab = t.functab[fileoff:]
|
||||
t.functab = t.functab[:functabsize]
|
||||
t.nfiletab = t.binary.Uint32(t.filetab)
|
||||
t.filetab = t.filetab[:t.nfiletab*4]
|
||||
case ver12:
|
||||
t.nfunctab = uint32(t.uintptr(t.Data[8:]))
|
||||
t.funcdata = t.Data
|
||||
t.funcnametab = t.Data
|
||||
t.functab = t.Data[8+t.ptrsize:]
|
||||
t.pctab = t.Data
|
||||
functabsize := t.nfunctab*2*t.ptrsize + t.ptrsize
|
||||
fileoff := t.binary.Uint32(t.functab[functabsize:])
|
||||
t.functab = t.functab[:functabsize]
|
||||
@ -330,17 +339,22 @@ func (t *LineTable) funcName(off uint32) string {
|
||||
return s
|
||||
}
|
||||
|
||||
// string returns a Go string found at off.
|
||||
func (t *LineTable) string(off uint32) string {
|
||||
// stringFrom returns a Go string found at off from a position.
|
||||
func (t *LineTable) stringFrom(arr []byte, off uint32) string {
|
||||
if s, ok := t.strings[off]; ok {
|
||||
return s
|
||||
}
|
||||
i := bytes.IndexByte(t.funcdata[off:], 0)
|
||||
s := string(t.funcdata[off : off+uint32(i)])
|
||||
i := bytes.IndexByte(arr[off:], 0)
|
||||
s := string(arr[off : off+uint32(i)])
|
||||
t.strings[off] = s
|
||||
return s
|
||||
}
|
||||
|
||||
// string returns a Go string found at off.
|
||||
func (t *LineTable) string(off uint32) string {
|
||||
return t.stringFrom(t.funcdata, off)
|
||||
}
|
||||
|
||||
// step advances to the next pc, value pair in the encoded table.
|
||||
func (t *LineTable) step(p *[]byte, pc *uint64, val *int32, first bool) bool {
|
||||
uvdelta := t.readvarint(p)
|
||||
@ -363,7 +377,7 @@ func (t *LineTable) step(p *[]byte, pc *uint64, val *int32, first bool) bool {
|
||||
// off is the offset to the beginning of the pc-value table,
|
||||
// and entry is the start PC for the corresponding function.
|
||||
func (t *LineTable) pcvalue(off uint32, entry, targetpc uint64) int32 {
|
||||
p := t.funcdata[off:]
|
||||
p := t.pctab[off:]
|
||||
|
||||
val := int32(-1)
|
||||
pc := entry
|
||||
@ -381,21 +395,25 @@ func (t *LineTable) pcvalue(off uint32, entry, targetpc uint64) int32 {
|
||||
// to file number. Since most functions come from a single file, these
|
||||
// are usually short and quick to scan. If a file match is found, then the
|
||||
// code goes to the expense of looking for a simultaneous line number match.
|
||||
func (t *LineTable) findFileLine(entry uint64, filetab, linetab uint32, filenum, line int32) uint64 {
|
||||
func (t *LineTable) findFileLine(entry uint64, filetab, linetab uint32, filenum, line int32, cutab []byte) uint64 {
|
||||
if filetab == 0 || linetab == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
fp := t.funcdata[filetab:]
|
||||
fl := t.funcdata[linetab:]
|
||||
fp := t.pctab[filetab:]
|
||||
fl := t.pctab[linetab:]
|
||||
fileVal := int32(-1)
|
||||
filePC := entry
|
||||
lineVal := int32(-1)
|
||||
linePC := entry
|
||||
fileStartPC := filePC
|
||||
for t.step(&fp, &filePC, &fileVal, filePC == entry) {
|
||||
if fileVal == filenum && fileStartPC < filePC {
|
||||
// fileVal is in effect starting at fileStartPC up to
|
||||
fileIndex := fileVal
|
||||
if t.version == ver116 {
|
||||
fileIndex = int32(t.binary.Uint32(cutab[fileVal*4:]))
|
||||
}
|
||||
if fileIndex == filenum && fileStartPC < filePC {
|
||||
// fileIndex is in effect starting at fileStartPC up to
|
||||
// but not including filePC, and it's the file we want.
|
||||
// Run the PC table looking for a matching line number
|
||||
// or until we reach filePC.
|
||||
@ -450,13 +468,24 @@ func (t *LineTable) go12PCToFile(pc uint64) (file string) {
|
||||
entry := t.uintptr(f)
|
||||
filetab := t.binary.Uint32(f[t.ptrsize+4*4:])
|
||||
fno := t.pcvalue(filetab, entry, pc)
|
||||
if fno <= 0 {
|
||||
if t.version == ver12 {
|
||||
if fno <= 0 {
|
||||
return ""
|
||||
}
|
||||
return t.string(t.binary.Uint32(t.filetab[4*fno:]))
|
||||
}
|
||||
// Go ≥ 1.16
|
||||
if fno < 0 { // 0 is valid for ≥ 1.16
|
||||
return ""
|
||||
}
|
||||
return t.string(t.binary.Uint32(t.filetab[4*fno:]))
|
||||
cuoff := t.binary.Uint32(f[t.ptrsize+7*4:])
|
||||
if fnoff := t.binary.Uint32(t.cutab[(cuoff+uint32(fno))*4:]); fnoff != ^uint32(0) {
|
||||
return t.stringFrom(t.filetab, fnoff)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// go12LineToPC maps a (file, line) pair to a program counter for the Go 1.2 pcln table.
|
||||
// go12LineToPC maps a (file, line) pair to a program counter for the Go 1.2/1.16 pcln table.
|
||||
func (t *LineTable) go12LineToPC(file string, line int) (pc uint64) {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
@ -465,20 +494,25 @@ func (t *LineTable) go12LineToPC(file string, line int) (pc uint64) {
|
||||
}()
|
||||
|
||||
t.initFileMap()
|
||||
filenum := t.fileMap[file]
|
||||
if filenum == 0 {
|
||||
filenum, ok := t.fileMap[file]
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Scan all functions.
|
||||
// If this turns out to be a bottleneck, we could build a map[int32][]int32
|
||||
// mapping file number to a list of functions with code from that file.
|
||||
var cutab []byte
|
||||
for i := uint32(0); i < t.nfunctab; i++ {
|
||||
f := t.funcdata[t.uintptr(t.functab[2*t.ptrsize*i+t.ptrsize:]):]
|
||||
entry := t.uintptr(f)
|
||||
filetab := t.binary.Uint32(f[t.ptrsize+4*4:])
|
||||
linetab := t.binary.Uint32(f[t.ptrsize+5*4:])
|
||||
pc := t.findFileLine(entry, filetab, linetab, int32(filenum), int32(line))
|
||||
if t.version == ver116 {
|
||||
cuoff := t.binary.Uint32(f[t.ptrsize+7*4:]) * 4
|
||||
cutab = t.cutab[cuoff:]
|
||||
}
|
||||
pc := t.findFileLine(entry, filetab, linetab, int32(filenum), int32(line), cutab)
|
||||
if pc != 0 {
|
||||
return pc
|
||||
}
|
||||
@ -496,9 +530,18 @@ func (t *LineTable) initFileMap() {
|
||||
}
|
||||
m := make(map[string]uint32)
|
||||
|
||||
for i := uint32(1); i < t.nfiletab; i++ {
|
||||
s := t.string(t.binary.Uint32(t.filetab[4*i:]))
|
||||
m[s] = i
|
||||
if t.version == ver12 {
|
||||
for i := uint32(1); i < t.nfiletab; i++ {
|
||||
s := t.string(t.binary.Uint32(t.filetab[4*i:]))
|
||||
m[s] = i
|
||||
}
|
||||
} else {
|
||||
var pos uint32
|
||||
for i := uint32(0); i < t.nfiletab; i++ {
|
||||
s := t.stringFrom(t.filetab, pos)
|
||||
m[s] = pos
|
||||
pos += uint32(len(s) + 1)
|
||||
}
|
||||
}
|
||||
t.fileMap = m
|
||||
}
|
||||
|
@ -810,13 +810,14 @@ type _func struct {
|
||||
args int32 // in/out args size
|
||||
deferreturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
|
||||
|
||||
pcsp int32
|
||||
pcfile int32
|
||||
pcln int32
|
||||
npcdata int32
|
||||
cuIndex uint16 // TODO(jfaller): 16 bits is never enough, make this larger.
|
||||
funcID funcID // set for certain special runtime functions
|
||||
nfuncdata uint8 // must be last
|
||||
pcsp uint32
|
||||
pcfile uint32
|
||||
pcln uint32
|
||||
npcdata uint32
|
||||
cuOffset uint32 // runtime.cutab offset of this function's CU
|
||||
funcID funcID // set for certain special runtime functions
|
||||
_ [2]byte // pad
|
||||
nfuncdata uint8 // must be last
|
||||
}
|
||||
|
||||
// Pseudo-Func that is returned for PCs that occur in inlined code.
|
||||
|
@ -337,14 +337,18 @@ const (
|
||||
funcID_wrapper // any autogenerated code (hash/eq algorithms, method wrappers, etc.)
|
||||
)
|
||||
|
||||
// PCHeader holds data used by the pclntab lookups.
|
||||
// pcHeader holds data used by the pclntab lookups.
|
||||
type pcHeader struct {
|
||||
magic uint32 // 0xFFFFFFFA
|
||||
pad1, pad2 uint8 // 0,0
|
||||
minLC uint8 // min instruction size
|
||||
ptrSize uint8 // size of a ptr in bytes
|
||||
nfunc int // number of functions in the module
|
||||
nfiles uint // number of entries in the file tab.
|
||||
funcnameOffset uintptr // offset to the funcnametab variable from pcHeader
|
||||
cuOffset uintptr // offset to the cutab variable from pcHeader
|
||||
filetabOffset uintptr // offset to the filetab variable from pcHeader
|
||||
pctabOffset uintptr // offset to the pctab varible from pcHeader
|
||||
pclnOffset uintptr // offset to the pclntab variable from pcHeader
|
||||
}
|
||||
|
||||
@ -356,9 +360,11 @@ type pcHeader struct {
|
||||
type moduledata struct {
|
||||
pcHeader *pcHeader
|
||||
funcnametab []byte
|
||||
cutab []uint32
|
||||
filetab []byte
|
||||
pctab []byte
|
||||
pclntable []byte
|
||||
ftab []functab
|
||||
filetab []uint32
|
||||
findfunctab uintptr
|
||||
minpc, maxpc uintptr
|
||||
|
||||
@ -720,7 +726,7 @@ type pcvalueCache struct {
|
||||
type pcvalueCacheEnt struct {
|
||||
// targetpc and off together are the key of this cache entry.
|
||||
targetpc uintptr
|
||||
off int32
|
||||
off uint32
|
||||
// val is the value of this cached pcvalue entry.
|
||||
val int32
|
||||
}
|
||||
@ -735,7 +741,7 @@ func pcvalueCacheKey(targetpc uintptr) uintptr {
|
||||
|
||||
// Returns the PCData value, and the PC where this value starts.
|
||||
// TODO: the start PC is returned only when cache is nil.
|
||||
func pcvalue(f funcInfo, off int32, targetpc uintptr, cache *pcvalueCache, strict bool) (int32, uintptr) {
|
||||
func pcvalue(f funcInfo, off uint32, targetpc uintptr, cache *pcvalueCache, strict bool) (int32, uintptr) {
|
||||
if off == 0 {
|
||||
return -1, 0
|
||||
}
|
||||
@ -769,7 +775,7 @@ func pcvalue(f funcInfo, off int32, targetpc uintptr, cache *pcvalueCache, stric
|
||||
return -1, 0
|
||||
}
|
||||
datap := f.datap
|
||||
p := datap.pclntable[off:]
|
||||
p := datap.pctab[off:]
|
||||
pc := f.entry
|
||||
prevpc := pc
|
||||
val := int32(-1)
|
||||
@ -811,7 +817,7 @@ func pcvalue(f funcInfo, off int32, targetpc uintptr, cache *pcvalueCache, stric
|
||||
|
||||
print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
|
||||
|
||||
p = datap.pclntable[off:]
|
||||
p = datap.pctab[off:]
|
||||
pc = f.entry
|
||||
val = -1
|
||||
for {
|
||||
@ -854,7 +860,12 @@ func funcfile(f funcInfo, fileno int32) string {
|
||||
if !f.valid() {
|
||||
return "?"
|
||||
}
|
||||
return gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
|
||||
// Make sure the cu index and file offset are valid
|
||||
if fileoff := datap.cutab[f.cuOffset+uint32(fileno)]; fileoff != ^uint32(0) {
|
||||
return gostringnocopy(&datap.filetab[fileoff])
|
||||
}
|
||||
// pcln section is corrupt.
|
||||
return "?"
|
||||
}
|
||||
|
||||
func funcline1(f funcInfo, targetpc uintptr, strict bool) (file string, line int32) {
|
||||
@ -868,7 +879,7 @@ func funcline1(f funcInfo, targetpc uintptr, strict bool) (file string, line int
|
||||
// print("looking for ", hex(targetpc), " in ", funcname(f), " got file=", fileno, " line=", lineno, "\n")
|
||||
return "?", 0
|
||||
}
|
||||
file = gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
|
||||
file = funcfile(f, fileno)
|
||||
return
|
||||
}
|
||||
|
||||
@ -887,7 +898,7 @@ func funcspdelta(f funcInfo, targetpc uintptr, cache *pcvalueCache) int32 {
|
||||
// funcMaxSPDelta returns the maximum spdelta at any point in f.
|
||||
func funcMaxSPDelta(f funcInfo) int32 {
|
||||
datap := f.datap
|
||||
p := datap.pclntable[f.pcsp:]
|
||||
p := datap.pctab[f.pcsp:]
|
||||
pc := f.entry
|
||||
val := int32(-1)
|
||||
max := int32(0)
|
||||
@ -903,20 +914,20 @@ func funcMaxSPDelta(f funcInfo) int32 {
|
||||
}
|
||||
}
|
||||
|
||||
func pcdatastart(f funcInfo, table int32) int32 {
|
||||
return *(*int32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
|
||||
func pcdatastart(f funcInfo, table uint32) uint32 {
|
||||
return *(*uint32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
|
||||
}
|
||||
|
||||
func pcdatavalue(f funcInfo, table int32, targetpc uintptr, cache *pcvalueCache) int32 {
|
||||
if table < 0 || table >= f.npcdata {
|
||||
func pcdatavalue(f funcInfo, table uint32, targetpc uintptr, cache *pcvalueCache) int32 {
|
||||
if table >= f.npcdata {
|
||||
return -1
|
||||
}
|
||||
r, _ := pcvalue(f, pcdatastart(f, table), targetpc, cache, true)
|
||||
return r
|
||||
}
|
||||
|
||||
func pcdatavalue1(f funcInfo, table int32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 {
|
||||
if table < 0 || table >= f.npcdata {
|
||||
func pcdatavalue1(f funcInfo, table uint32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 {
|
||||
if table >= f.npcdata {
|
||||
return -1
|
||||
}
|
||||
r, _ := pcvalue(f, pcdatastart(f, table), targetpc, cache, strict)
|
||||
@ -925,8 +936,8 @@ func pcdatavalue1(f funcInfo, table int32, targetpc uintptr, cache *pcvalueCache
|
||||
|
||||
// Like pcdatavalue, but also return the start PC of this PCData value.
|
||||
// It doesn't take a cache.
|
||||
func pcdatavalue2(f funcInfo, table int32, targetpc uintptr) (int32, uintptr) {
|
||||
if table < 0 || table >= f.npcdata {
|
||||
func pcdatavalue2(f funcInfo, table uint32, targetpc uintptr) (int32, uintptr) {
|
||||
if table >= f.npcdata {
|
||||
return -1, 0
|
||||
}
|
||||
return pcvalue(f, pcdatastart(f, table), targetpc, nil, true)
|
||||
@ -1008,7 +1019,7 @@ type inlinedCall struct {
|
||||
parent int16 // index of parent in the inltree, or < 0
|
||||
funcID funcID // type of the called function
|
||||
_ byte
|
||||
file int32 // fileno index into filetab
|
||||
file int32 // perCU file index for inlined call. See cmd/link:pcln.go
|
||||
line int32 // line number of the call site
|
||||
func_ int32 // offset into pclntab for name of called function
|
||||
parentPc int32 // position of an instruction whose source position is the call site (offset from entry)
|
||||
|
Loading…
Reference in New Issue
Block a user