From 0f15d797ceee52ae8fa507500d1119cc9638431a Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Fri, 3 Aug 2007 18:32:29 +0000 Subject: [PATCH] Catch exceptions on Windows, to stop it popping up dialog boxes Adaptated from code from Sigbjorn Finne --- rts/Main.c | 6 +++- rts/seh_excn.c | 42 ++++++++++++++++++++++++++ rts/seh_excn.h | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 rts/seh_excn.c create mode 100644 rts/seh_excn.h diff --git a/rts/Main.c b/rts/Main.c index 745d775..5f16fa3 100644 --- a/rts/Main.c +++ b/rts/Main.c @@ -16,6 +16,7 @@ #include "RtsUtils.h" #include "Prelude.h" #include "Task.h" +#include "seh_excn.h" #include #ifdef DEBUG @@ -48,6 +49,7 @@ int main(int argc, char *argv[]) SchedulerStatus status; /* all GranSim/GUM init is done in startupHaskell; sets IAmMainThread! */ + BEGIN_CATCH startupHaskell(argc,argv,__stginit_ZCMain); /* kick off the computation by creating the main thread with a pointer @@ -133,6 +135,8 @@ int main(int argc, char *argv[]) barf("main thread completed with invalid status"); } shutdownHaskellAndExit(exit_status); - return 0; /* never reached, keep gcc -Wall happy */ + END_CATCH + return 0; /* not reached unless a Windows exception happens, + also keeps gcc -Wall happy */ } # endif /* BATCH_MODE */ diff --git a/rts/seh_excn.c b/rts/seh_excn.c new file mode 100644 index 0000000..5da7579 --- /dev/null +++ b/rts/seh_excn.c @@ -0,0 +1,42 @@ +#include "seh_excn.h" + +/* + * Exception / signal handlers. + */ +#if defined(__MINGW32__) +jmp_buf seh_unwind_to; +unsigned long seh_excn_code; /* variable used to communicate what kind of exception we've caught;nice. */ + +EXCEPTION_DISPOSITION +catchDivZero(struct _EXCEPTION_RECORD* rec, + void* arg1 __attribute__((unused)), + struct _CONTEXT* ctxt __attribute__((unused)), + void* arg2 __attribute__((unused))) +{ + if ((rec->ExceptionFlags & EH_UNWINDING) != 0) { + // When the system unwinds the SEH stack after having handled an excn, + // return immediately. + return ExceptionContinueSearch; + } + switch (rec->ExceptionCode) { + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_INT_DIVIDE_BY_ZERO: + seh_excn_code = 0; + longjmp(seh_unwind_to, rec->ExceptionCode); + return ExceptionContinueExecution; + case EXCEPTION_STACK_OVERFLOW: + seh_excn_code = 1; + longjmp(seh_unwind_to, rec->ExceptionCode); + return ExceptionContinueExecution; + case EXCEPTION_ACCESS_VIOLATION: + seh_excn_code = 2; + longjmp(seh_unwind_to, rec->ExceptionCode); + return ExceptionContinueExecution; + longjmp(seh_unwind_to, rec->ExceptionCode); + return ExceptionContinueExecution; + default: ; + } + return ExceptionContinueSearch; +} +#endif + diff --git a/rts/seh_excn.h b/rts/seh_excn.h new file mode 100644 index 0000000..311675d --- /dev/null +++ b/rts/seh_excn.h @@ -0,0 +1,92 @@ +#ifndef __SEH_EXCN_H__ +#define __SEH_EXCN_H__ +#include +#include + +#if defined(__MINGW32__) +/* Stuff needed to install and use SEH exception handlers */ +#include +#include +#include +#elif defined(_MSC_VER) +#include +#else +#include +#endif + +/* Exception handling. + * + * On Win32, the default action for things like division by zero and + * segfaults is to pop up an annoying little dialog box. + * + * This is a pain when we are SSHed into a Windows machine, or when we + * want to debug a problem with gdb. + * + * seh_excn provides two macros, BEGIN_CATCH and END_CATCH, which + * will catch such exceptions in the code they bracket and die by + * printing a message and calling exit(1). + */ +#define ON_DIV_ZERO fprintf(stdout,"divide by zero\n"); fflush(stdout);exit(1) +#define ON_STACK_OVERFLOW fprintf(stdout,"C stack overflow in generated code\n"); fflush(stdout); exit(1) +#define ON_SIGSEGV fprintf(stdout,"Segmentation fault/access violation in generated code\n"); fflush(stdout); exit(1) + +#if defined(__MINGW32__) +extern jmp_buf seh_unwind_to; +extern unsigned long seh_excn_code; +/* + * install an exception handler 'exHandler' which longjmp()s (via 'jumpBuf') + * to the code 'onExnCaught' when successfully catching an exception. + * + * Macro based on Andrew Begel's SEH support code posted to the mingw-users + * mailing list. + */ +#define TRY_BEGIN(jumpBuf, exHandler, onExcnCaught) \ + do { \ + int signal; \ + if ((signal = setjmp(jumpBuf)) != 0) { \ + onExcnCaught; \ + } else { \ + __try1(exHandler); \ + } \ + } while (0); + +#define TRY_END() __except1 + +extern +EXCEPTION_DISPOSITION +catchDivZero(struct _EXCEPTION_RECORD*, + void*, + struct _CONTEXT*, + void*); + +#define ON_EXCN \ + if (seh_excn_code == 1) { \ + ON_STACK_OVERFLOW; \ + } else if ( seh_excn_code == 2 ) { \ + ON_SIGSEGV; \ + } else { \ + ON_DIV_ZERO; \ + } + +#define BEGIN_CATCH TRY_BEGIN(seh_unwind_to, catchDivZero, ON_EXCN) +#define END_CATCH TRY_END() +#elif defined(_MSC_VER) +#define BEGIN_CATCH __try { +#define END_CATCH } __except ( ( ((GetExceptionCode() == EXCEPTION_FLT_DIVIDE_BY_ZERO) || (GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO) || (GetExceptionCode() == EXCEPTION_STACK_OVERFLOW) || (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) ) { \ + switch ( (GetExceptionCode()) ) { \ + case EXCEPTION_FLT_DIVIDE_BY_ZERO: \ + case EXCEPTION_INT_DIVIDE_BY_ZERO: + ON_DIV_ZERO; break; \ + case EXCEPTION_STACK_OVERFLOW: \ + ON_STACK_OVERFLOW; break; \ + case EXCEPTION_ACCESS_VIOLATION: \ + ON_SIGSEGV; break; \ + } \ + } +#else +#define BEGIN_CATCH /* nothing */ +#define END_CATCH /* nothing */ +#endif + +#endif /* __SEH_EXCN_H__ */ + -- 1.7.10.4