From 5a63edf27896c8aee411bb17d322ce6f247eddce Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 22 Oct 2009 05:22:59 -0500 Subject: [PATCH] vm: clean up signal handling and add EXC_BAD_INSTRUCTION Mach exception handler for OS X, since signal handlers cannot change the stack pointer --- vm/mach_signal.cpp | 12 ++++++-- vm/os-freebsd-x86.32.hpp | 10 ++----- vm/os-freebsd-x86.64.hpp | 10 ++----- vm/os-genunix.hpp | 5 ++++ vm/os-linux-arm.hpp | 12 ++------ vm/os-linux-ppc.hpp | 11 ++----- vm/os-linux-x86.32.hpp | 11 ++----- vm/os-linux-x86.64.hpp | 10 ++----- vm/os-macosx-ppc.hpp | 2 +- vm/os-macosx-x86.32.hpp | 2 +- vm/os-macosx-x86.64.hpp | 2 +- vm/os-macosx.hpp | 8 ++---- vm/os-netbsd-x86.32.hpp | 6 ++-- vm/os-netbsd-x86.64.hpp | 7 ++--- vm/os-openbsd-x86.32.hpp | 14 +++------ vm/os-openbsd-x86.64.hpp | 14 +++------ vm/os-solaris-x86.32.hpp | 10 ++----- vm/os-solaris-x86.64.hpp | 10 ++----- vm/os-unix.cpp | 62 +++++++++++++++------------------------- vm/vm.hpp | 11 ++----- 20 files changed, 79 insertions(+), 150 deletions(-) diff --git a/vm/mach_signal.cpp b/vm/mach_signal.cpp index 2d76b12c38..d05942ff7e 100644 --- a/vm/mach_signal.cpp +++ b/vm/mach_signal.cpp @@ -47,7 +47,7 @@ void factor_vm::call_fault_handler( else signal_callstack_top = NULL; - MACH_STACK_POINTER(thread_state) = fix_stack_pointer(MACH_STACK_POINTER(thread_state)); + MACH_STACK_POINTER(thread_state) = align_stack_pointer(MACH_STACK_POINTER(thread_state)); /* Now we point the program counter at the right handler function. */ if(exception == EXC_BAD_ACCESS) @@ -63,7 +63,13 @@ void factor_vm::call_fault_handler( } else { - signal_number = (exception == EXC_ARITHMETIC ? SIGFPE : SIGABRT); + switch(exception) + { + case EXC_ARITHMETIC: signal_number = SIGFPE; break; + case EXC_BAD_INSTRUCTION: signal_number = SIGILL; break; + default: signal_number = SIGABRT; break; + } + MACH_PROGRAM_COUNTER(thread_state) = (cell)factor::misc_signal_handler_impl; } } @@ -226,7 +232,7 @@ void mach_initialize () fatal_error("mach_port_insert_right() failed",0); /* The exceptions we want to catch. */ - mask = EXC_MASK_BAD_ACCESS | EXC_MASK_ARITHMETIC; + mask = EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC; /* Create the thread listening on the exception port. */ start_thread(mach_exception_thread,NULL); diff --git a/vm/os-freebsd-x86.32.hpp b/vm/os-freebsd-x86.32.hpp index e682fec13c..5ed5cf0e81 100644 --- a/vm/os-freebsd-x86.32.hpp +++ b/vm/os-freebsd-x86.32.hpp @@ -4,12 +4,6 @@ namespace factor { -inline static void *ucontext_stack_pointer(void *uap) -{ - ucontext_t *ucontext = (ucontext_t *)uap; - return (void *)ucontext->uc_mcontext.mc_esp; -} - inline static unsigned int uap_fpu_status(void *uap) { ucontext_t *ucontext = (ucontext_t *)uap; @@ -43,6 +37,8 @@ inline static void uap_clear_fpu_status(void *uap) } } -#define UAP_PROGRAM_COUNTER(ucontext) (((ucontext_t *)(ucontext))->uc_mcontext.mc_eip) + +#define UAP_STACK_POINTER(ucontext) (((ucontext_t *)ucontext)->uc_mcontext.mc_esp) +#define UAP_PROGRAM_COUNTER(ucontext) (((ucontext_t *)ucontext)->uc_mcontext.mc_eip) } diff --git a/vm/os-freebsd-x86.64.hpp b/vm/os-freebsd-x86.64.hpp index 8f8d218a10..02f7fb3ad2 100644 --- a/vm/os-freebsd-x86.64.hpp +++ b/vm/os-freebsd-x86.64.hpp @@ -4,12 +4,6 @@ namespace factor { -inline static void *ucontext_stack_pointer(void *uap) -{ - ucontext_t *ucontext = (ucontext_t *)uap; - return (void *)ucontext->uc_mcontext.mc_rsp; -} - inline static unsigned int uap_fpu_status(void *uap) { ucontext_t *ucontext = (ucontext_t *)uap; @@ -33,6 +27,8 @@ inline static void uap_clear_fpu_status(void *uap) } } -#define UAP_PROGRAM_COUNTER(ucontext) (((ucontext_t *)(ucontext))->uc_mcontext.mc_rip) + +#define UAP_STACK_POINTER(ucontext) (((ucontext_t *)ucontext)->uc_mcontext.mc_rsp) +#define UAP_PROGRAM_COUNTER(ucontext) (((ucontext_t *)ucontext)->uc_mcontext.mc_rip) } diff --git a/vm/os-genunix.hpp b/vm/os-genunix.hpp index 1972a728e6..626d399a27 100644 --- a/vm/os-genunix.hpp +++ b/vm/os-genunix.hpp @@ -10,4 +10,9 @@ void early_init(); const char *vm_executable_path(); const char *default_image_path(); +inline static cell align_stack_pointer(cell sp) +{ + return sp; +} + } diff --git a/vm/os-linux-arm.hpp b/vm/os-linux-arm.hpp index 70c3eb3ff6..3af92fda99 100644 --- a/vm/os-linux-arm.hpp +++ b/vm/os-linux-arm.hpp @@ -5,15 +5,9 @@ namespace factor { -inline static void *ucontext_stack_pointer(void *uap) -{ - ucontext_t *ucontext = (ucontext_t *)uap; - return (void *)ucontext->uc_mcontext.arm_sp; -} - -#define UAP_PROGRAM_COUNTER(ucontext) \ - (((ucontext_t *)(ucontext))->uc_mcontext.arm_pc) - void flush_icache(cell start, cell len); +#define UAP_STACK_POINTER(ucontext) (((ucontext_t *)ucontext)->uc_mcontext.arm_sp) +#define UAP_PROGRAM_COUNTER(ucontext) (((ucontext_t *)ucontext)->uc_mcontext.arm_pc) + } diff --git a/vm/os-linux-ppc.hpp b/vm/os-linux-ppc.hpp index 62671e5ded..51e017bdad 100644 --- a/vm/os-linux-ppc.hpp +++ b/vm/os-linux-ppc.hpp @@ -4,14 +4,7 @@ namespace factor { #define FRAME_RETURN_ADDRESS(frame,vm) *((void **)(vm->frame_successor(frame) + 1) + 1) - -inline static void *ucontext_stack_pointer(void *uap) -{ - ucontext_t *ucontext = (ucontext_t *)uap; - return (void *)ucontext->uc_mcontext.uc_regs->gregs[PT_R1]; -} - -#define UAP_PROGRAM_COUNTER(ucontext) \ - (((ucontext_t *)(ucontext))->uc_mcontext.uc_regs->gregs[PT_NIP]) +#define UAP_STACK_POINTER(ucontext) ((ucontext_t *)ucontext)->uc_mcontext.uc_regs->gregs[PT_R1] +#define UAP_PROGRAM_COUNTER(ucontext) (((ucontext_t *)ucontext)->uc_mcontext.uc_regs->gregs[PT_NIP]) } diff --git a/vm/os-linux-x86.32.hpp b/vm/os-linux-x86.32.hpp index bd2315ccef..53a93d17de 100644 --- a/vm/os-linux-x86.32.hpp +++ b/vm/os-linux-x86.32.hpp @@ -29,12 +29,6 @@ struct _fpstate { #define X86_FXSR_MAGIC 0x0000 -inline static void *ucontext_stack_pointer(void *uap) -{ - ucontext_t *ucontext = (ucontext_t *)uap; - return (void *)ucontext->uc_mcontext.gregs[7]; -} - inline static unsigned int uap_fpu_status(void *uap) { ucontext_t *ucontext = (ucontext_t *)uap; @@ -54,7 +48,8 @@ inline static void uap_clear_fpu_status(void *uap) fpregs->mxcsr &= 0xffffffc0; } -#define UAP_PROGRAM_COUNTER(ucontext) \ - (((ucontext_t *)(ucontext))->uc_mcontext.gregs[14]) + +#define UAP_STACK_POINTER(ucontext) (((ucontext_t *)ucontext)->uc_mcontext.gregs[7]) +#define UAP_PROGRAM_COUNTER(ucontext) (((ucontext_t *)ucontext)->uc_mcontext.gregs[14]) } diff --git a/vm/os-linux-x86.64.hpp b/vm/os-linux-x86.64.hpp index 42adb3c6b8..14ba9fb002 100644 --- a/vm/os-linux-x86.64.hpp +++ b/vm/os-linux-x86.64.hpp @@ -3,12 +3,6 @@ namespace factor { -inline static void *ucontext_stack_pointer(void *uap) -{ - ucontext_t *ucontext = (ucontext_t *)uap; - return (void *)ucontext->uc_mcontext.gregs[15]; -} - inline static unsigned int uap_fpu_status(void *uap) { ucontext_t *ucontext = (ucontext_t *)uap; @@ -23,7 +17,7 @@ inline static void uap_clear_fpu_status(void *uap) ucontext->uc_mcontext.fpregs->mxcsr &= 0xffffffc0; } -#define UAP_PROGRAM_COUNTER(ucontext) \ - (((ucontext_t *)(ucontext))->uc_mcontext.gregs[16]) +#define UAP_STACK_POINTER(ucontext) (((ucontext_t *)ucontext)->uc_mcontext.gregs[15]) +#define UAP_PROGRAM_COUNTER(ucontext) (((ucontext_t *)ucontext)->uc_mcontext.gregs[16]) } diff --git a/vm/os-macosx-ppc.hpp b/vm/os-macosx-ppc.hpp index 2bea926890..70fa18142a 100644 --- a/vm/os-macosx-ppc.hpp +++ b/vm/os-macosx-ppc.hpp @@ -62,7 +62,7 @@ inline static unsigned int uap_fpu_status(void *uap) return mach_fpu_status(UAP_FS(uap)); } -inline static cell fix_stack_pointer(cell sp) +inline static cell align_stack_pointer(cell sp) { return sp; } diff --git a/vm/os-macosx-x86.32.hpp b/vm/os-macosx-x86.32.hpp index 89906cd9a4..4bdc68ff72 100644 --- a/vm/os-macosx-x86.32.hpp +++ b/vm/os-macosx-x86.32.hpp @@ -64,7 +64,7 @@ inline static unsigned int uap_fpu_status(void *uap) return mach_fpu_status(UAP_FS(uap)); } -inline static cell fix_stack_pointer(cell sp) +inline static cell align_stack_pointer(cell sp) { return ((sp + 4) & ~15) - 4; } diff --git a/vm/os-macosx-x86.64.hpp b/vm/os-macosx-x86.64.hpp index fd6db4d68c..b923674cd1 100644 --- a/vm/os-macosx-x86.64.hpp +++ b/vm/os-macosx-x86.64.hpp @@ -62,7 +62,7 @@ inline static unsigned int uap_fpu_status(void *uap) return mach_fpu_status(UAP_FS(uap)); } -inline static cell fix_stack_pointer(cell sp) +inline static cell align_stack_pointer(cell sp) { return ((sp + 8) & ~15) - 8; } diff --git a/vm/os-macosx.hpp b/vm/os-macosx.hpp index cdc0ff7b42..0d230f48e3 100644 --- a/vm/os-macosx.hpp +++ b/vm/os-macosx.hpp @@ -11,12 +11,8 @@ void early_init(); const char *vm_executable_path(); const char *default_image_path(); -inline static void *ucontext_stack_pointer(void *uap) -{ - ucontext_t *ucontext = (ucontext_t *)uap; - return ucontext->uc_stack.ss_sp; -} - void c_to_factor_toplevel(cell quot); +#define UAP_STACK_POINTER(ucontext) (((ucontext_t *)ucontext)->uc_stack.ss_sp) + } diff --git a/vm/os-netbsd-x86.32.hpp b/vm/os-netbsd-x86.32.hpp index f2f47ecf6c..21b3557239 100644 --- a/vm/os-netbsd-x86.32.hpp +++ b/vm/os-netbsd-x86.32.hpp @@ -3,9 +3,9 @@ namespace factor { -#define ucontext_stack_pointer(uap) ((void *)_UC_MACHINE_SP((ucontext_t *)uap)) - static inline unsigned int uap_fpu_status(void *uap) { return 0; } -static inline void uap_clear_fpu_status(void *uap) { } +static inline void uap_clear_fpu_status(void *uap) {} + +#define UAP_STACK_POINTER(ucontext) (_UC_MACHINE_SP((ucontext_t *)ucontext)) } diff --git a/vm/os-netbsd-x86.64.hpp b/vm/os-netbsd-x86.64.hpp index a9d52a6c2b..3e94998993 100644 --- a/vm/os-netbsd-x86.64.hpp +++ b/vm/os-netbsd-x86.64.hpp @@ -3,10 +3,9 @@ namespace factor { -#define ucontext_stack_pointer(uap) \ - ((void *)(((ucontext_t *)(uap))->uc_mcontext.__gregs[_REG_URSP])) - static inline unsigned int uap_fpu_status(void *uap) { return 0; } -static inline void uap_clear_fpu_status(void *uap) { } +static inline void uap_clear_fpu_status(void *uap) {} + +#define UAP_STACK_POINTER(ucontext) (((ucontext_t *)ucontext)->uc_mcontext.__gregs[_REG_URSP]) } diff --git a/vm/os-openbsd-x86.32.hpp b/vm/os-openbsd-x86.32.hpp index 0abd019219..34a641c235 100644 --- a/vm/os-openbsd-x86.32.hpp +++ b/vm/os-openbsd-x86.32.hpp @@ -3,16 +3,10 @@ namespace factor { -inline static void *openbsd_stack_pointer(void *uap) -{ - struct sigcontext *sc = (struct sigcontext*) uap; - return (void *)sc->sc_esp; -} - -#define ucontext_stack_pointer openbsd_stack_pointer -#define UAP_PROGRAM_COUNTER(uap) (((struct sigcontext*)(uap))->sc_eip) - static inline unsigned int uap_fpu_status(void *uap) { return 0; } -static inline void uap_clear_fpu_status(void *uap) { } +static inline void uap_clear_fpu_status(void *uap) {} + +#define UAP_STACK_POINTER(ucontext) (((struct sigcontext *)ucontext)->sc_esp) +#define UAP_PROGRAM_COUNTER(ucontext) (((struct sigcontext *)ucontext)->sc_eip) } diff --git a/vm/os-openbsd-x86.64.hpp b/vm/os-openbsd-x86.64.hpp index 9dce48ee91..032e77b154 100644 --- a/vm/os-openbsd-x86.64.hpp +++ b/vm/os-openbsd-x86.64.hpp @@ -3,16 +3,10 @@ namespace factor { -inline static void *openbsd_stack_pointer(void *uap) -{ - struct sigcontext *sc = (struct sigcontext*) uap; - return (void *)sc->sc_rsp; -} - -#define ucontext_stack_pointer openbsd_stack_pointer -#define UAP_PROGRAM_COUNTER(uap) (((struct sigcontext*)(uap))->sc_rip) - static inline unsigned int uap_fpu_status(void *uap) { return 0; } -static inline void uap_clear_fpu_status(void *uap) { } +static inline void uap_clear_fpu_status(void *uap) {} + +#define UAP_STACK_POINTER(ucontext) (((struct sigcontext *)ucontext)->sc_rsp) +#define UAP_PROGRAM_COUNTER(ucontext) (((struct sigcontext *)ucontext)->sc_rip) } diff --git a/vm/os-solaris-x86.32.hpp b/vm/os-solaris-x86.32.hpp index b89b8d541b..2ec8bc138f 100644 --- a/vm/os-solaris-x86.32.hpp +++ b/vm/os-solaris-x86.32.hpp @@ -3,13 +3,7 @@ namespace factor { -inline static void *ucontext_stack_pointer(void *uap) -{ - ucontext_t *ucontext = (ucontext_t *)uap; - return (void *)ucontext->uc_mcontext.gregs[ESP]; -} - -#define UAP_PROGRAM_COUNTER(ucontext) \ - (((ucontext_t *)(ucontext))->uc_mcontext.gregs[EIP]) +#define UAP_STACK_POINTER(ucontext) (((ucontext_t *)ucontext)->uc_mcontext.gregs[ESP]) +#define UAP_PROGRAM_COUNTER(ucontext) (((ucontext_t *)ucontext)->uc_mcontext.gregs[EIP]) } diff --git a/vm/os-solaris-x86.64.hpp b/vm/os-solaris-x86.64.hpp index 0d3a74e11d..72a7b5c2fd 100644 --- a/vm/os-solaris-x86.64.hpp +++ b/vm/os-solaris-x86.64.hpp @@ -3,13 +3,7 @@ namespace factor { -inline static void *ucontext_stack_pointer(void *uap) -{ - ucontext_t *ucontext = (ucontext_t *)uap; - return (void *)ucontext->uc_mcontext.gregs[RSP]; -} - -#define UAP_PROGRAM_COUNTER(ucontext) \ - (((ucontext_t *)(ucontext))->uc_mcontext.gregs[RIP]) +#define UAP_STACK_POINTER(ucontext) (((ucontext_t *)ucontext)->uc_mcontext.gregs[RSP]) +#define UAP_PROGRAM_COUNTER(ucontext) (((ucontext_t *)ucontext)->uc_mcontext.gregs[RIP]) } diff --git a/vm/os-unix.cpp b/vm/os-unix.cpp index 2f9d5a3c89..0f2570b183 100644 --- a/vm/os-unix.cpp +++ b/vm/os-unix.cpp @@ -115,63 +115,47 @@ segment::~segment() if(retval) fatal_error("Segment deallocation failed",0); } - -stack_frame *factor_vm::uap_stack_pointer(void *uap) + +void factor_vm::dispatch_signal(void *uap, void (handler)()) { - /* There is a race condition here, but in practice a signal - delivered during stack frame setup/teardown or while transitioning - from Factor to C is a sign of things seriously gone wrong, not just - a divide by zero or stack underflow in the listener */ if(in_code_heap_p(UAP_PROGRAM_COUNTER(uap))) { - stack_frame *ptr = (stack_frame *)ucontext_stack_pointer(uap); - if(!ptr) - critical_error("Invalid uap",(cell)uap); - return ptr; + stack_frame *ptr = (stack_frame *)UAP_STACK_POINTER(uap); + assert(ptr); + signal_callstack_top = ptr; } else - return NULL; -} + signal_callstack_top = NULL; -void factor_vm::memory_signal_handler(int signal, siginfo_t *siginfo, void *uap) -{ - signal_fault_addr = (cell)siginfo->si_addr; - signal_callstack_top = uap_stack_pointer(uap); - UAP_PROGRAM_COUNTER(uap) = (cell)factor::memory_signal_handler_impl; + UAP_STACK_POINTER(uap) = (void *)align_stack_pointer((cell)UAP_STACK_POINTER(uap)); + UAP_PROGRAM_COUNTER(uap) = (cell)handler; } void memory_signal_handler(int signal, siginfo_t *siginfo, void *uap) { - tls_vm()->memory_signal_handler(signal,siginfo,uap); -} - -void factor_vm::misc_signal_handler(int signal, siginfo_t *siginfo, void *uap) -{ - signal_number = signal; - signal_callstack_top = uap_stack_pointer(uap); - UAP_PROGRAM_COUNTER(uap) = (cell)factor::misc_signal_handler_impl; + factor_vm *vm = tls_vm(); + vm->signal_fault_addr = (cell)siginfo->si_addr; + vm->dispatch_signal(uap,factor::memory_signal_handler_impl); } void misc_signal_handler(int signal, siginfo_t *siginfo, void *uap) { - tls_vm()->misc_signal_handler(signal,siginfo,uap); -} - -void factor_vm::fpe_signal_handler(int signal, siginfo_t *siginfo, void *uap) -{ - signal_number = signal; - signal_callstack_top = uap_stack_pointer(uap); - signal_fpu_status = fpu_status(uap_fpu_status(uap)); - uap_clear_fpu_status(uap); - UAP_PROGRAM_COUNTER(uap) = - (siginfo->si_code == FPE_INTDIV || siginfo->si_code == FPE_INTOVF) - ? (cell)factor::misc_signal_handler_impl - : (cell)factor::fp_signal_handler_impl; + factor_vm *vm = tls_vm(); + vm->signal_number = signal; + vm->dispatch_signal(uap,factor::misc_signal_handler_impl); } void fpe_signal_handler(int signal, siginfo_t *siginfo, void *uap) { - tls_vm()->fpe_signal_handler(signal, siginfo, uap); + factor_vm *vm = tls_vm(); + vm->signal_number = signal; + vm->signal_fpu_status = fpu_status(uap_fpu_status(uap)); + uap_clear_fpu_status(uap); + + vm->dispatch_signal(uap, + (siginfo->si_code == FPE_INTDIV || siginfo->si_code == FPE_INTOVF) + ? factor::misc_signal_handler_impl + : factor::fp_signal_handler_impl); } static void sigaction_safe(int signum, const struct sigaction *act, struct sigaction *oldact) diff --git a/vm/vm.hpp b/vm/vm.hpp index 202996ce26..4b115ecd3f 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -689,17 +689,12 @@ struct factor_vm void windows_image_path(vm_char *full_path, vm_char *temp_path, unsigned int length); bool windows_stat(vm_char *path); - #if defined(WINNT) + #if defined(WINNT) void open_console(); LONG exception_handler(PEXCEPTION_POINTERS pe); - // next method here: - #endif + #endif #else // UNIX - void memory_signal_handler(int signal, siginfo_t *siginfo, void *uap); - void misc_signal_handler(int signal, siginfo_t *siginfo, void *uap); - void fpe_signal_handler(int signal, siginfo_t *siginfo, void *uap); - stack_frame *uap_stack_pointer(void *uap); - + void factor_vm::dispatch_signal(void *uap, void (handler)()); #endif #ifdef __APPLE__