/* Support for handling exceptions in Dylan (other than MM traps) */ /* Currently, we just handle stack overflows arithmetic exceptions */ /* ---*** TODO: Find out how to trap stack overflows on Linux */ extern int inside_dylan_ffi_barrier(); extern void dylan_stack_overflow_handler(PVOID base_address, int size, DWORD protection); extern void dylan_integer_overflow_handler(); extern void dylan_integer_divide_0_handler(); extern void dylan_float_divide_0_handler(); extern void dylan_float_overflow_handler(); extern void dylan_float_underflow_handler(); /* Linux exception handling: Setup a signal handler for SIGFPE (floating point exceptions). We rely on the fact that Linux passes a second argument containing the error context. */ /* ---*** NOTE: On x86 Linux, our use of the INT 4 and INTO instructions to raise an integer overflow exception isn't properly converted into a SIGFPE signal. Presumably, the hardware trap vector isn't setup properly and, as a result, we get a SIGSEGV signal instead. So, on x86 Linux only, we establish a SIGSEGV handler which checks the trap number in the sigcontext structure to see if we were invoked for an integer overflow. */ /* ---*** TODO: Find out how to trap stack overflows and add an appropriate handler */ #include #include #define EXCEPTION_PREAMBLE() \ struct sigaction oldFPEHandler; \ struct sigaction oldSEGVHandler; \ void doFPEHandler (int signum, siginfo_t *info, void * sc) { \ DylanFPEHandler(signum, info, sc); \ } \ void doSEGVHandler (int signum, siginfo_t *info, void * sc) { \ DylanSEGVHandler(signum, info, sc); \ } \ oldFPEHandler.sa_sigaction = doFPEHandler; \ oldSEGVHandler.sa_sigaction = doSEGVHandler; \ EstablishDylanExceptionHandlers(&oldFPEHandler, &oldSEGVHandler); \ { #define EXCEPTION_POSTAMBLE() \ } \ RemoveDylanExceptionHandlers(&oldFPEHandler, &oldSEGVHandler); typedef void (* SIG_SIGCONTEXT)(int, struct sigcontext); static void DylanFPEHandler (int sig, siginfo_t *info, void *sc); static void DylanSEGVHandler (int sig, siginfo_t *info, void *sc); static void EstablishDylanExceptionHandlers (struct sigaction * oldFPEHandler, struct sigaction * oldSEGVHandler) { struct sigaction newFPEHandler; struct sigaction newSEGVHandler; sigset_t set, oldset; newFPEHandler.sa_handler = oldFPEHandler->sa_handler; sigemptyset(&newFPEHandler.sa_mask); newFPEHandler.sa_flags = 0; sigaction(SIGFPE, &newFPEHandler, oldFPEHandler); #if 0 newSEGVHandler.sa_handler = oldSEGVHandler->sa_handler; sigemptyset(&newSEGVHandler.sa_mask); newSEGVHandler.sa_flags = 0; sigaction(SIGSEGV, &newSEGVHandler, oldSEGVHandler); #endif sigemptyset(&set); sigaddset(&set, SIGPIPE); sigprocmask(SIG_BLOCK, &set, &oldset); } static void RemoveDylanExceptionHandlers (struct sigaction * oldFPEHandler, struct sigaction * oldSEGVHandler) { sigaction(SIGFPE, oldFPEHandler, NULL); #if 0 sigaction(SIGSEGV, oldSEGVHandler, NULL); #endif } /* ---*** NOTE: There doesn't appear to be an include file that defines these constants! */ #define TRAP_INTEGER_DIVZERO 0 #define TRAP_INTEGER_OVERFLOW 4 #define TRAP_FLOAT_EXCEPTION 16 #define FS_INVALID_OP 1 #define FS_DENORMAL_OPERAND 2 #define FS_DIVZERO 4 #define FS_OVERFLOW 8 #define FS_UNDERFLOW 16 #define FS_INEXACT 32 #define FS_FSTACK_OVERFLOW 64 #define FS_ALL_EXCEPTIONS \ (FS_INVALID_OP | FS_DENORMAL_OPERAND | FS_DIVZERO | FS_OVERFLOW | FS_UNDERFLOW \ | FS_INEXACT | FS_FSTACK_OVERFLOW) #include __inline void RestoreFPState () { fpresetsticky(fpgetsticky()); fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL); return; } static void DylanFPEHandler (int sig, siginfo_t *info, void *sc) { if (inside_dylan_ffi_barrier() == 0) { } else { switch (info->si_code) { case FPE_INTDIV: RestoreFPState(); dylan_integer_divide_0_handler(); break; /* Should never get here ... */ case FPE_INTOVF: RestoreFPState(); dylan_integer_overflow_handler(); break; /* Should never get here ... */ case FPE_FLTDIV: RestoreFPState(); dylan_float_divide_0_handler(); /* Should never return ... */ break; case FPE_FLTOVF: RestoreFPState(); dylan_float_overflow_handler(); /* Should never return ... */ break; case FPE_FLTUND: RestoreFPState(); dylan_float_underflow_handler(); /* Should never return ... */ break; default: break; } } /* // Here iff we should invoke the previous handler ... if (oldHandler == SIG_DFL) { signal(signum, SIG_DFL); raise(signum); } else // ---*** NOTE: What if the old handler isn't expecting this calling sequence? (*(SIG_SIGCONTEXT)oldHandler)(signum, sc); */ return; } static void DylanSEGVHandler (int sig, siginfo_t *info, void *sc) { if (inside_dylan_ffi_barrier() == 0) { } // else if (sc.trapno == TRAP_INTEGER_OVERFLOW) { // RestoreFPState(sc.fpstate); // dylan_integer_overflow_handler(); /* Should never return ... */ //} // Here iff we should invoke the previous handler ... //if (oldHandler == SIG_DFL) { // signal(signum, SIG_DFL); // raise(signum); //} //else // ---*** NOTE: What if the old handler isn't expecting this calling sequence? // (*(SIG_SIGCONTEXT)oldHandler)(signum, sc); return; }