aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/traceback.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/traceback.go')
-rw-r--r--src/runtime/traceback.go58
1 files changed, 43 insertions, 15 deletions
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index cc5e01eb8b..4c2010493a 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -99,8 +99,9 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
if skip > 0 && callback != nil {
throw("gentraceback callback cannot be used with non-zero skip")
}
- g := getg()
- if g == gp && g == g.m.curg {
+
+ // Don't call this "g"; it's too easy get "g" and "gp" confused.
+ if ourg := getg(); ourg == gp && ourg == ourg.m.curg {
// The starting sp has been passed in as a uintptr, and the caller may
// have other uintptr-typed stack references as well.
// If during one of the calls that got us here or during one of the
@@ -196,16 +197,29 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
// Found an actual function.
// Derive frame pointer and link register.
if frame.fp == 0 {
- // We want to jump over the systemstack switch. If we're running on the
- // 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.
- sp := frame.sp
- if flags&_TraceJumpStack != 0 && f.funcID == funcID_systemstack && gp == g.m.g0 && gp.m.curg != nil {
- sp = gp.m.curg.sched.sp
- frame.sp = sp
- cgoCtxt = gp.m.curg.cgoCtxt
+ // Jump over system stack transitions. If we're on g0 and there's a user
+ // goroutine, try to jump. Otherwise this is a regular call.
+ if flags&_TraceJumpStack != 0 && gp == gp.m.g0 && gp.m.curg != nil {
+ switch f.funcID {
+ case funcID_morestack:
+ // morestack does not return normally -- newstack()
+ // gogo's to curg.sched. Match that.
+ // This keeps morestack() from showing up in the backtrace,
+ // but that makes some sense since it'll never be returned
+ // to.
+ frame.pc = gp.m.curg.sched.pc
+ frame.fn = findfunc(frame.pc)
+ f = frame.fn
+ frame.sp = gp.m.curg.sched.sp
+ cgoCtxt = gp.m.curg.cgoCtxt
+ case funcID_systemstack:
+ // systemstack returns normally, so just follow the
+ // stack transition.
+ frame.sp = gp.m.curg.sched.sp
+ cgoCtxt = gp.m.curg.cgoCtxt
+ }
}
- frame.fp = sp + uintptr(funcspdelta(f, frame.pc, &cache))
+ frame.fp = frame.sp + uintptr(funcspdelta(f, frame.pc, &cache))
if !usesLR {
// On x86, call instruction pushes return PC before entering new function.
frame.fp += sys.RegSize
@@ -271,7 +285,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
// If framepointer_enabled and there's a frame, then
// there's a saved bp here.
- if framepointer_enabled && GOARCH == "amd64" && frame.varp > frame.sp {
+ if frame.varp > frame.sp && (framepointer_enabled && GOARCH == "amd64" || GOARCH == "arm64") {
frame.varp -= sys.RegSize
}
@@ -425,7 +439,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
if frame.pc > f.entry {
print(" +", hex(frame.pc-f.entry))
}
- if g.m.throwing > 0 && gp == g.m.curg || level >= 2 {
+ if gp.m != nil && gp.m.throwing > 0 && gp == gp.m.curg || level >= 2 {
print(" fp=", hex(frame.fp), " sp=", hex(frame.sp), " pc=", hex(frame.pc))
}
print("\n")
@@ -679,7 +693,14 @@ func traceback(pc, sp, lr uintptr, gp *g) {
// the initial PC must not be rewound to the previous instruction.
// (All the saved pairs record a PC that is a return address, so we
// rewind it into the CALL instruction.)
+// If gp.m.libcall{g,pc,sp} information is available, it uses that information in preference to
+// the pc/sp/lr passed in.
func tracebacktrap(pc, sp, lr uintptr, gp *g) {
+ if gp.m.libcallsp != 0 {
+ // We're in C code somewhere, traceback from the saved position.
+ traceback1(gp.m.libcallpc, gp.m.libcallsp, 0, gp.m.libcallg.ptr(), 0)
+ return
+ }
traceback1(pc, sp, lr, gp, _TraceTrap)
}
@@ -836,7 +857,7 @@ func showfuncinfo(f funcInfo, firstFrame, elideWrapper bool) bool {
return true
}
- return contains(name, ".") && (!hasprefix(name, "runtime.") || isExportedRuntime(name))
+ return contains(name, ".") && (!hasPrefix(name, "runtime.") || isExportedRuntime(name))
}
// isExportedRuntime reports whether name is an exported runtime function.
@@ -1015,7 +1036,7 @@ func isSystemGoroutine(gp *g) bool {
// back into user code.
return !fingRunning
}
- return hasprefix(funcname(f), "runtime.")
+ return hasPrefix(funcname(f), "runtime.")
}
// SetCgoTraceback records three C functions to use to gather
@@ -1115,6 +1136,13 @@ func isSystemGoroutine(gp *g) bool {
// to the symbolizer function, return the file/line of the call
// instruction. No additional subtraction is required or appropriate.
//
+// On all platforms, the traceback function is invoked when a call from
+// Go to C to Go requests a stack trace. On linux/amd64, linux/ppc64le,
+// and freebsd/amd64, the traceback function is also invoked when a
+// signal is received by a thread that is executing a cgo call. The
+// traceback function should not make assumptions about when it is
+// called, as future versions of Go may make additional calls.
+//
// The symbolizer function will be called with a single argument, a
// pointer to a struct:
//