diff --git a/src/runtime/extern.go b/src/runtime/extern.go index ddcb81fdc7..896bfc4fcb 100644 --- a/src/runtime/extern.go +++ b/src/runtime/extern.go @@ -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) diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go index 32e393db2b..35f6124643 100644 --- a/src/runtime/heapdump.go +++ b/src/runtime/heapdump.go @@ -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-- diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index 7bead96904..3e782f50da 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -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 { diff --git a/src/runtime/os3_plan9.go b/src/runtime/os3_plan9.go index 5aa6b67a85..5d4b5a6698 100644 --- a/src/runtime/os3_plan9.go +++ b/src/runtime/os3_plan9.go @@ -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 } diff --git a/src/runtime/plugin.go b/src/runtime/plugin.go index ea246509cc..682caacb21 100644 --- a/src/runtime/plugin.go +++ b/src/runtime/plugin.go @@ -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 } diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 722bdf7b39..c9c451351c 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -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 diff --git a/src/runtime/race.go b/src/runtime/race.go index 1034e35ceb..49495cc783 100644 --- a/src/runtime/race.go +++ b/src/runtime/race.go @@ -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() diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index 7c1591994e..8b6bddf456 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -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 diff --git a/src/runtime/signal_386.go b/src/runtime/signal_386.go index 8807552da2..416c7c2715 100644 --- a/src/runtime/signal_386.go +++ b/src/runtime/signal_386.go @@ -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 } diff --git a/src/runtime/signal_amd64x.go b/src/runtime/signal_amd64x.go index c8a6513261..fad5fc0f8a 100644 --- a/src/runtime/signal_amd64x.go +++ b/src/runtime/signal_amd64x.go @@ -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 } diff --git a/src/runtime/signal_arm.go b/src/runtime/signal_arm.go index 9748544e0e..d00b225ef6 100644 --- a/src/runtime/signal_arm.go +++ b/src/runtime/signal_arm.go @@ -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 } diff --git a/src/runtime/signal_arm64.go b/src/runtime/signal_arm64.go index 4c6df425d8..1db052538c 100644 --- a/src/runtime/signal_arm64.go +++ b/src/runtime/signal_arm64.go @@ -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 } diff --git a/src/runtime/signal_linux_s390x.go b/src/runtime/signal_linux_s390x.go index de71ee950d..a31f436411 100644 --- a/src/runtime/signal_linux_s390x.go +++ b/src/runtime/signal_linux_s390x.go @@ -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 } diff --git a/src/runtime/signal_mips64x.go b/src/runtime/signal_mips64x.go index 973ec2dc36..9546a5af99 100644 --- a/src/runtime/signal_mips64x.go +++ b/src/runtime/signal_mips64x.go @@ -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 } diff --git a/src/runtime/signal_mipsx.go b/src/runtime/signal_mipsx.go index 62df79caeb..1c545ec8cb 100644 --- a/src/runtime/signal_mipsx.go +++ b/src/runtime/signal_mipsx.go @@ -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 } diff --git a/src/runtime/signal_ppc64x.go b/src/runtime/signal_ppc64x.go index f09f890aee..03cb996f3f 100644 --- a/src/runtime/signal_ppc64x.go +++ b/src/runtime/signal_ppc64x.go @@ -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 } diff --git a/src/runtime/stack.go b/src/runtime/stack.go index d6a4e4ea80..92b8a2b921 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -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 } diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index b16e5445bd..a31cf55c29 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -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) } diff --git a/src/runtime/trace.go b/src/runtime/trace.go index 9f319cd570..c29c162333 100644 --- a/src/runtime/trace.go +++ b/src/runtime/trace.go @@ -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 } diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 39ef8a2a64..f72b068516 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -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 ||