aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2015-11-18 13:20:35 -0500
committerAustin Clements <austin@google.com>2015-11-20 19:53:41 +0000
commit2a6c7739b5bdb5fbaf743d89a18bd466fb178fe1 (patch)
tree40625f58609c49307f246838fd9e845c6f9fe7cf
parenta10b27094cbddd7d470281590a50b5b38265e541 (diff)
downloadgo-2a6c7739b5bdb5fbaf743d89a18bd466fb178fe1.tar.gz
go-2a6c7739b5bdb5fbaf743d89a18bd466fb178fe1.zip
[release-branch.go1.5] runtime: handle sigprof in stackBarrier
Currently, if a profiling signal happens in the middle of stackBarrier, gentraceback may see inconsistencies between stkbar and the barriers on the stack and it will certainly get the wrong return PC for stackBarrier. In most cases, the return PC won't be a PC at all and this will immediately abort the traceback (which is considered okay for a sigprof), but if it happens to be a valid PC this may sent gentraceback down a rabbit hole. Fix this by detecting when the gentraceback starts in stackBarrier and simulating the completion of the barrier to get the correct initial frame. Change-Id: Ib11f705ac9194925f63fe5dfbfc84013a38333e6 Reviewed-on: https://go-review.googlesource.com/17035 Reviewed-by: Russ Cox <rsc@golang.org> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-on: https://go-review.googlesource.com/17056
-rw-r--r--src/runtime/traceback.go28
1 files changed, 28 insertions, 0 deletions
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 2def3592d6..aed6cbd694 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -188,6 +188,34 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
}
f := findfunc(frame.pc)
+ if f.entry == stackBarrierPC {
+ // We got caught in the middle of a stack barrier
+ // (presumably by a signal), so stkbar may be
+ // inconsistent with the barriers on the stack.
+ // Simulate the completion of the barrier.
+ //
+ // On x86, SP will be exactly one word above
+ // savedLRPtr. On LR machines, SP will be above
+ // savedLRPtr by some frame size.
+ var stkbarPos uintptr
+ if len(stkbar) > 0 && stkbar[0].savedLRPtr < sp0 {
+ // stackBarrier has not incremented stkbarPos.
+ stkbarPos = gp.stkbarPos
+ } else if gp.stkbarPos > 0 && gp.stkbar[gp.stkbarPos-1].savedLRPtr < sp0 {
+ // stackBarrier has incremented stkbarPos.
+ stkbarPos = gp.stkbarPos - 1
+ } else {
+ printlock()
+ print("runtime: failed to unwind through stackBarrier at SP ", hex(sp0), " index ", gp.stkbarPos, "; ")
+ gcPrintStkbars(gp.stkbar)
+ print("\n")
+ throw("inconsistent state in stackBarrier")
+ }
+
+ frame.pc = gp.stkbar[stkbarPos].savedLRVal
+ stkbar = gp.stkbar[stkbarPos+1:]
+ f = findfunc(frame.pc)
+ }
if f == nil {
if callback != nil {
print("runtime: unknown pc ", hex(frame.pc), "\n")