summaryrefslogtreecommitdiff
path: root/src/pkg
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-09-05 14:58:54 -0400
committerRuss Cox <rsc@golang.org>2014-09-05 14:58:54 -0400
commite008530606766d3b43ddddaf3b40c062dd7dd02c (patch)
tree073c37fdfe2d931fce37e50bd45e1afc39fc43cb /src/pkg
parent1d6a8c81e28b1bd997a7e5b036ad79e59318f951 (diff)
downloadgo-e008530606766d3b43ddddaf3b40c062dd7dd02c.tar.gz
runtime: handle nil ptr load/store in arm software floating point
We cannot let a real panic start there, because there is C code on the stack, and worse, there is an assembly frame with a saved copy of the registers and we have no idea which ones are pointers. Instead, detect the nil ptr load/store and return out of the C and assembly into a stub that will start the call to sigpanic. Fixes GOARM=5 build. LGTM=iant R=golang-codereviews, iant CC=dave, golang-codereviews, minux, r https://codereview.appspot.com/138130043
Diffstat (limited to 'src/pkg')
-rw-r--r--src/pkg/runtime/softfloat_arm.c69
-rw-r--r--src/pkg/runtime/vlop_arm.s12
2 files changed, 66 insertions, 15 deletions
diff --git a/src/pkg/runtime/softfloat_arm.c b/src/pkg/runtime/softfloat_arm.c
index 09b0cf20a..3f3f33a19 100644
--- a/src/pkg/runtime/softfloat_arm.c
+++ b/src/pkg/runtime/softfloat_arm.c
@@ -100,6 +100,8 @@ static const uint8 conditions[10/2] = {
(FLAGS_Z >> 28), // 8: HI (C set and Z clear), 9: LS (C clear and Z set)
};
+#define FAULT (0x80000000U) // impossible PC offset
+
// returns number of words that the fp instruction
// is occupying, 0 if next instruction isn't float.
static uint32
@@ -221,6 +223,11 @@ stage1: // load/store regn is cpureg, regm is 8bit offset
case 0xed900a00: // single load
addr = (uint32*)(regs[regn] + regm);
+ if((uintptr)addr < 4096) {
+ if(trace)
+ runtime·printf("*** load @%p => fault\n", addr);
+ return FAULT;
+ }
m->freglo[regd] = addr[0];
if(trace)
@@ -230,6 +237,11 @@ stage1: // load/store regn is cpureg, regm is 8bit offset
case 0xed900b00: // double load
addr = (uint32*)(regs[regn] + regm);
+ if((uintptr)addr < 4096) {
+ if(trace)
+ runtime·printf("*** double load @%p => fault\n", addr);
+ return FAULT;
+ }
m->freglo[regd] = addr[0];
m->freghi[regd] = addr[1];
@@ -240,6 +252,11 @@ stage1: // load/store regn is cpureg, regm is 8bit offset
case 0xed800a00: // single store
addr = (uint32*)(regs[regn] + regm);
+ if((uintptr)addr < 4096) {
+ if(trace)
+ runtime·printf("*** store @%p => fault\n", addr);
+ return FAULT;
+ }
addr[0] = m->freglo[regd];
if(trace)
@@ -249,6 +266,11 @@ stage1: // load/store regn is cpureg, regm is 8bit offset
case 0xed800b00: // double store
addr = (uint32*)(regs[regn] + regm);
+ if((uintptr)addr < 4096) {
+ if(trace)
+ runtime·printf("*** double store @%p => fault\n", addr);
+ return FAULT;
+ }
addr[0] = m->freglo[regd];
addr[1] = m->freghi[regd];
@@ -607,42 +629,59 @@ struct Sfregs
};
static void sfloat2(void);
+void _sfloatpanic(void);
#pragma textflag NOSPLIT
uint32*
-runtime·_sfloat2(uint32 *lr, Sfregs regs)
+runtime·_sfloat2(uint32 *pc, Sfregs regs)
{
void (*fn)(void);
- g->m->ptrarg[0] = lr;
+ g->m->ptrarg[0] = pc;
g->m->ptrarg[1] = &regs;
fn = sfloat2;
runtime·onM(&fn);
- lr = g->m->ptrarg[0];
+ pc = g->m->ptrarg[0];
g->m->ptrarg[0] = nil;
- return lr;
+ return pc;
}
static void
sfloat2(void)
{
- uint32 *lr;
+ uint32 *pc;
+ G *curg;
Sfregs *regs;
- uint32 skip;
+ int32 skip;
+ bool first;
- lr = g->m->ptrarg[0];
+ pc = g->m->ptrarg[0];
regs = g->m->ptrarg[1];
g->m->ptrarg[0] = nil;
g->m->ptrarg[1] = nil;
- skip = stepflt(lr, (uint32*)&regs->r0);
- if(skip == 0) {
- runtime·printf("sfloat2 %p %x\n", lr, *lr);
+ first = true;
+ while(skip = stepflt(pc, (uint32*)&regs->r0)) {
+ first = false;
+ if(skip == FAULT) {
+ // Encountered bad address in store/load.
+ // Record signal information and return to assembly
+ // trampoline that fakes the call.
+ enum { SIGSEGV = 11 };
+ curg = g->m->curg;
+ curg->sig = SIGSEGV;
+ curg->sigcode0 = 0;
+ curg->sigcode1 = 0;
+ curg->sigpc = (uint32)pc;
+ pc = (uint32*)_sfloatpanic;
+ break;
+ }
+ pc += skip;
+ }
+ if(first) {
+ runtime·printf("sfloat2 %p %x\n", pc, *pc);
fabort(); // not ok to fail first instruction
}
-
- lr += skip;
- while(skip = stepflt(lr, (uint32*)&regs->r0))
- lr += skip;
- g->m->ptrarg[0] = lr;
+
+ g->m->ptrarg[0] = pc;
}
diff --git a/src/pkg/runtime/vlop_arm.s b/src/pkg/runtime/vlop_arm.s
index 6abcabad2..b4b905bb7 100644
--- a/src/pkg/runtime/vlop_arm.s
+++ b/src/pkg/runtime/vlop_arm.s
@@ -94,6 +94,18 @@ TEXT _sfloat(SB), NOSPLIT, $68-0 // 4 arg + 14*4 saved regs + cpsr + return valu
MOVW 8(R13), R0
RET
+// trampoline for _sfloat2 panic.
+// _sfloat2 instructs _sfloat to return here.
+// We need to push a fake saved LR onto the stack,
+// load the signal fault address into LR, and jump
+// to the real sigpanic.
+// This simulates what sighandler does for a memory fault.
+TEXT _sfloatpanic(SB),NOSPLIT,$-4
+ MOVW $0, R0
+ MOVW.W R0, -4(R13)
+ MOVW g_sigpc(g), LR
+ B runtime·sigpanic(SB)
+
// func udiv(n, d uint32) (q, r uint32)
// Reference:
// Sloss, Andrew et. al; ARM System Developer's Guide: Designing and Optimizing System Software