From 4b3906fec35b81e9bce7af5e1ce64c2a431c8301 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 5 Sep 2014 14:58:54 -0400 Subject: [PATCH] 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 --- src/pkg/runtime/softfloat_arm.c | 69 ++++++++++++++++++++++++++------- src/pkg/runtime/vlop_arm.s | 12 ++++++ 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/src/pkg/runtime/softfloat_arm.c b/src/pkg/runtime/softfloat_arm.c index 09b0cf20ac..3f3f33a19e 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] = ®s; 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*)®s->r0); - if(skip == 0) { - runtime·printf("sfloat2 %p %x\n", lr, *lr); + first = true; + while(skip = stepflt(pc, (uint32*)®s->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*)®s->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 6abcabad20..b4b905bb7a 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 -- 2.48.1