commit 4135fa2ab106a92a7c46b4ea0b11659c93b644dc
parent 6c054b5cf94f0a5b872451f50a5eac2517dbd3c5
Author: Russ Cox <rsc@swtch.com>
Date: Sun, 29 Jun 2008 21:26:48 -0400
9vx/OSX: handle EXC_BAD_INSTRUCTION that signals segmentation limit fault
Diffstat:
src/9vx/osx/signal.c | | | 105 | ++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------- |
1 file changed, 66 insertions(+), 39 deletions(-)
diff --git a/src/9vx/osx/signal.c b/src/9vx/osx/signal.c
@@ -89,6 +89,8 @@ wrapper(siginfo_t *siginfo,
"movl %0, %%eax\n"
"movl %1, %%ebx\n"
"movl $0xdeadbeef, %%esp\n"
+ ".globl _wrapper_bad\n"
+ "_wrapper_bad:\n"
".long 0xffff0b0f\n"
: : "r" (mcontext), "r" (siginfo));
}
@@ -137,17 +139,36 @@ catch_exception_raise(mach_port_t exception_port,
uint *sp;
mcontext_t stk_mcontext;
void (*handler)(int, siginfo_t*, void*);
+ ulong addr;
+ int signo;
n = x86_THREAD_STATE32_COUNT;
ret = thread_get_state(thread, x86_THREAD_STATE32, (void*)®s, &n);
if(ret != KERN_SUCCESS)
panic("mach get regs failed: %d", ret);
+ addr = 0;
+ save_regs = regs;
+
switch(exception){
case EXC_BAD_ACCESS:
+ signo = SIGBUS;
+ addr = code_vector[1];
+ handler = sigbus;
+ goto Trigger;
+
case EXC_BREAKPOINT:
+ signo = SIGTRAP;
+ handler = sigtrap;
+ regs.eflags &= ~EFLAGS_TF;
+ goto Trigger;
+
case EXC_ARITHMETIC:
- save_regs = regs;
+ signo = SIGFPE;
+ handler = sigfpe;
+ goto Trigger;
+
+ Trigger:
if(invx32)
regs.esp = (uint)altstack;
else if(regs.ss != normal.ss)
@@ -162,24 +183,8 @@ catch_exception_raise(mach_port_t exception_port,
stk_mcontext = alloc(®s, sizeof *stk_mcontext);
memset(stk_siginfo, 0, sizeof *stk_siginfo);
- switch(exception){
- default:
- panic("osx/signal.c missing case %d", exception);
- case EXC_BAD_ACCESS:
- stk_siginfo->si_signo = SIGBUS;
- stk_siginfo->si_addr = (void*)code_vector[1];
- handler = sigbus;
- break;
- case EXC_BREAKPOINT:
- stk_siginfo->si_signo = SIGTRAP;
- handler = sigtrap;
- regs.eflags &= ~EFLAGS_TF;
- break;
- case EXC_ARITHMETIC:
- stk_siginfo->si_signo = SIGFPE;
- handler = sigfpe;
- break;
- }
+ stk_siginfo->si_signo = signo;
+ stk_siginfo->si_addr = (void*)addr;
stk_mcontext->ss = save_regs;
n = x86_FLOAT_STATE32_COUNT;
@@ -209,28 +214,50 @@ catch_exception_raise(mach_port_t exception_port,
}
return KERN_SUCCESS;
- case EXC_BAD_INSTRUCTION:
- /* Thread signalling that it's done with sigsegv. */
- if(regs.esp != 0xdeadbeef){
- dumpregs1(®s);
- return KERN_INVALID_RIGHT;
- panic("bad instruction eip=%p", regs.eip);
+ case EXC_BAD_INSTRUCTION:;
+ /*
+ * We use an invalid instruction in wrapper to note
+ * that we're done with the signal handler, but
+ * Mach sends the same exception (different code_vector[0])
+ * when it gets the GP fault triggered by an address
+ * greater than the segment limit. Catch both.
+ */
+ extern char wrapper_bad[];
+ if(regs.eip == (ulong)wrapper_bad && regs.esp == 0xdeadbeef){
+ stk_mcontext = (mcontext_t)regs.eax;
+ stk_siginfo = (siginfo_t*)regs.ebx;
+ if(0 && stk_siginfo->si_signo != SIGBUS){
+ iprint("return sig %d\n", stk_siginfo->si_signo);
+ dumpmcontext(stk_mcontext);
+ }
+ ret = thread_set_state(thread, x86_THREAD_STATE32,
+ (void*)&stk_mcontext->ss, x86_THREAD_STATE32_COUNT);
+ if(ret != KERN_SUCCESS)
+ panic("mach set regs1 failed: %d", ret);
+ ret = thread_set_state(thread, x86_FLOAT_STATE32,
+ (void*)&stk_mcontext->fs, x86_FLOAT_STATE32_COUNT);
+ if(ret != KERN_SUCCESS)
+ panic("mach set fpregs failed: %d", ret);
+ return KERN_SUCCESS;
}
- stk_mcontext = (mcontext_t)regs.eax;
- stk_siginfo = (siginfo_t*)regs.ebx;
- if(0 && stk_siginfo->si_signo != SIGBUS){
- iprint("return sig %d\n", stk_siginfo->si_signo);
- dumpmcontext(stk_mcontext);
+
+ /*
+ * Other things can cause GP faults too, but let's assume it was this.
+ * Linux sends si_addr == 0; so will we. The app isn't going to try
+ * to recover anyway, so it's not a big deal if we send other GP
+ * faults that way too.
+ */
+ if(code_vector[0] == EXC_I386_GPFLT){
+ signo = SIGBUS;
+ handler = sigbus;
+ addr = 0;
+ goto Trigger;
}
- ret = thread_set_state(thread, x86_THREAD_STATE32,
- (void*)&stk_mcontext->ss, x86_THREAD_STATE32_COUNT);
- if(ret != KERN_SUCCESS)
- panic("mach set regs1 failed: %d", ret);
- ret = thread_set_state(thread, x86_FLOAT_STATE32,
- (void*)&stk_mcontext->fs, x86_FLOAT_STATE32_COUNT);
- if(ret != KERN_SUCCESS)
- panic("mach set fpregs failed: %d", ret);
- return KERN_SUCCESS;
+
+ iprint("Unexpected bad instruction at eip=%p: code %p %p\n",
+ regs.eip, code_vector[0], code_vector[1]);
+ dumpregs1(®s);
+ return KERN_INVALID_RIGHT;
}
return KERN_INVALID_RIGHT;
}