mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00: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
20 changed files with 84 additions and 73 deletions
|
|
@ -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) {
|
||||||
// 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,
|
||||||
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) {
|
||||||
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 {
|
||||||
// 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) {
|
||||||
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) {
|
||||||
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) {
|
||||||
// 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) {
|
||||||
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 {
|
||||||
|
|
||||||
// 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) {
|
||||||
// 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) {
|
||||||
// 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) {
|
||||||
// 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) {
|
||||||
// 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) {
|
||||||
// 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) {
|
||||||
// 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) {
|
||||||
// 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) {
|
||||||
// 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 {
|
||||||
|
|
||||||
// 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
|
||||||
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 {
|
||||||
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) {
|
||||||
// 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 {
|
||||||
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) {
|
||||||
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) {
|
||||||
// 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) {
|
||||||
// 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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
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
|
return nil
|
||||||
}
|
}
|
||||||
datap := findmoduledatap(f.entry) // inefficient
|
return &f.datap.pclntable[f.nameoff]
|
||||||
if datap == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &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
|
||||||
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 {
|
||||||
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
|
||||||
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) (
|
||||||
|
|
||||||
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
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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
|
||||||
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
|
||||||
}
|
}
|
||||||
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 {
|
||||||
// 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) {
|
||||||
// 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 {
|
||||||
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 {
|
||||||
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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 ||
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue