Commit 0efc8b21 authored by Austin Clements's avatar Austin Clements

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: default avatarMichael Hudson-Doyle <michael.hudson@canonical.com>
parent 6533cc1c
...@@ -174,7 +174,7 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) { ...@@ -174,7 +174,7 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
return return
} }
f := findfunc(rpc[1]) f := findfunc(rpc[1])
if f == nil { if !f.valid() {
// TODO(rsc): Probably a bug? // TODO(rsc): Probably a bug?
// The C version said "have retpc at least" // The C version said "have retpc at least"
// but actually returned pc=0. // but actually returned pc=0.
...@@ -187,7 +187,7 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) { ...@@ -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. // 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 // 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. // 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-- xpc--
} }
file, line32 := funcline(f, xpc) file, line32 := funcline(f, xpc)
......
...@@ -565,7 +565,7 @@ func dumpmemprof_callback(b *bucket, nstk uintptr, pstk *uintptr, size, allocs, ...@@ -565,7 +565,7 @@ func dumpmemprof_callback(b *bucket, nstk uintptr, pstk *uintptr, size, allocs,
for i := uintptr(0); i < nstk; i++ { for i := uintptr(0); i < nstk; i++ {
pc := stk[i] pc := stk[i]
f := findfunc(pc) f := findfunc(pc)
if f == nil { if !f.valid() {
var buf [64]byte var buf [64]byte
n := len(buf) n := len(buf)
n-- n--
......
...@@ -1877,7 +1877,7 @@ func getgcmask(ep interface{}) (mask []byte) { ...@@ -1877,7 +1877,7 @@ func getgcmask(ep interface{}) (mask []byte) {
frame.sp = uintptr(p) frame.sp = uintptr(p)
_g_ := getg() _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) 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 f := frame.fn
targetpc := frame.continpc targetpc := frame.continpc
if targetpc == 0 { if targetpc == 0 {
......
...@@ -62,7 +62,7 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int { ...@@ -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, // but we do recognize the top pointer on the stack as code,
// then assume this was a call to non-code and treat like // then assume this was a call to non-code and treat like
// pc == 0, to make unwinding show the context. // 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 pc = 0
} }
......
...@@ -95,7 +95,7 @@ func pluginftabverify(md *moduledata) { ...@@ -95,7 +95,7 @@ func pluginftabverify(md *moduledata) {
continue 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) name := funcname(f)
// A common bug is f.entry has a relocation to a duplicate // A common bug is f.entry has a relocation to a duplicate
...@@ -104,7 +104,7 @@ func pluginftabverify(md *moduledata) { ...@@ -104,7 +104,7 @@ func pluginftabverify(md *moduledata) {
name2 := "none" name2 := "none"
entry2 := uintptr(0) entry2 := uintptr(0)
f2 := findfunc(entry) f2 := findfunc(entry)
if f2 != nil { if f2.valid() {
name2 = funcname(f2) name2 = funcname(f2)
entry2 = f2.entry entry2 = f2.entry
} }
......
...@@ -3336,7 +3336,7 @@ func sigprofNonGoPC(pc uintptr) { ...@@ -3336,7 +3336,7 @@ func sigprofNonGoPC(pc uintptr) {
// or putting one on the stack at the right offset. // or putting one on the stack at the right offset.
func setsSP(pc uintptr) bool { func setsSP(pc uintptr) bool {
f := findfunc(pc) f := findfunc(pc)
if f == nil { if !f.valid() {
// couldn't find the function for this PC, // couldn't find the function for this PC,
// so assume the worst and stop traceback // so assume the worst and stop traceback
return true return true
......
...@@ -98,7 +98,7 @@ func raceSymbolizeCode(ctx *symbolizeCodeContext) { ...@@ -98,7 +98,7 @@ func raceSymbolizeCode(ctx *symbolizeCodeContext) {
if f != nil { if f != nil {
file, line := f.FileLine(ctx.pc) file, line := f.FileLine(ctx.pc)
if line != 0 { if line != 0 {
ctx.fn = cfuncname(f.raw()) ctx.fn = cfuncname(f.funcInfo())
ctx.line = uintptr(line) ctx.line = uintptr(line)
ctx.file = &bytes(file)[0] // assume NUL-terminated ctx.file = &bytes(file)[0] // assume NUL-terminated
ctx.off = ctx.pc - f.Entry() ctx.off = ctx.pc - f.Entry()
......
...@@ -685,7 +685,7 @@ type _panic struct { ...@@ -685,7 +685,7 @@ type _panic struct {
// stack traces // stack traces
type stkframe struct { type stkframe struct {
fn *_func // function being run fn funcInfo // function being run
pc uintptr // program counter within fn pc uintptr // program counter within fn
continpc uintptr // program counter where execution can continue, or 0 if not continpc uintptr // program counter where execution can continue, or 0 if not
lr uintptr // program counter at caller aka link register lr uintptr // program counter at caller aka link register
......
...@@ -60,7 +60,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { ...@@ -60,7 +60,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
// but we do recognize the top pointer on the stack as code, // but we do recognize the top pointer on the stack as code,
// then assume this was a call to non-code and treat like // then assume this was a call to non-code and treat like
// pc == 0, to make unwinding show the context. // 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 pc = 0
} }
......
...@@ -71,7 +71,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { ...@@ -71,7 +71,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
// but we do recognize the top pointer on the stack as code, // but we do recognize the top pointer on the stack as code,
// then assume this was a call to non-code and treat like // then assume this was a call to non-code and treat like
// pc == 0, to make unwinding show the context. // 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 pc = 0
} }
......
...@@ -57,7 +57,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { ...@@ -57,7 +57,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
// but we do recognize the link register as code, // but we do recognize the link register as code,
// then assume this was a call to non-code and treat like // then assume this was a call to non-code and treat like
// pc == 0, to make unwinding show the context. // 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 pc = 0
} }
......
...@@ -73,7 +73,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { ...@@ -73,7 +73,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
// but we do recognize the link register as code, // but we do recognize the link register as code,
// then assume this was a call to non-code and treat like // then assume this was a call to non-code and treat like
// pc == 0, to make unwinding show the context. // 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 pc = 0
} }
......
...@@ -103,7 +103,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { ...@@ -103,7 +103,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
// but we do recognize the link register as code, // but we do recognize the link register as code,
// then assume this was a call to non-code and treat like // then assume this was a call to non-code and treat like
// pc == 0, to make unwinding show the context. // 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 pc = 0
} }
......
...@@ -77,7 +77,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { ...@@ -77,7 +77,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
// but we do recognize the link register as code, // but we do recognize the link register as code,
// then assume this was a call to non-code and treat like // then assume this was a call to non-code and treat like
// pc == 0, to make unwinding show the context. // 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 pc = 0
} }
......
...@@ -74,7 +74,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { ...@@ -74,7 +74,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
// but we do recognize the link register as code, // but we do recognize the link register as code,
// then assume this was a call to non-code and treat like // then assume this was a call to non-code and treat like
// pc == 0, to make unwinding show the context. // 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 pc = 0
} }
......
...@@ -78,7 +78,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { ...@@ -78,7 +78,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
// but we do recognize the link register as code, // but we do recognize the link register as code,
// then assume this was a call to non-code and treat like // then assume this was a call to non-code and treat like
// pc == 0, to make unwinding show the context. // 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 pc = 0
} }
......
...@@ -569,7 +569,7 @@ func ptrbit(bv *gobitvector, i uintptr) uint8 { ...@@ -569,7 +569,7 @@ func ptrbit(bv *gobitvector, i uintptr) uint8 {
// bv describes the memory starting at address scanp. // bv describes the memory starting at address scanp.
// Adjust any pointers contained therein. // 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) bv := gobv(*cbv)
minp := adjinfo.old.lo minp := adjinfo.old.lo
maxp := adjinfo.old.hi maxp := adjinfo.old.hi
...@@ -589,7 +589,7 @@ func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f ...@@ -589,7 +589,7 @@ func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f
pp := (*uintptr)(add(scanp, i*sys.PtrSize)) pp := (*uintptr)(add(scanp, i*sys.PtrSize))
retry: retry:
p := *pp 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. // Looks like a junk value in a pointer slot.
// Live analysis wrong? // Live analysis wrong?
getg().m.traceback = 2 getg().m.traceback = 2
...@@ -713,7 +713,7 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool { ...@@ -713,7 +713,7 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
if stackDebug >= 3 { if stackDebug >= 3 {
print(" args\n") print(" args\n")
} }
adjustpointers(unsafe.Pointer(frame.argp), &bv, adjinfo, nil) adjustpointers(unsafe.Pointer(frame.argp), &bv, adjinfo, funcInfo{})
} }
return true return true
} }
......
...@@ -157,7 +157,8 @@ func (ci *Frames) cgoNext(pc uintptr, more bool) (Frame, bool) { ...@@ -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 // 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 // values to users, and we want to keep them from being able to overwrite the data
// with (say) *f = Func{}. // 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. // A Func represents a Go function in the running binary.
type Func struct { type Func struct {
...@@ -168,6 +169,11 @@ func (f *Func) raw() *_func { ...@@ -168,6 +169,11 @@ func (f *Func) raw() *_func {
return (*_func)(unsafe.Pointer(f)) return (*_func)(unsafe.Pointer(f))
} }
func (f *Func) funcInfo() funcInfo {
fn := f.raw()
return funcInfo{fn, findmoduledatap(fn.entry)}
}
// PCDATA and FUNCDATA table indexes. // PCDATA and FUNCDATA table indexes.
// //
// See funcdata.h and ../cmd/internal/obj/funcdata.go. // See funcdata.h and ../cmd/internal/obj/funcdata.go.
...@@ -365,15 +371,15 @@ func moduledataverify1(datap *moduledata) { ...@@ -365,15 +371,15 @@ func moduledataverify1(datap *moduledata) {
for i := 0; i < nftab; i++ { for i := 0; i < nftab; i++ {
// NOTE: ftab[nftab].entry is legal; it is the address beyond the final function. // NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
if datap.ftab[i].entry > datap.ftab[i+1].entry { if datap.ftab[i].entry > datap.ftab[i+1].entry {
f1 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])) f1 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])), datap}
f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])) f2 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])), datap}
f2name := "end" f2name := "end"
if i+1 < nftab { if i+1 < nftab {
f2name = funcname(f2) 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) 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++ { 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") throw("invalid runtime symbol table")
} }
...@@ -386,10 +392,10 @@ func moduledataverify1(datap *moduledata) { ...@@ -386,10 +392,10 @@ func moduledataverify1(datap *moduledata) {
// But don't use the next PC if it corresponds to a foreign object chunk // 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 // (no pcln table, f2.pcln == 0). That chunk might have an alignment
// more than 16 bytes. // 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 end := f.entry
if i+1 < nftab { 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 { if f2.pcln != 0 {
end = f2.entry - 16 end = f2.entry - 16
if end < f.entry { if end < f.entry {
...@@ -419,12 +425,12 @@ func moduledataverify1(datap *moduledata) { ...@@ -419,12 +425,12 @@ func moduledataverify1(datap *moduledata) {
// FuncForPC returns a *Func describing the function that contains the // FuncForPC returns a *Func describing the function that contains the
// given program counter address, or else nil. // given program counter address, or else nil.
func FuncForPC(pc uintptr) *Func { 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. // Name returns the name of the function.
func (f *Func) Name() string { func (f *Func) Name() string {
return funcname(f.raw()) return funcname(f.funcInfo())
} }
// Entry returns the entry address of the function. // Entry returns the entry address of the function.
...@@ -439,7 +445,7 @@ func (f *Func) Entry() uintptr { ...@@ -439,7 +445,7 @@ func (f *Func) Entry() uintptr {
func (f *Func) FileLine(pc uintptr) (file string, line int) { func (f *Func) FileLine(pc uintptr) (file string, line int) {
// Pass strict=false here, because anyone can call this function, // Pass strict=false here, because anyone can call this function,
// and they might just be wrong about targetpc belonging to f. // 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) return file, int(line32)
} }
...@@ -452,10 +458,19 @@ func findmoduledatap(pc uintptr) *moduledata { ...@@ -452,10 +458,19 @@ func findmoduledatap(pc uintptr) *moduledata {
return nil 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) datap := findmoduledatap(pc)
if datap == nil { if datap == nil {
return nil return funcInfo{}
} }
const nsub = uintptr(len(findfuncbucket{}.subbuckets)) const nsub = uintptr(len(findfuncbucket{}.subbuckets))
...@@ -491,7 +506,7 @@ func findfunc(pc uintptr) *_func { ...@@ -491,7 +506,7 @@ func findfunc(pc uintptr) *_func {
idx++ 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 { type pcvalueCache struct {
...@@ -506,7 +521,7 @@ type pcvalueCacheEnt struct { ...@@ -506,7 +521,7 @@ type pcvalueCacheEnt struct {
val int32 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 { if off == 0 {
return -1 return -1
} }
...@@ -530,14 +545,14 @@ func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict ...@@ -530,14 +545,14 @@ func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict
} }
} }
datap := findmoduledatap(f.entry) // inefficient if !f.valid() {
if datap == nil {
if strict && panicking == 0 { if strict && panicking == 0 {
print("runtime: no module data for ", hex(f.entry), "\n") print("runtime: no module data for ", hex(f.entry), "\n")
throw("no module data") throw("no module data")
} }
return -1 return -1
} }
datap := f.datap
p := datap.pclntable[off:] p := datap.pclntable[off:]
pc := f.entry pc := f.entry
val := int32(-1) val := int32(-1)
...@@ -589,41 +604,37 @@ func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict ...@@ -589,41 +604,37 @@ func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict
return -1 return -1
} }
func cfuncname(f *_func) *byte { func cfuncname(f funcInfo) *byte {
if f == nil || f.nameoff == 0 { if !f.valid() || f.nameoff == 0 {
return nil
}
datap := findmoduledatap(f.entry) // inefficient
if datap == nil {
return 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)) return gostringnocopy(cfuncname(f))
} }
func funcnameFromNameoff(f *_func, nameoff int32) string { func funcnameFromNameoff(f funcInfo, nameoff int32) string {
datap := findmoduledatap(f.entry) // inefficient datap := f.datap
if datap == nil { if !f.valid() {
return "" return ""
} }
cstr := &datap.pclntable[nameoff] cstr := &datap.pclntable[nameoff]
return gostringnocopy(cstr) return gostringnocopy(cstr)
} }
func funcfile(f *_func, fileno int32) string { func funcfile(f funcInfo, fileno int32) string {
datap := findmoduledatap(f.entry) // inefficient datap := f.datap
if datap == nil { if !f.valid() {
return "?" return "?"
} }
return gostringnocopy(&datap.pclntable[datap.filetab[fileno]]) return gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
} }
func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) { func funcline1(f funcInfo, targetpc uintptr, strict bool) (file string, line int32) {
datap := findmoduledatap(f.entry) // inefficient datap := f.datap
if datap == nil { if !f.valid() {
return "?", 0 return "?", 0
} }
fileno := int(pcvalue(f, f.pcfile, targetpc, nil, strict)) 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 ...@@ -636,11 +647,11 @@ func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32
return 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) 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) x := pcvalue(f, f.pcsp, targetpc, cache, true)
if x&(sys.PtrSize-1) != 0 { if x&(sys.PtrSize-1) != 0 {
print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n") 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 { ...@@ -648,7 +659,7 @@ func funcspdelta(f *_func, targetpc uintptr, cache *pcvalueCache) int32 {
return x 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 { if table < 0 || table >= f.npcdata {
return -1 return -1
} }
...@@ -656,14 +667,14 @@ func pcdatavalue(f *_func, table int32, targetpc uintptr, cache *pcvalueCache) i ...@@ -656,14 +667,14 @@ func pcdatavalue(f *_func, table int32, targetpc uintptr, cache *pcvalueCache) i
return pcvalue(f, off, targetpc, cache, true) 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 { if i < 0 || i >= f.nfuncdata {
return nil return nil
} }
p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4) p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4)
if sys.PtrSize == 8 && uintptr(p)&4 != 0 { if sys.PtrSize == 8 && uintptr(p)&4 != 0 {
if uintptr(unsafe.Pointer(f))&4 != 0 { if uintptr(unsafe.Pointer(f._func))&4 != 0 {
println("runtime: misaligned func", f) println("runtime: misaligned func", f._func)
} }
p = add(p, 4) p = add(p, 4)
} }
......
...@@ -816,7 +816,7 @@ func traceFrameForPC(buf *traceBuf, frames map[uintptr]traceFrame, pc uintptr) ( ...@@ -816,7 +816,7 @@ func traceFrameForPC(buf *traceBuf, frames map[uintptr]traceFrame, pc uintptr) (
var frame traceFrame var frame traceFrame
f := findfunc(pc) f := findfunc(pc)
if f == nil { if !f.valid() {
frames[pc] = frame frames[pc] = frame
return frame, buf return frame, buf
} }
......
...@@ -92,14 +92,14 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns ...@@ -92,14 +92,14 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns
if fn == nil { if fn == nil {
// Defer of nil function. Args don't matter. // Defer of nil function. Args don't matter.
frame.pc = 0 frame.pc = 0
frame.fn = nil frame.fn = funcInfo{}
frame.argp = 0 frame.argp = 0
frame.arglen = 0 frame.arglen = 0
frame.argmap = nil frame.argmap = nil
} else { } else {
frame.pc = fn.fn frame.pc = fn.fn
f := findfunc(frame.pc) f := findfunc(frame.pc)
if f == nil { if !f.valid() {
print("runtime: unknown pc in defer ", hex(frame.pc), "\n") print("runtime: unknown pc in defer ", hex(frame.pc), "\n")
throw("unknown pc") throw("unknown pc")
} }
...@@ -186,7 +186,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in ...@@ -186,7 +186,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
} }
f := findfunc(frame.pc) f := findfunc(frame.pc)
if f == nil { if !f.valid() {
if callback != nil { if callback != nil {
print("runtime: unknown pc ", hex(frame.pc), "\n") print("runtime: unknown pc ", hex(frame.pc), "\n")
throw("unknown pc") throw("unknown pc")
...@@ -230,10 +230,10 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in ...@@ -230,10 +230,10 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
frame.fp += sys.RegSize frame.fp += sys.RegSize
} }
} }
var flr *_func var flr funcInfo
if topofstack(f) { if topofstack(f) {
frame.lr = 0 frame.lr = 0
flr = nil flr = funcInfo{}
} else if usesLR && f.entry == jmpdeferPC { } else if usesLR && f.entry == jmpdeferPC {
// jmpdefer modifies SP/LR/PC non-atomically. // jmpdefer modifies SP/LR/PC non-atomically.
// If a profiling interrupt arrives during jmpdefer, // 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 ...@@ -259,7 +259,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
} }
} }
flr = findfunc(frame.lr) flr = findfunc(frame.lr)
if flr == nil { if !flr.valid() {
// This happens if you get a profiling interrupt at just the wrong time. // This happens if you get a profiling interrupt at just the wrong time.
// In that context it is okay to stop early. // In that context it is okay to stop early.
// But if callback is set, we're doing a garbage collection and must // 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 ...@@ -403,7 +403,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
waspanic = f.entry == sigpanicPC waspanic = f.entry == sigpanicPC
// Do not unwind past the bottom of the stack. // Do not unwind past the bottom of the stack.
if flr == nil { if !flr.valid() {
break break
} }
...@@ -426,7 +426,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in ...@@ -426,7 +426,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
} }
f = findfunc(frame.pc) f = findfunc(frame.pc)
frame.fn = f frame.fn = f
if f == nil { if !f.valid() {
frame.pc = x frame.pc = x
} else if funcspdelta(f, frame.pc, &cache) == 0 { } else if funcspdelta(f, frame.pc, &cache) == 0 {
frame.lr = x frame.lr = x
...@@ -521,7 +521,7 @@ type reflectMethodValue struct { ...@@ -521,7 +521,7 @@ type reflectMethodValue struct {
// call, ctxt must be nil (getArgInfo will retrieve what it needs from // 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 active stack frame). If this is a deferred call, ctxt must be
// the function object that was deferred. // 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) arglen = uintptr(f.args)
if needArgMap && f.args == _ArgsSizeUnknown { if needArgMap && f.args == _ArgsSizeUnknown {
// Extract argument bitmaps for reflect stubs from the calls they made to reflect. // Extract argument bitmaps for reflect stubs from the calls they made to reflect.
...@@ -593,7 +593,7 @@ func printcreatedby(gp *g) { ...@@ -593,7 +593,7 @@ func printcreatedby(gp *g) {
// Show what created goroutine, except main goroutine (goid 1). // Show what created goroutine, except main goroutine (goid 1).
pc := gp.gopc pc := gp.gopc
f := findfunc(pc) 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") print("created by ", funcname(f), "\n")
tracepc := pc // back up to CALL instruction for funcline. tracepc := pc // back up to CALL instruction for funcline.
if pc > f.entry { if pc > f.entry {
...@@ -673,7 +673,7 @@ func gcallers(gp *g, skip int, pcbuf []uintptr) int { ...@@ -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) 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() g := getg()
if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig.ptr()) { if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig.ptr()) {
return true return true
...@@ -690,7 +690,7 @@ func showframe(f *_func, gp *g, firstFrame bool) bool { ...@@ -690,7 +690,7 @@ func showframe(f *_func, gp *g, firstFrame bool) bool {
return true 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. // isExportedRuntime reports whether name is an exported runtime function.
...@@ -781,7 +781,7 @@ func tracebackothers(me *g) { ...@@ -781,7 +781,7 @@ func tracebackothers(me *g) {
} }
// Does f mark the top of a goroutine stack? // Does f mark the top of a goroutine stack?
func topofstack(f *_func) bool { func topofstack(f funcInfo) bool {
pc := f.entry pc := f.entry
return pc == goexitPC || return pc == goexitPC ||
pc == mstartPC || pc == mstartPC ||
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment