aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-06-12 16:55:36 -0400
committerRuss Cox <rsc@golang.org>2014-06-12 16:55:36 -0400
commit1305c4ce9d0af20b84bacf9029f839ad8e56b392 (patch)
tree8f2fb95b92164fbb20bf0817fa16d2851bd65c8d
parent5c196b842a59bbb723005f1f84bfc29f687c79ba (diff)
downloadgo-1305c4ce9d0af20b84bacf9029f839ad8e56b392.tar.gz
go-1305c4ce9d0af20b84bacf9029f839ad8e56b392.zip
[release-branch.go1.3] runtime: do not trace past jmpdefer during pprof traceback on arm
««« CL 107970043 / b336da131a84 runtime: do not trace past jmpdefer during pprof traceback on arm jmpdefer modifies PC, SP, and LR, and not atomically, so walking past jmpdefer will often end up in a state where the three are not a consistent execution snapshot. This was causing warning messages a few frames later when the traceback realized it was confused, but given the right memory it could easily crash instead. Update #8153 LGTM=minux, iant R=golang-codereviews, minux, iant CC=golang-codereviews, r https://golang.org/cl/107970043 »»» LGTM=r R=golang-codereviews, r CC=adg, golang-codereviews, iant https://golang.org/cl/101260043
-rw-r--r--src/pkg/runtime/asm_arm.s4
-rw-r--r--src/pkg/runtime/traceback_arm.c13
2 files changed, 17 insertions, 0 deletions
diff --git a/src/pkg/runtime/asm_arm.s b/src/pkg/runtime/asm_arm.s
index 024649be07..1aea9036a7 100644
--- a/src/pkg/runtime/asm_arm.s
+++ b/src/pkg/runtime/asm_arm.s
@@ -394,6 +394,10 @@ TEXT runtime·lessstack(SB), NOSPLIT, $-4-0
// 1. grab stored LR for caller
// 2. sub 4 bytes to get back to BL deferreturn
// 3. B to fn
+// TODO(rsc): Push things on stack and then use pop
+// to load all registers simultaneously, so that a profiling
+// interrupt can never see mismatched SP/LR/PC.
+// (And double-check that pop is atomic in that way.)
TEXT runtime·jmpdefer(SB), NOSPLIT, $0-8
MOVW 0(SP), LR
MOVW $-4(LR), LR // BL deferreturn
diff --git a/src/pkg/runtime/traceback_arm.c b/src/pkg/runtime/traceback_arm.c
index 8d1fc54266..d15244c2a9 100644
--- a/src/pkg/runtime/traceback_arm.c
+++ b/src/pkg/runtime/traceback_arm.c
@@ -110,6 +110,19 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
if(runtime·topofstack(f)) {
frame.lr = 0;
flr = nil;
+ } else if(f->entry == (uintptr)runtime·jmpdefer) {
+ // jmpdefer modifies SP/LR/PC non-atomically.
+ // If a profiling interrupt arrives during jmpdefer,
+ // the stack unwind may see a mismatched register set
+ // and get confused. Stop if we see PC within jmpdefer
+ // to avoid that confusion.
+ // See golang.org/issue/8153.
+ // This check can be deleted if jmpdefer is changed
+ // to restore all three atomically using pop.
+ if(callback != nil)
+ runtime·throw("traceback_arm: found jmpdefer when tracing with callback");
+ frame.lr = 0;
+ flr = nil;
} else {
if((n == 0 && frame.sp < frame.fp) || frame.lr == 0)
frame.lr = *(uintptr*)frame.sp;