/* 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 <sys/signal.h>
#include <ieeefp.h>
#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 <fenv.h>
__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;
}
syntax highlighted by Code2HTML, v. 0.9.1