mirror of
https://github.com/golang/go
synced 2024-11-23 06:40:05 -07:00
runtime: avoid repeated findmoduledatap calls
Currently almost every function that deals with a *_func has to first look up the *moduledata for the module containing the function's entry point. This means we almost always do at least two identical module lookups whenever we deal with a *_func (one to get the *_func and another to get something from its module data) and sometimes several more. Fix this by making findfunc return a new funcInfo type that embeds *_func, but also includes the *moduledata, and making all of the functions that currently take a *_func instead take a funcInfo and use the already-found *moduledata. This transformation is trivial for the most part, since the *_func type is usually inferred. The annoying part is that we can no longer use nil to indicate failure, so this introduces a funcInfo.valid() method and replaces nil checks with calls to valid. Change-Id: I9b8075ef1c31185c1943596d96dec45c7ab5100f Reviewed-on: https://go-review.googlesource.com/37331 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Michael Hudson-Doyle <michael.hudson@canonical.com>
This commit is contained in:
parent
6533cc1ce8
commit
0efc8b2188
@ -174,7 +174,7 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
|
||||
return
|
||||
}
|
||||
f := findfunc(rpc[1])
|
||||
if f == nil {
|
||||
if !f.valid() {
|
||||
// TODO(rsc): Probably a bug?
|
||||
// The C version said "have retpc at least"
|
||||
// but actually returned pc=0.
|
||||
@ -187,7 +187,7 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
|
||||
// All architectures turn faults into apparent calls to sigpanic.
|
||||
// If we see a call to sigpanic, we do not back up the PC to find
|
||||
// the line number of the call instruction, because there is no call.
|
||||
if xpc > f.entry && (g == nil || g.entry != funcPC(sigpanic)) {
|
||||
if xpc > f.entry && (!g.valid() || g.entry != funcPC(sigpanic)) {
|
||||
xpc--
|
||||
}
|
||||
file, line32 := funcline(f, xpc)
|
||||
|
@ -565,7 +565,7 @@ func dumpmemprof_callback(b *bucket, nstk uintptr, pstk *uintptr, size, allocs,
|
||||
for i := uintptr(0); i < nstk; i++ {
|
||||
pc := stk[i]
|
||||
f := findfunc(pc)
|
||||
if f == nil {
|
||||
if !f.valid() {
|
||||
var buf [64]byte
|
||||
n := len(buf)
|
||||
n--
|
||||
|
@ -1877,7 +1877,7 @@ func getgcmask(ep interface{}) (mask []byte) {
|
||||
frame.sp = uintptr(p)
|
||||
_g_ := getg()
|
||||
gentraceback(_g_.m.curg.sched.pc, _g_.m.curg.sched.sp, 0, _g_.m.curg, 0, nil, 1000, getgcmaskcb, noescape(unsafe.Pointer(&frame)), 0)
|
||||
if frame.fn != nil {
|
||||
if frame.fn.valid() {
|
||||
f := frame.fn
|
||||
targetpc := frame.continpc
|
||||
if targetpc == 0 {
|
||||
|
@ -62,7 +62,7 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int {
|
||||
// but we do recognize the top pointer on the stack as code,
|
||||
// then assume this was a call to non-code and treat like
|
||||
// pc == 0, to make unwinding show the context.
|
||||
if pc != 0 && findfunc(pc) == nil && findfunc(*(*uintptr)(unsafe.Pointer(sp))) != nil {
|
||||
if pc != 0 && !findfunc(pc).valid() && findfunc(*(*uintptr)(unsafe.Pointer(sp))).valid() {
|
||||
pc = 0
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ func pluginftabverify(md *moduledata) {
|
||||
continue
|
||||
}
|
||||
|
||||
f := (*_func)(unsafe.Pointer(&md.pclntable[md.ftab[i].funcoff]))
|
||||
f := funcInfo{(*_func)(unsafe.Pointer(&md.pclntable[md.ftab[i].funcoff])), md}
|
||||
name := funcname(f)
|
||||
|
||||
// A common bug is f.entry has a relocation to a duplicate
|
||||
@ -104,7 +104,7 @@ func pluginftabverify(md *moduledata) {
|
||||
name2 := "none"
|
||||
entry2 := uintptr(0)
|
||||
f2 := findfunc(entry)
|
||||
if f2 != nil {
|
||||
if f2.valid() {
|
||||
name2 = funcname(f2)
|
||||
entry2 = f2.entry
|
||||
}
|
||||
|
@ -3336,7 +3336,7 @@ func sigprofNonGoPC(pc uintptr) {
|
||||
// or putting one on the stack at the right offset.
|
||||
func setsSP(pc uintptr) bool {
|
||||
f := findfunc(pc)
|
||||
if f == nil {
|
||||
if !f.valid() {
|
||||
// couldn't find the function for this PC,
|
||||
// so assume the worst and stop traceback
|
||||
return true
|
||||
|
@ -98,7 +98,7 @@ func raceSymbolizeCode(ctx *symbolizeCodeContext) {
|
||||
if f != nil {
|
||||
file, line := f.FileLine(ctx.pc)
|
||||
if line != 0 {
|
||||
ctx.fn = cfuncname(f.raw())
|
||||
ctx.fn = cfuncname(f.funcInfo())
|
||||
ctx.line = uintptr(line)
|
||||
ctx.file = &bytes(file)[0] // assume NUL-terminated
|
||||
ctx.off = ctx.pc - f.Entry()
|
||||
|
@ -685,7 +685,7 @@ type _panic struct {
|
||||
|
||||
// stack traces
|
||||
type stkframe struct {
|
||||
fn *_func // function being run
|
||||
fn funcInfo // function being run
|
||||
pc uintptr // program counter within fn
|
||||
continpc uintptr // program counter where execution can continue, or 0 if not
|
||||
lr uintptr // program counter at caller aka link register
|
||||
|
@ -60,7 +60,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
|
||||
// but we do recognize the top pointer on the stack as code,
|
||||
// then assume this was a call to non-code and treat like
|
||||
// pc == 0, to make unwinding show the context.
|
||||
if pc != 0 && findfunc(pc) == nil && findfunc(*(*uintptr)(unsafe.Pointer(sp))) != nil {
|
||||
if pc != 0 && !findfunc(pc).valid() && findfunc(*(*uintptr)(unsafe.Pointer(sp))).valid() {
|
||||
pc = 0
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
|
||||
// but we do recognize the top pointer on the stack as code,
|
||||
// then assume this was a call to non-code and treat like
|
||||
// pc == 0, to make unwinding show the context.
|
||||
if pc != 0 && findfunc(pc) == nil && findfunc(*(*uintptr)(unsafe.Pointer(sp))) != nil {
|
||||
if pc != 0 && !findfunc(pc).valid() && findfunc(*(*uintptr)(unsafe.Pointer(sp))).valid() {
|
||||
pc = 0
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
|
||||
// but we do recognize the link register as code,
|
||||
// then assume this was a call to non-code and treat like
|
||||
// pc == 0, to make unwinding show the context.
|
||||
if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.lr())) != nil {
|
||||
if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.lr())).valid() {
|
||||
pc = 0
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
|
||||
// but we do recognize the link register as code,
|
||||
// then assume this was a call to non-code and treat like
|
||||
// pc == 0, to make unwinding show the context.
|
||||
if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.lr())) != nil {
|
||||
if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.lr())).valid() {
|
||||
pc = 0
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
|
||||
// but we do recognize the link register as code,
|
||||
// then assume this was a call to non-code and treat like
|
||||
// pc == 0, to make unwinding show the context.
|
||||
if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
|
||||
if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.link())).valid() {
|
||||
pc = 0
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
|
||||
// but we do recognize the link register as code,
|
||||
// then assume this was a call to non-code and treat like
|
||||
// pc == 0, to make unwinding show the context.
|
||||
if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
|
||||
if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.link())).valid() {
|
||||
pc = 0
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
|
||||
// but we do recognize the link register as code,
|
||||
// then assume this was a call to non-code and treat like
|
||||
// pc == 0, to make unwinding show the context.
|
||||
if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
|
||||
if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.link())).valid() {
|
||||
pc = 0
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
|
||||
// but we do recognize the link register as code,
|
||||
// then assume this was a call to non-code and treat like
|
||||
// pc == 0, to make unwinding show the context.
|
||||
if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
|
||||
if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.link())).valid() {
|
||||
pc = 0
|
||||
}
|
||||
|
||||
|
@ -569,7 +569,7 @@ func ptrbit(bv *gobitvector, i uintptr) uint8 {
|
||||
|
||||
// bv describes the memory starting at address scanp.
|
||||
// Adjust any pointers contained therein.
|
||||
func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f *_func) {
|
||||
func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f funcInfo) {
|
||||
bv := gobv(*cbv)
|
||||
minp := adjinfo.old.lo
|
||||
maxp := adjinfo.old.hi
|
||||
@ -589,7 +589,7 @@ func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f
|
||||
pp := (*uintptr)(add(scanp, i*sys.PtrSize))
|
||||
retry:
|
||||
p := *pp
|
||||
if f != nil && 0 < p && p < minLegalPointer && debug.invalidptr != 0 {
|
||||
if f.valid() && 0 < p && p < minLegalPointer && debug.invalidptr != 0 {
|
||||
// Looks like a junk value in a pointer slot.
|
||||
// Live analysis wrong?
|
||||
getg().m.traceback = 2
|
||||
@ -713,7 +713,7 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
|
||||
if stackDebug >= 3 {
|
||||
print(" args\n")
|
||||
}
|
||||
adjustpointers(unsafe.Pointer(frame.argp), &bv, adjinfo, nil)
|
||||
adjustpointers(unsafe.Pointer(frame.argp), &bv, adjinfo, funcInfo{})
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -157,7 +157,8 @@ func (ci *Frames) cgoNext(pc uintptr, more bool) (Frame, bool) {
|
||||
// NOTE: Func does not expose the actual unexported fields, because we return *Func
|
||||
// values to users, and we want to keep them from being able to overwrite the data
|
||||
// with (say) *f = Func{}.
|
||||
// All code operating on a *Func must call raw to get the *_func instead.
|
||||
// All code operating on a *Func must call raw() to get the *_func
|
||||
// or funcInfo() to get the funcInfo instead.
|
||||
|
||||
// A Func represents a Go function in the running binary.
|
||||
type Func struct {
|
||||
@ -168,6 +169,11 @@ func (f *Func) raw() *_func {
|
||||
return (*_func)(unsafe.Pointer(f))
|
||||
}
|
||||
|
||||
func (f *Func) funcInfo() funcInfo {
|
||||
fn := f.raw()
|
||||
return funcInfo{fn, findmoduledatap(fn.entry)}
|
||||
}
|
||||
|
||||
// PCDATA and FUNCDATA table indexes.
|
||||
//
|
||||
// See funcdata.h and ../cmd/internal/obj/funcdata.go.
|
||||
@ -365,15 +371,15 @@ func moduledataverify1(datap *moduledata) {
|
||||
for i := 0; i < nftab; i++ {
|
||||
// NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
|
||||
if datap.ftab[i].entry > datap.ftab[i+1].entry {
|
||||
f1 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
|
||||
f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
|
||||
f1 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])), datap}
|
||||
f2 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])), datap}
|
||||
f2name := "end"
|
||||
if i+1 < nftab {
|
||||
f2name = funcname(f2)
|
||||
}
|
||||
println("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name)
|
||||
for j := 0; j <= i; j++ {
|
||||
print("\t", hex(datap.ftab[j].entry), " ", funcname((*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff]))), "\n")
|
||||
print("\t", hex(datap.ftab[j].entry), " ", funcname(funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff])), datap}), "\n")
|
||||
}
|
||||
throw("invalid runtime symbol table")
|
||||
}
|
||||
@ -386,10 +392,10 @@ func moduledataverify1(datap *moduledata) {
|
||||
// But don't use the next PC if it corresponds to a foreign object chunk
|
||||
// (no pcln table, f2.pcln == 0). That chunk might have an alignment
|
||||
// more than 16 bytes.
|
||||
f := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
|
||||
f := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])), datap}
|
||||
end := f.entry
|
||||
if i+1 < nftab {
|
||||
f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
|
||||
f2 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])), datap}
|
||||
if f2.pcln != 0 {
|
||||
end = f2.entry - 16
|
||||
if end < f.entry {
|
||||
@ -419,12 +425,12 @@ func moduledataverify1(datap *moduledata) {
|
||||
// FuncForPC returns a *Func describing the function that contains the
|
||||
// given program counter address, or else nil.
|
||||
func FuncForPC(pc uintptr) *Func {
|
||||
return (*Func)(unsafe.Pointer(findfunc(pc)))
|
||||
return (*Func)(unsafe.Pointer(findfunc(pc)._func))
|
||||
}
|
||||
|
||||
// Name returns the name of the function.
|
||||
func (f *Func) Name() string {
|
||||
return funcname(f.raw())
|
||||
return funcname(f.funcInfo())
|
||||
}
|
||||
|
||||
// Entry returns the entry address of the function.
|
||||
@ -439,7 +445,7 @@ func (f *Func) Entry() uintptr {
|
||||
func (f *Func) FileLine(pc uintptr) (file string, line int) {
|
||||
// Pass strict=false here, because anyone can call this function,
|
||||
// and they might just be wrong about targetpc belonging to f.
|
||||
file, line32 := funcline1(f.raw(), pc, false)
|
||||
file, line32 := funcline1(f.funcInfo(), pc, false)
|
||||
return file, int(line32)
|
||||
}
|
||||
|
||||
@ -452,10 +458,19 @@ func findmoduledatap(pc uintptr) *moduledata {
|
||||
return nil
|
||||
}
|
||||
|
||||
func findfunc(pc uintptr) *_func {
|
||||
type funcInfo struct {
|
||||
*_func
|
||||
datap *moduledata
|
||||
}
|
||||
|
||||
func (f funcInfo) valid() bool {
|
||||
return f._func != nil
|
||||
}
|
||||
|
||||
func findfunc(pc uintptr) funcInfo {
|
||||
datap := findmoduledatap(pc)
|
||||
if datap == nil {
|
||||
return nil
|
||||
return funcInfo{}
|
||||
}
|
||||
const nsub = uintptr(len(findfuncbucket{}.subbuckets))
|
||||
|
||||
@ -491,7 +506,7 @@ func findfunc(pc uintptr) *_func {
|
||||
idx++
|
||||
}
|
||||
}
|
||||
return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff]))
|
||||
return funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff])), datap}
|
||||
}
|
||||
|
||||
type pcvalueCache struct {
|
||||
@ -506,7 +521,7 @@ type pcvalueCacheEnt struct {
|
||||
val int32
|
||||
}
|
||||
|
||||
func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 {
|
||||
func pcvalue(f funcInfo, off int32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 {
|
||||
if off == 0 {
|
||||
return -1
|
||||
}
|
||||
@ -530,14 +545,14 @@ func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict
|
||||
}
|
||||
}
|
||||
|
||||
datap := findmoduledatap(f.entry) // inefficient
|
||||
if datap == nil {
|
||||
if !f.valid() {
|
||||
if strict && panicking == 0 {
|
||||
print("runtime: no module data for ", hex(f.entry), "\n")
|
||||
throw("no module data")
|
||||
}
|
||||
return -1
|
||||
}
|
||||
datap := f.datap
|
||||
p := datap.pclntable[off:]
|
||||
pc := f.entry
|
||||
val := int32(-1)
|
||||
@ -589,41 +604,37 @@ func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict
|
||||
return -1
|
||||
}
|
||||
|
||||
func cfuncname(f *_func) *byte {
|
||||
if f == nil || f.nameoff == 0 {
|
||||
func cfuncname(f funcInfo) *byte {
|
||||
if !f.valid() || f.nameoff == 0 {
|
||||
return nil
|
||||
}
|
||||
datap := findmoduledatap(f.entry) // inefficient
|
||||
if datap == nil {
|
||||
return nil
|
||||
}
|
||||
return &datap.pclntable[f.nameoff]
|
||||
return &f.datap.pclntable[f.nameoff]
|
||||
}
|
||||
|
||||
func funcname(f *_func) string {
|
||||
func funcname(f funcInfo) string {
|
||||
return gostringnocopy(cfuncname(f))
|
||||
}
|
||||
|
||||
func funcnameFromNameoff(f *_func, nameoff int32) string {
|
||||
datap := findmoduledatap(f.entry) // inefficient
|
||||
if datap == nil {
|
||||
func funcnameFromNameoff(f funcInfo, nameoff int32) string {
|
||||
datap := f.datap
|
||||
if !f.valid() {
|
||||
return ""
|
||||
}
|
||||
cstr := &datap.pclntable[nameoff]
|
||||
return gostringnocopy(cstr)
|
||||
}
|
||||
|
||||
func funcfile(f *_func, fileno int32) string {
|
||||
datap := findmoduledatap(f.entry) // inefficient
|
||||
if datap == nil {
|
||||
func funcfile(f funcInfo, fileno int32) string {
|
||||
datap := f.datap
|
||||
if !f.valid() {
|
||||
return "?"
|
||||
}
|
||||
return gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
|
||||
}
|
||||
|
||||
func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) {
|
||||
datap := findmoduledatap(f.entry) // inefficient
|
||||
if datap == nil {
|
||||
func funcline1(f funcInfo, targetpc uintptr, strict bool) (file string, line int32) {
|
||||
datap := f.datap
|
||||
if !f.valid() {
|
||||
return "?", 0
|
||||
}
|
||||
fileno := int(pcvalue(f, f.pcfile, targetpc, nil, strict))
|
||||
@ -636,11 +647,11 @@ func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32
|
||||
return
|
||||
}
|
||||
|
||||
func funcline(f *_func, targetpc uintptr) (file string, line int32) {
|
||||
func funcline(f funcInfo, targetpc uintptr) (file string, line int32) {
|
||||
return funcline1(f, targetpc, true)
|
||||
}
|
||||
|
||||
func funcspdelta(f *_func, targetpc uintptr, cache *pcvalueCache) int32 {
|
||||
func funcspdelta(f funcInfo, targetpc uintptr, cache *pcvalueCache) int32 {
|
||||
x := pcvalue(f, f.pcsp, targetpc, cache, true)
|
||||
if x&(sys.PtrSize-1) != 0 {
|
||||
print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
|
||||
@ -648,7 +659,7 @@ func funcspdelta(f *_func, targetpc uintptr, cache *pcvalueCache) int32 {
|
||||
return x
|
||||
}
|
||||
|
||||
func pcdatavalue(f *_func, table int32, targetpc uintptr, cache *pcvalueCache) int32 {
|
||||
func pcdatavalue(f funcInfo, table int32, targetpc uintptr, cache *pcvalueCache) int32 {
|
||||
if table < 0 || table >= f.npcdata {
|
||||
return -1
|
||||
}
|
||||
@ -656,14 +667,14 @@ func pcdatavalue(f *_func, table int32, targetpc uintptr, cache *pcvalueCache) i
|
||||
return pcvalue(f, off, targetpc, cache, true)
|
||||
}
|
||||
|
||||
func funcdata(f *_func, i int32) unsafe.Pointer {
|
||||
func funcdata(f funcInfo, i int32) unsafe.Pointer {
|
||||
if i < 0 || i >= f.nfuncdata {
|
||||
return nil
|
||||
}
|
||||
p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4)
|
||||
if sys.PtrSize == 8 && uintptr(p)&4 != 0 {
|
||||
if uintptr(unsafe.Pointer(f))&4 != 0 {
|
||||
println("runtime: misaligned func", f)
|
||||
if uintptr(unsafe.Pointer(f._func))&4 != 0 {
|
||||
println("runtime: misaligned func", f._func)
|
||||
}
|
||||
p = add(p, 4)
|
||||
}
|
||||
|
@ -816,7 +816,7 @@ func traceFrameForPC(buf *traceBuf, frames map[uintptr]traceFrame, pc uintptr) (
|
||||
|
||||
var frame traceFrame
|
||||
f := findfunc(pc)
|
||||
if f == nil {
|
||||
if !f.valid() {
|
||||
frames[pc] = frame
|
||||
return frame, buf
|
||||
}
|
||||
|
@ -92,14 +92,14 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns
|
||||
if fn == nil {
|
||||
// Defer of nil function. Args don't matter.
|
||||
frame.pc = 0
|
||||
frame.fn = nil
|
||||
frame.fn = funcInfo{}
|
||||
frame.argp = 0
|
||||
frame.arglen = 0
|
||||
frame.argmap = nil
|
||||
} else {
|
||||
frame.pc = fn.fn
|
||||
f := findfunc(frame.pc)
|
||||
if f == nil {
|
||||
if !f.valid() {
|
||||
print("runtime: unknown pc in defer ", hex(frame.pc), "\n")
|
||||
throw("unknown pc")
|
||||
}
|
||||
@ -186,7 +186,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
}
|
||||
|
||||
f := findfunc(frame.pc)
|
||||
if f == nil {
|
||||
if !f.valid() {
|
||||
if callback != nil {
|
||||
print("runtime: unknown pc ", hex(frame.pc), "\n")
|
||||
throw("unknown pc")
|
||||
@ -230,10 +230,10 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
frame.fp += sys.RegSize
|
||||
}
|
||||
}
|
||||
var flr *_func
|
||||
var flr funcInfo
|
||||
if topofstack(f) {
|
||||
frame.lr = 0
|
||||
flr = nil
|
||||
flr = funcInfo{}
|
||||
} else if usesLR && f.entry == jmpdeferPC {
|
||||
// jmpdefer modifies SP/LR/PC non-atomically.
|
||||
// If a profiling interrupt arrives during jmpdefer,
|
||||
@ -259,7 +259,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
}
|
||||
}
|
||||
flr = findfunc(frame.lr)
|
||||
if flr == nil {
|
||||
if !flr.valid() {
|
||||
// This happens if you get a profiling interrupt at just the wrong time.
|
||||
// In that context it is okay to stop early.
|
||||
// But if callback is set, we're doing a garbage collection and must
|
||||
@ -403,7 +403,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
waspanic = f.entry == sigpanicPC
|
||||
|
||||
// Do not unwind past the bottom of the stack.
|
||||
if flr == nil {
|
||||
if !flr.valid() {
|
||||
break
|
||||
}
|
||||
|
||||
@ -426,7 +426,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
}
|
||||
f = findfunc(frame.pc)
|
||||
frame.fn = f
|
||||
if f == nil {
|
||||
if !f.valid() {
|
||||
frame.pc = x
|
||||
} else if funcspdelta(f, frame.pc, &cache) == 0 {
|
||||
frame.lr = x
|
||||
@ -521,7 +521,7 @@ type reflectMethodValue struct {
|
||||
// call, ctxt must be nil (getArgInfo will retrieve what it needs from
|
||||
// the active stack frame). If this is a deferred call, ctxt must be
|
||||
// the function object that was deferred.
|
||||
func getArgInfo(frame *stkframe, f *_func, needArgMap bool, ctxt *funcval) (arglen uintptr, argmap *bitvector) {
|
||||
func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (arglen uintptr, argmap *bitvector) {
|
||||
arglen = uintptr(f.args)
|
||||
if needArgMap && f.args == _ArgsSizeUnknown {
|
||||
// Extract argument bitmaps for reflect stubs from the calls they made to reflect.
|
||||
@ -593,7 +593,7 @@ func printcreatedby(gp *g) {
|
||||
// Show what created goroutine, except main goroutine (goid 1).
|
||||
pc := gp.gopc
|
||||
f := findfunc(pc)
|
||||
if f != nil && showframe(f, gp, false) && gp.goid != 1 {
|
||||
if f.valid() && showframe(f, gp, false) && gp.goid != 1 {
|
||||
print("created by ", funcname(f), "\n")
|
||||
tracepc := pc // back up to CALL instruction for funcline.
|
||||
if pc > f.entry {
|
||||
@ -673,7 +673,7 @@ func gcallers(gp *g, skip int, pcbuf []uintptr) int {
|
||||
return gentraceback(^uintptr(0), ^uintptr(0), 0, gp, skip, &pcbuf[0], len(pcbuf), nil, nil, 0)
|
||||
}
|
||||
|
||||
func showframe(f *_func, gp *g, firstFrame bool) bool {
|
||||
func showframe(f funcInfo, gp *g, firstFrame bool) bool {
|
||||
g := getg()
|
||||
if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig.ptr()) {
|
||||
return true
|
||||
@ -690,7 +690,7 @@ func showframe(f *_func, gp *g, firstFrame bool) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
return level > 1 || f != nil && contains(name, ".") && (!hasprefix(name, "runtime.") || isExportedRuntime(name))
|
||||
return level > 1 || f.valid() && contains(name, ".") && (!hasprefix(name, "runtime.") || isExportedRuntime(name))
|
||||
}
|
||||
|
||||
// isExportedRuntime reports whether name is an exported runtime function.
|
||||
@ -781,7 +781,7 @@ func tracebackothers(me *g) {
|
||||
}
|
||||
|
||||
// Does f mark the top of a goroutine stack?
|
||||
func topofstack(f *_func) bool {
|
||||
func topofstack(f funcInfo) bool {
|
||||
pc := f.entry
|
||||
return pc == goexitPC ||
|
||||
pc == mstartPC ||
|
||||
|
Loading…
Reference in New Issue
Block a user