Commit 4b3906fe authored by Russ Cox's avatar Russ Cox

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://golang.org/cl/138130043
parent f93e21ac
...@@ -100,6 +100,8 @@ static const uint8 conditions[10/2] = { ...@@ -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) (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 // returns number of words that the fp instruction
// is occupying, 0 if next instruction isn't float. // is occupying, 0 if next instruction isn't float.
static uint32 static uint32
...@@ -221,6 +223,11 @@ stage1: // load/store regn is cpureg, regm is 8bit offset ...@@ -221,6 +223,11 @@ stage1: // load/store regn is cpureg, regm is 8bit offset
case 0xed900a00: // single load case 0xed900a00: // single load
addr = (uint32*)(regs[regn] + regm); 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]; m->freglo[regd] = addr[0];
if(trace) if(trace)
...@@ -230,6 +237,11 @@ stage1: // load/store regn is cpureg, regm is 8bit offset ...@@ -230,6 +237,11 @@ stage1: // load/store regn is cpureg, regm is 8bit offset
case 0xed900b00: // double load case 0xed900b00: // double load
addr = (uint32*)(regs[regn] + regm); 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->freglo[regd] = addr[0];
m->freghi[regd] = addr[1]; m->freghi[regd] = addr[1];
...@@ -240,6 +252,11 @@ stage1: // load/store regn is cpureg, regm is 8bit offset ...@@ -240,6 +252,11 @@ stage1: // load/store regn is cpureg, regm is 8bit offset
case 0xed800a00: // single store case 0xed800a00: // single store
addr = (uint32*)(regs[regn] + regm); 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]; addr[0] = m->freglo[regd];
if(trace) if(trace)
...@@ -249,6 +266,11 @@ stage1: // load/store regn is cpureg, regm is 8bit offset ...@@ -249,6 +266,11 @@ stage1: // load/store regn is cpureg, regm is 8bit offset
case 0xed800b00: // double store case 0xed800b00: // double store
addr = (uint32*)(regs[regn] + regm); 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[0] = m->freglo[regd];
addr[1] = m->freghi[regd]; addr[1] = m->freghi[regd];
...@@ -607,42 +629,59 @@ struct Sfregs ...@@ -607,42 +629,59 @@ struct Sfregs
}; };
static void sfloat2(void); static void sfloat2(void);
void _sfloatpanic(void);
#pragma textflag NOSPLIT #pragma textflag NOSPLIT
uint32* uint32*
runtime·_sfloat2(uint32 *lr, Sfregs regs) runtime·_sfloat2(uint32 *pc, Sfregs regs)
{ {
void (*fn)(void); void (*fn)(void);
g->m->ptrarg[0] = lr; g->m->ptrarg[0] = pc;
g->m->ptrarg[1] = &regs; g->m->ptrarg[1] = &regs;
fn = sfloat2; fn = sfloat2;
runtime·onM(&fn); runtime·onM(&fn);
lr = g->m->ptrarg[0]; pc = g->m->ptrarg[0];
g->m->ptrarg[0] = nil; g->m->ptrarg[0] = nil;
return lr; return pc;
} }
static void static void
sfloat2(void) sfloat2(void)
{ {
uint32 *lr; uint32 *pc;
G *curg;
Sfregs *regs; Sfregs *regs;
uint32 skip; int32 skip;
bool first;
lr = g->m->ptrarg[0]; pc = g->m->ptrarg[0];
regs = g->m->ptrarg[1]; regs = g->m->ptrarg[1];
g->m->ptrarg[0] = nil; g->m->ptrarg[0] = nil;
g->m->ptrarg[1] = nil; g->m->ptrarg[1] = nil;
skip = stepflt(lr, (uint32*)&regs->r0); first = true;
if(skip == 0) { while(skip = stepflt(pc, (uint32*)&regs->r0)) {
runtime·printf("sfloat2 %p %x\n", lr, *lr); 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 fabort(); // not ok to fail first instruction
} }
lr += skip; g->m->ptrarg[0] = pc;
while(skip = stepflt(lr, (uint32*)&regs->r0))
lr += skip;
g->m->ptrarg[0] = lr;
} }
...@@ -94,6 +94,18 @@ TEXT _sfloat(SB), NOSPLIT, $68-0 // 4 arg + 14*4 saved regs + cpsr + return valu ...@@ -94,6 +94,18 @@ TEXT _sfloat(SB), NOSPLIT, $68-0 // 4 arg + 14*4 saved regs + cpsr + return valu
MOVW 8(R13), R0 MOVW 8(R13), R0
RET 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) // func udiv(n, d uint32) (q, r uint32)
// Reference: // Reference:
// Sloss, Andrew et. al; ARM System Developer's Guide: Designing and Optimizing System Software // Sloss, Andrew et. al; ARM System Developer's Guide: Designing and Optimizing System Software
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment