mirror of https://github.com/golang/go.git
runtime: identify special functions by flag instead of address
When there are plugins, there may not be a unique copy of runtime functions like goexit, mcall, etc. So identifying them by entry address is problematic. Instead, keep track of each special function using a field in the symbol table. That way, multiple copies of the same runtime function will be treated identically. Fixes #24351 Fixes #23133 Change-Id: Iea3232df8a6af68509769d9ca618f530cc0f84fd Reviewed-on: https://go-review.googlesource.com/100739 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
cd2cb6e3f5
commit
9d4215311b
|
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "plugin"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
p, err := plugin.Open("issue24351.so")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
f, err := p.Lookup("B")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
c := make(chan bool)
|
||||||
|
f.(func(chan bool))(c)
|
||||||
|
<-c
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func B(c chan bool) {
|
||||||
|
go func() {
|
||||||
|
fmt.Println(1.5)
|
||||||
|
c <- true
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
@ -85,3 +85,8 @@ GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue22175 src/issue22175/main.
|
||||||
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue.22295.so issue22295.pkg
|
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue.22295.so issue22295.pkg
|
||||||
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue22295 src/issue22295.pkg/main.go
|
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue22295 src/issue22295.pkg/main.go
|
||||||
./issue22295
|
./issue22295
|
||||||
|
|
||||||
|
# Test for issue 24351
|
||||||
|
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue24351.so src/issue24351/plugin.go
|
||||||
|
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue24351 src/issue24351/main.go
|
||||||
|
./issue24351
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package objabi
|
||||||
|
|
||||||
|
// A FuncID identifies particular functions that need to be treated
|
||||||
|
// specially by the runtime.
|
||||||
|
// Note that in some situations involving plugins, there may be multiple
|
||||||
|
// copies of a particular special runtime function.
|
||||||
|
// Note: this list must match the list in runtime/symtab.go.
|
||||||
|
type FuncID uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
FuncID_normal FuncID = iota // not a special function
|
||||||
|
FuncID_goexit
|
||||||
|
FuncID_jmpdefer
|
||||||
|
FuncID_mcall
|
||||||
|
FuncID_morestack
|
||||||
|
FuncID_mstart
|
||||||
|
FuncID_rt0_go
|
||||||
|
FuncID_asmcgocall
|
||||||
|
FuncID_sigpanic
|
||||||
|
FuncID_runfinq
|
||||||
|
FuncID_bgsweep
|
||||||
|
FuncID_forcegchelper
|
||||||
|
FuncID_timerproc
|
||||||
|
FuncID_gcBgMarkWorker
|
||||||
|
FuncID_systemstack_switch
|
||||||
|
FuncID_systemstack
|
||||||
|
FuncID_cgocallback_gofunc
|
||||||
|
FuncID_gogo
|
||||||
|
FuncID_externalthreadhandler
|
||||||
|
)
|
||||||
|
|
@ -312,12 +312,47 @@ func (ctxt *Link) pclntab() {
|
||||||
}
|
}
|
||||||
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), args))
|
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), args))
|
||||||
|
|
||||||
// frame int32
|
// funcID uint32
|
||||||
// This has been removed (it was never set quite correctly anyway).
|
funcID := objabi.FuncID_normal
|
||||||
// Nothing should use it.
|
switch s.Name {
|
||||||
// Leave an obviously incorrect value.
|
case "runtime.goexit":
|
||||||
// TODO: Remove entirely.
|
funcID = objabi.FuncID_goexit
|
||||||
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), 0x1234567))
|
case "runtime.jmpdefer":
|
||||||
|
funcID = objabi.FuncID_jmpdefer
|
||||||
|
case "runtime.mcall":
|
||||||
|
funcID = objabi.FuncID_mcall
|
||||||
|
case "runtime.morestack":
|
||||||
|
funcID = objabi.FuncID_morestack
|
||||||
|
case "runtime.mstart":
|
||||||
|
funcID = objabi.FuncID_mstart
|
||||||
|
case "runtime.rt0_go":
|
||||||
|
funcID = objabi.FuncID_rt0_go
|
||||||
|
case "runtime.asmcgocall":
|
||||||
|
funcID = objabi.FuncID_asmcgocall
|
||||||
|
case "runtime.sigpanic":
|
||||||
|
funcID = objabi.FuncID_sigpanic
|
||||||
|
case "runtime.runfinq":
|
||||||
|
funcID = objabi.FuncID_runfinq
|
||||||
|
case "runtime.bgsweep":
|
||||||
|
funcID = objabi.FuncID_bgsweep
|
||||||
|
case "runtime.forcegchelper":
|
||||||
|
funcID = objabi.FuncID_forcegchelper
|
||||||
|
case "runtime.timerproc":
|
||||||
|
funcID = objabi.FuncID_timerproc
|
||||||
|
case "runtime.gcBgMarkWorker":
|
||||||
|
funcID = objabi.FuncID_gcBgMarkWorker
|
||||||
|
case "runtime.systemstack_switch":
|
||||||
|
funcID = objabi.FuncID_systemstack_switch
|
||||||
|
case "runtime.systemstack":
|
||||||
|
funcID = objabi.FuncID_systemstack
|
||||||
|
case "runtime.cgocallback_gofunc":
|
||||||
|
funcID = objabi.FuncID_cgocallback_gofunc
|
||||||
|
case "runtime.gogo":
|
||||||
|
funcID = objabi.FuncID_gogo
|
||||||
|
case "runtime.externalthreadhandler":
|
||||||
|
funcID = objabi.FuncID_externalthreadhandler
|
||||||
|
}
|
||||||
|
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(funcID)))
|
||||||
|
|
||||||
if pcln != &pclntabZpcln {
|
if pcln != &pclntabZpcln {
|
||||||
renumberfiles(ctxt, pcln.File, &pcln.Pcfile)
|
renumberfiles(ctxt, pcln.File, &pcln.Pcfile)
|
||||||
|
|
|
||||||
|
|
@ -304,8 +304,6 @@ func osinit() {
|
||||||
|
|
||||||
disableWER()
|
disableWER()
|
||||||
|
|
||||||
externalthreadhandlerp = funcPC(externalthreadhandler)
|
|
||||||
|
|
||||||
initExceptionHandler()
|
initExceptionHandler()
|
||||||
|
|
||||||
stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
|
stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
|
||||||
|
|
|
||||||
|
|
@ -393,6 +393,11 @@ func releaseSudog(s *sudog) {
|
||||||
|
|
||||||
// funcPC returns the entry PC of the function f.
|
// funcPC returns the entry PC of the function f.
|
||||||
// It assumes that f is a func value. Otherwise the behavior is undefined.
|
// It assumes that f is a func value. Otherwise the behavior is undefined.
|
||||||
|
// CAREFUL: In programs with plugins, funcPC can return different values
|
||||||
|
// for the same function (because there are actually multiple copies of
|
||||||
|
// the same function in the address space). To be safe, don't use the
|
||||||
|
// results of this function in any == expression. It is only safe to
|
||||||
|
// use the result as an address at which to start executing code.
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func funcPC(f interface{}) uintptr {
|
func funcPC(f interface{}) uintptr {
|
||||||
return **(**uintptr)(add(unsafe.Pointer(&f), sys.PtrSize))
|
return **(**uintptr)(add(unsafe.Pointer(&f), sys.PtrSize))
|
||||||
|
|
@ -3789,8 +3794,8 @@ func setsSP(pc uintptr) bool {
|
||||||
// so assume the worst and stop traceback
|
// so assume the worst and stop traceback
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
switch f.entry {
|
switch f.funcID {
|
||||||
case gogoPC, systemstackPC, mcallPC, morestackPC:
|
case funcID_gogo, funcID_systemstack, funcID_mcall, funcID_morestack:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
|
|
@ -638,8 +638,8 @@ type _func struct {
|
||||||
entry uintptr // start pc
|
entry uintptr // start pc
|
||||||
nameoff int32 // function name
|
nameoff int32 // function name
|
||||||
|
|
||||||
args int32 // in/out args size
|
args int32 // in/out args size
|
||||||
_ int32 // previously legacy frame size; kept for layout compatibility
|
funcID funcID // set for certain special runtime functions
|
||||||
|
|
||||||
pcsp int32
|
pcsp int32
|
||||||
pcfile int32
|
pcfile int32
|
||||||
|
|
|
||||||
|
|
@ -619,7 +619,7 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
|
||||||
if stackDebug >= 2 {
|
if stackDebug >= 2 {
|
||||||
print(" adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n")
|
print(" adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n")
|
||||||
}
|
}
|
||||||
if f.entry == systemstack_switchPC {
|
if f.funcID == funcID_systemstack_switch {
|
||||||
// A special routine at the bottom of stack of a goroutine that does an systemstack call.
|
// A special routine at the bottom of stack of a goroutine that does an systemstack call.
|
||||||
// We will allow it to be copied even though we don't
|
// We will allow it to be copied even though we don't
|
||||||
// have full GC info for it (because it is written in asm).
|
// have full GC info for it (because it is written in asm).
|
||||||
|
|
@ -1110,7 +1110,8 @@ func shrinkstack(gp *g) {
|
||||||
if debug.gcshrinkstackoff > 0 {
|
if debug.gcshrinkstackoff > 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if gp.startpc == gcBgMarkWorkerPC {
|
f := findfunc(gp.startpc)
|
||||||
|
if f.valid() && f.funcID == funcID_gcBgMarkWorker {
|
||||||
// We're not allowed to shrink the gcBgMarkWorker
|
// We're not allowed to shrink the gcBgMarkWorker
|
||||||
// stack (see gcBgMarkWorker for explanation).
|
// stack (see gcBgMarkWorker for explanation).
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ again:
|
||||||
}
|
}
|
||||||
se.pcExpander.init(ncallers[0], se.wasPanic)
|
se.pcExpander.init(ncallers[0], se.wasPanic)
|
||||||
ncallers = ncallers[1:]
|
ncallers = ncallers[1:]
|
||||||
se.wasPanic = se.pcExpander.funcInfo.valid() && se.pcExpander.funcInfo.entry == sigpanicPC
|
se.wasPanic = se.pcExpander.funcInfo.valid() && se.pcExpander.funcInfo.funcID == funcID_sigpanic
|
||||||
if se.skip > 0 {
|
if se.skip > 0 {
|
||||||
for ; se.skip > 0; se.skip-- {
|
for ; se.skip > 0; se.skip-- {
|
||||||
se.pcExpander.next()
|
se.pcExpander.next()
|
||||||
|
|
@ -349,6 +349,35 @@ const (
|
||||||
_ArgsSizeUnknown = -0x80000000
|
_ArgsSizeUnknown = -0x80000000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// A FuncID identifies particular functions that need to be treated
|
||||||
|
// specially by the runtime.
|
||||||
|
// Note that in some situations involving plugins, there may be multiple
|
||||||
|
// copies of a particular special runtime function.
|
||||||
|
// Note: this list must match the list in cmd/internal/objabi/funcid.go.
|
||||||
|
type funcID uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
funcID_normal funcID = iota // not a special function
|
||||||
|
funcID_goexit
|
||||||
|
funcID_jmpdefer
|
||||||
|
funcID_mcall
|
||||||
|
funcID_morestack
|
||||||
|
funcID_mstart
|
||||||
|
funcID_rt0_go
|
||||||
|
funcID_asmcgocall
|
||||||
|
funcID_sigpanic
|
||||||
|
funcID_runfinq
|
||||||
|
funcID_bgsweep
|
||||||
|
funcID_forcegchelper
|
||||||
|
funcID_timerproc
|
||||||
|
funcID_gcBgMarkWorker
|
||||||
|
funcID_systemstack_switch
|
||||||
|
funcID_systemstack
|
||||||
|
funcID_cgocallback_gofunc
|
||||||
|
funcID_gogo
|
||||||
|
funcID_externalthreadhandler
|
||||||
|
)
|
||||||
|
|
||||||
// moduledata records information about the layout of the executable
|
// moduledata records information about the layout of the executable
|
||||||
// image. It is written by the linker. Any changes here must be
|
// image. It is written by the linker. Any changes here must be
|
||||||
// matched changes to the code in cmd/internal/ld/symtab.go:symtab.
|
// matched changes to the code in cmd/internal/ld/symtab.go:symtab.
|
||||||
|
|
@ -648,7 +677,6 @@ func findfunc(pc uintptr) funcInfo {
|
||||||
idx = uint32(len(datap.ftab) - 1)
|
idx = uint32(len(datap.ftab) - 1)
|
||||||
}
|
}
|
||||||
if pc < datap.ftab[idx].entry {
|
if pc < datap.ftab[idx].entry {
|
||||||
|
|
||||||
// With multiple text sections, the idx might reference a function address that
|
// With multiple text sections, the idx might reference a function address that
|
||||||
// is higher than the pc being searched, so search backward until the matching address is found.
|
// is higher than the pc being searched, so search backward until the matching address is found.
|
||||||
|
|
||||||
|
|
@ -659,7 +687,6 @@ func findfunc(pc uintptr) funcInfo {
|
||||||
throw("findfunc: bad findfunctab entry idx")
|
throw("findfunc: bad findfunctab entry idx")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// linear search to find func with pc >= entry.
|
// linear search to find func with pc >= entry.
|
||||||
for datap.ftab[idx+1].entry <= pc {
|
for datap.ftab[idx+1].entry <= pc {
|
||||||
idx++
|
idx++
|
||||||
|
|
|
||||||
|
|
@ -35,56 +35,14 @@ import (
|
||||||
|
|
||||||
const usesLR = sys.MinFrameSize > 0
|
const usesLR = sys.MinFrameSize > 0
|
||||||
|
|
||||||
var (
|
var skipPC uintptr
|
||||||
// initialized in tracebackinit
|
|
||||||
goexitPC uintptr
|
|
||||||
jmpdeferPC uintptr
|
|
||||||
mcallPC uintptr
|
|
||||||
morestackPC uintptr
|
|
||||||
mstartPC uintptr
|
|
||||||
rt0_goPC uintptr
|
|
||||||
asmcgocallPC uintptr
|
|
||||||
sigpanicPC uintptr
|
|
||||||
runfinqPC uintptr
|
|
||||||
bgsweepPC uintptr
|
|
||||||
forcegchelperPC uintptr
|
|
||||||
timerprocPC uintptr
|
|
||||||
gcBgMarkWorkerPC uintptr
|
|
||||||
systemstack_switchPC uintptr
|
|
||||||
systemstackPC uintptr
|
|
||||||
cgocallback_gofuncPC uintptr
|
|
||||||
skipPC uintptr
|
|
||||||
|
|
||||||
gogoPC uintptr
|
|
||||||
|
|
||||||
externalthreadhandlerp uintptr // initialized elsewhere
|
|
||||||
)
|
|
||||||
|
|
||||||
func tracebackinit() {
|
func tracebackinit() {
|
||||||
// Go variable initialization happens late during runtime startup.
|
// Go variable initialization happens late during runtime startup.
|
||||||
// Instead of initializing the variables above in the declarations,
|
// Instead of initializing the variables above in the declarations,
|
||||||
// schedinit calls this function so that the variables are
|
// schedinit calls this function so that the variables are
|
||||||
// initialized and available earlier in the startup sequence.
|
// initialized and available earlier in the startup sequence.
|
||||||
goexitPC = funcPC(goexit)
|
|
||||||
jmpdeferPC = funcPC(jmpdefer)
|
|
||||||
mcallPC = funcPC(mcall)
|
|
||||||
morestackPC = funcPC(morestack)
|
|
||||||
mstartPC = funcPC(mstart)
|
|
||||||
rt0_goPC = funcPC(rt0_go)
|
|
||||||
asmcgocallPC = funcPC(asmcgocall)
|
|
||||||
sigpanicPC = funcPC(sigpanic)
|
|
||||||
runfinqPC = funcPC(runfinq)
|
|
||||||
bgsweepPC = funcPC(bgsweep)
|
|
||||||
forcegchelperPC = funcPC(forcegchelper)
|
|
||||||
timerprocPC = funcPC(timerproc)
|
|
||||||
gcBgMarkWorkerPC = funcPC(gcBgMarkWorker)
|
|
||||||
systemstack_switchPC = funcPC(systemstack_switch)
|
|
||||||
systemstackPC = funcPC(systemstack)
|
|
||||||
cgocallback_gofuncPC = funcPC(cgocallback_gofunc)
|
|
||||||
skipPC = funcPC(skipPleaseUseCallersFrames)
|
skipPC = funcPC(skipPleaseUseCallersFrames)
|
||||||
|
|
||||||
// used by sigprof handler
|
|
||||||
gogoPC = funcPC(gogo)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Traceback over the deferred function calls.
|
// Traceback over the deferred function calls.
|
||||||
|
|
@ -137,9 +95,6 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||||
if skip > 0 && callback != nil {
|
if skip > 0 && callback != nil {
|
||||||
throw("gentraceback callback cannot be used with non-zero skip")
|
throw("gentraceback callback cannot be used with non-zero skip")
|
||||||
}
|
}
|
||||||
if goexitPC == 0 {
|
|
||||||
throw("gentraceback before goexitPC initialization")
|
|
||||||
}
|
|
||||||
g := getg()
|
g := getg()
|
||||||
if g == gp && g == g.m.curg {
|
if g == gp && g == g.m.curg {
|
||||||
// The starting sp has been passed in as a uintptr, and the caller may
|
// The starting sp has been passed in as a uintptr, and the caller may
|
||||||
|
|
@ -241,7 +196,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||||
// g0, this systemstack is at the top of the stack.
|
// g0, this systemstack is at the top of the stack.
|
||||||
// if we're not on g0 or there's a no curg, then this is a regular call.
|
// if we're not on g0 or there's a no curg, then this is a regular call.
|
||||||
sp := frame.sp
|
sp := frame.sp
|
||||||
if flags&_TraceJumpStack != 0 && f.entry == systemstackPC && gp == g.m.g0 && gp.m.curg != nil {
|
if flags&_TraceJumpStack != 0 && f.funcID == funcID_systemstack && gp == g.m.g0 && gp.m.curg != nil {
|
||||||
sp = gp.m.curg.sched.sp
|
sp = gp.m.curg.sched.sp
|
||||||
frame.sp = sp
|
frame.sp = sp
|
||||||
cgoCtxt = gp.m.curg.cgoCtxt
|
cgoCtxt = gp.m.curg.cgoCtxt
|
||||||
|
|
@ -256,7 +211,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||||
if topofstack(f, gp.m != nil && gp == gp.m.g0) {
|
if topofstack(f, gp.m != nil && gp == gp.m.g0) {
|
||||||
frame.lr = 0
|
frame.lr = 0
|
||||||
flr = funcInfo{}
|
flr = funcInfo{}
|
||||||
} else if usesLR && f.entry == jmpdeferPC {
|
} else if usesLR && f.funcID == funcID_jmpdefer {
|
||||||
// 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,
|
||||||
// the stack unwind may see a mismatched register set
|
// the stack unwind may see a mismatched register set
|
||||||
|
|
@ -287,7 +242,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||||
// 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
|
||||||
// get everything, so crash loudly.
|
// get everything, so crash loudly.
|
||||||
doPrint := printing
|
doPrint := printing
|
||||||
if doPrint && gp.m.incgo && f.entry == sigpanicPC {
|
if doPrint && gp.m.incgo && f.funcID == funcID_sigpanic {
|
||||||
// We can inject sigpanic
|
// We can inject sigpanic
|
||||||
// calls directly into C code,
|
// calls directly into C code,
|
||||||
// in which case we'll see a C
|
// in which case we'll see a C
|
||||||
|
|
@ -396,8 +351,8 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||||
// if there's room, pcbuf[1] is a skip PC that encodes the number of skipped frames in pcbuf[0]
|
// if there's room, pcbuf[1] is a skip PC that encodes the number of skipped frames in pcbuf[0]
|
||||||
if n+1 < max {
|
if n+1 < max {
|
||||||
n++
|
n++
|
||||||
skipPC := funcPC(skipPleaseUseCallersFrames) + uintptr(logicalSkipped)
|
pc := skipPC + uintptr(logicalSkipped)
|
||||||
(*[1 << 20]uintptr)(unsafe.Pointer(pcbuf))[n] = skipPC
|
(*[1 << 20]uintptr)(unsafe.Pointer(pcbuf))[n] = pc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -466,7 +421,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||||
n++
|
n++
|
||||||
|
|
||||||
skipped:
|
skipped:
|
||||||
if f.entry == cgocallback_gofuncPC && len(cgoCtxt) > 0 {
|
if f.funcID == funcID_cgocallback_gofunc && len(cgoCtxt) > 0 {
|
||||||
ctxt := cgoCtxt[len(cgoCtxt)-1]
|
ctxt := cgoCtxt[len(cgoCtxt)-1]
|
||||||
cgoCtxt = cgoCtxt[:len(cgoCtxt)-1]
|
cgoCtxt = cgoCtxt[:len(cgoCtxt)-1]
|
||||||
|
|
||||||
|
|
@ -478,7 +433,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
waspanic = f.entry == sigpanicPC
|
waspanic = f.funcID == funcID_sigpanic
|
||||||
|
|
||||||
// Do not unwind past the bottom of the stack.
|
// Do not unwind past the bottom of the stack.
|
||||||
if !flr.valid() {
|
if !flr.valid() {
|
||||||
|
|
@ -931,30 +886,32 @@ func tracebackHexdump(stk stack, frame *stkframe, bad uintptr) {
|
||||||
|
|
||||||
// Does f mark the top of a goroutine stack?
|
// Does f mark the top of a goroutine stack?
|
||||||
func topofstack(f funcInfo, g0 bool) bool {
|
func topofstack(f funcInfo, g0 bool) bool {
|
||||||
pc := f.entry
|
return f.funcID == funcID_goexit ||
|
||||||
return pc == goexitPC ||
|
f.funcID == funcID_mstart ||
|
||||||
pc == mstartPC ||
|
f.funcID == funcID_mcall ||
|
||||||
pc == mcallPC ||
|
f.funcID == funcID_morestack ||
|
||||||
pc == morestackPC ||
|
f.funcID == funcID_rt0_go ||
|
||||||
pc == rt0_goPC ||
|
f.funcID == funcID_externalthreadhandler ||
|
||||||
externalthreadhandlerp != 0 && pc == externalthreadhandlerp ||
|
|
||||||
// asmcgocall is TOS on the system stack because it
|
// asmcgocall is TOS on the system stack because it
|
||||||
// switches to the system stack, but in this case we
|
// switches to the system stack, but in this case we
|
||||||
// can come back to the regular stack and still want
|
// can come back to the regular stack and still want
|
||||||
// to be able to unwind through the call that appeared
|
// to be able to unwind through the call that appeared
|
||||||
// on the regular stack.
|
// on the regular stack.
|
||||||
(g0 && pc == asmcgocallPC)
|
(g0 && f.funcID == funcID_asmcgocall)
|
||||||
}
|
}
|
||||||
|
|
||||||
// isSystemGoroutine reports whether the goroutine g must be omitted in
|
// isSystemGoroutine reports whether the goroutine g must be omitted in
|
||||||
// stack dumps and deadlock detector.
|
// stack dumps and deadlock detector.
|
||||||
func isSystemGoroutine(gp *g) bool {
|
func isSystemGoroutine(gp *g) bool {
|
||||||
pc := gp.startpc
|
f := findfunc(gp.startpc)
|
||||||
return pc == runfinqPC && !fingRunning ||
|
if !f.valid() {
|
||||||
pc == bgsweepPC ||
|
return false
|
||||||
pc == forcegchelperPC ||
|
}
|
||||||
pc == timerprocPC ||
|
return f.funcID == funcID_runfinq && !fingRunning ||
|
||||||
pc == gcBgMarkWorkerPC
|
f.funcID == funcID_bgsweep ||
|
||||||
|
f.funcID == funcID_forcegchelper ||
|
||||||
|
f.funcID == funcID_timerproc ||
|
||||||
|
f.funcID == funcID_gcBgMarkWorker
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCgoTraceback records three C functions to use to gather
|
// SetCgoTraceback records three C functions to use to gather
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue