diff options
Diffstat (limited to 'rts/win32')
| -rw-r--r-- | rts/win32/OSMem.c | 2 | ||||
| -rw-r--r-- | rts/win32/OSThreads.c | 2 | ||||
| -rw-r--r-- | rts/win32/Ticker.c | 1 | ||||
| -rw-r--r-- | rts/win32/seh_excn.c | 45 | ||||
| -rw-r--r-- | rts/win32/seh_excn.h | 92 | ||||
| -rw-r--r-- | rts/win32/veh_excn.c | 100 | ||||
| -rw-r--r-- | rts/win32/veh_excn.h | 73 |
7 files changed, 173 insertions, 142 deletions
diff --git a/rts/win32/OSMem.c b/rts/win32/OSMem.c index d9700727a5..afa5113638 100644 --- a/rts/win32/OSMem.c +++ b/rts/win32/OSMem.c @@ -6,8 +6,6 @@ * * ---------------------------------------------------------------------------*/ -#define _WIN32_WINNT 0x0501 - #include "Rts.h" #include "sm/OSMem.h" #include "RtsUtils.h" diff --git a/rts/win32/OSThreads.c b/rts/win32/OSThreads.c index c3d3af64d2..0c256127e5 100644 --- a/rts/win32/OSThreads.c +++ b/rts/win32/OSThreads.c @@ -7,8 +7,6 @@ * * --------------------------------------------------------------------------*/ -#define _WIN32_WINNT 0x0501 - #include "Rts.h" #include <windows.h> #if defined(THREADED_RTS) diff --git a/rts/win32/Ticker.c b/rts/win32/Ticker.c index 89902e568d..dd04d84118 100644 --- a/rts/win32/Ticker.c +++ b/rts/win32/Ticker.c @@ -2,7 +2,6 @@ * RTS periodic timers. * */ -#define _WIN32_WINNT 0x0501 #include "Rts.h" #include "Ticker.h" diff --git a/rts/win32/seh_excn.c b/rts/win32/seh_excn.c deleted file mode 100644 index da5f64d812..0000000000 --- a/rts/win32/seh_excn.c +++ /dev/null @@ -1,45 +0,0 @@ -#include "ghcconfig.h" -#include "seh_excn.h" - -/* - * Exception / signal handlers. - */ -#if defined(mingw32_HOST_OS) -#if defined(i386_HOST_ARCH) -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 -#endif - diff --git a/rts/win32/seh_excn.h b/rts/win32/seh_excn.h deleted file mode 100644 index 8829e840b7..0000000000 --- a/rts/win32/seh_excn.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef WIN32_SEH_EXCN_H -#define WIN32_SEH_EXCN_H - -#include <stdio.h> -#include <stdlib.h> - -#if defined(__MINGW32__) -/* Stuff needed to install and use SEH exception handlers */ -#include <excpt.h> -#include <setjmp.h> -#include <windows.h> -#elif defined(_MSC_VER) -#include <windows.h> -#else -#include <signal.h> -#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 stg_exit(1). - */ -#define ON_DIV_ZERO fprintf(stdout,"divide by zero\n"); fflush(stdout);stg_exit(1) -#define ON_STACK_OVERFLOW fprintf(stdout,"C stack overflow in generated code\n"); fflush(stdout); stg_exit(1) -#define ON_SIGSEGV fprintf(stdout,"Segmentation fault/access violation in generated code\n"); fflush(stdout); stg_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 -#error Cannot determine what sort of Windows system this is -#endif - -#endif /* WIN32_SEH_EXCN_H */ - diff --git a/rts/win32/veh_excn.c b/rts/win32/veh_excn.c new file mode 100644 index 0000000000..a24354e9d6 --- /dev/null +++ b/rts/win32/veh_excn.c @@ -0,0 +1,100 @@ +/* ----------------------------------------------------------------------------- +* +* (c) The GHC Team 1998-2000 +* +* Error Handling implementations for windows +* +* ---------------------------------------------------------------------------*/ + +#include "Rts.h" +#include "ghcconfig.h" +#include "veh_excn.h" +#include <assert.h> + +///////////////////////////////// +// Exception / signal handlers. +///////////////////////////////// + +// Define some values for the ordering of VEH Handlers: +// - CALL_FIRST means call this exception handler first +// - CALL_LAST means call this exception handler last +#define CALL_FIRST 1 +#define CALL_LAST 0 + +// this should be in <excpt.h>, but it's been removed from MinGW distributions +#ifndef EH_UNWINDING +#define EH_UNWINDING 0x02 +#endif /* EH_UNWINDING */ + +// Registered exception handler +PVOID __hs_handle = NULL; + +long WINAPI __hs_exception_handler(struct _EXCEPTION_POINTERS *exception_data) +{ + long action = EXCEPTION_CONTINUE_SEARCH; + + // When the system unwinds the VEH stack after having handled an excn, + // return immediately. + if ((exception_data->ExceptionRecord->ExceptionFlags & EH_UNWINDING) == 0) + { + + // Error handling cases covered by this implementation. + switch (exception_data->ExceptionRecord->ExceptionCode) { + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_INT_DIVIDE_BY_ZERO: + fprintf(stdout, "divide by zero\n"); + action = EXCEPTION_CONTINUE_EXECUTION; + break; + case EXCEPTION_STACK_OVERFLOW: + fprintf(stdout, "C stack overflow in generated code\n"); + action = EXCEPTION_CONTINUE_EXECUTION; + break; + case EXCEPTION_ACCESS_VIOLATION: + fprintf(stdout, "Segmentation fault/access violation in generated code\n"); + action = EXCEPTION_CONTINUE_EXECUTION; + break; + default:; + } + + // If an error has occurred and we've decided to continue execution + // then we've done so to prevent something else from handling the error. + // But the correct action is still to exit as fast as possible. + if (EXCEPTION_CONTINUE_EXECUTION == action) + { + fflush(stdout); + stg_exit(1); + } + } + + return action; +} + +void __register_hs_exception_handler( void ) +{ + // Allow the VEH handler to be registered only once. + if (NULL == __hs_handle) + { + __hs_handle = AddVectoredExceptionHandler(CALL_FIRST, __hs_exception_handler); + // should the handler not be registered this will return a null. + assert(__hs_handle); + } + else + { + errorBelch("There is no need to call __register_hs_exception_handler() twice, VEH handlers are global per process."); + } +} + +void __unregister_hs_exception_handler( void ) +{ + if (__hs_handle != NULL) + { + // Should the return value be checked? we're terminating anyway. + RemoveVectoredExceptionHandler(__hs_handle); + __hs_handle = NULL; + } + else + { + errorBelch("__unregister_hs_exception_handler() called without having called __register_hs_exception_handler() first."); + } +} + diff --git a/rts/win32/veh_excn.h b/rts/win32/veh_excn.h new file mode 100644 index 0000000000..4223a2ae2d --- /dev/null +++ b/rts/win32/veh_excn.h @@ -0,0 +1,73 @@ +/* ----------------------------------------------------------------------------- +* +* (c) The GHC Team 1998-2000 +* +* Header for windows Error Handling implementations +* +* ---------------------------------------------------------------------------*/ + +#ifndef WIN32_VEH_EXCN_H +#define WIN32_VEH_EXCN_H + +#include <stdio.h> +#include <stdlib.h> +#include <Rts.h> + +// Stuff needed to install and use VEH exception handlers +#include <excpt.h> +#include <windows.h> + +// Exception handling. +// +// On Windows, the default action for things like division by zero and +// segfaults is to pop up a Dr. Watson error reporting dialog if the exception +// is unhandled by the user code. +// +// This is a pain when we are SSHed into a Windows machine, or when we +// want to debug a problem with gdb (gdb will get a first and second chance to +// handle the exception, but if it doesn't the pop-up will show). +// +// +// Previously this code was handled using SEH (Structured Exception Handlers) +// however each compiler and platform have different ways of dealing with SEH. +// +// MSVC compilers have the keywords __try, __catch and __except to have the +// compiler generate the appropriate SEH handler code for you. +// +// MinGW compilers have no such keywords and require you to manually set the +// SEH Handlers, however because SEH is implemented differently in x86 and x64 +// the methods to use them in GCC differs. +// +// x86: SEH is based on the stack, the SEH handlers are available at FS[0]. +// On startup one would only need to add a new handler there. This has +// a number of issues such as hard to share handlers and it can be exploited. +// +// x64: In order to fix the issues with the way SEH worked in x86, on x64 SEH handlers +// are statically compiled and added to the .pdata section by the compiler. +// Instead of being thread global they can now be Image global since you have to +// specify the RVA of the region of code that the handlers govern. +// +// You can on x64 Dynamically allocate SEH handlers, but it seems that (based on +// experimentation and it's very under-documented) that the dynamic calls cannot override +// static SEH handlers in the .pdata section. +// +// Because of this and because GHC no longer needs to support < windows XP, the better +// alternative for handling errors would be using the in XP introduced VEH. +// +// The bonus is because VEH (Vectored Exception Handler) are a runtime construct the API +// is the same for both x86 and x64 (note that the Context object does contain CPU specific +// structures) and the calls are the same cross compilers. Which means this file can be +// simplified quite a bit. +// Using VEH also means we don't have to worry about the dynamic code generated by GHCi. + +// Prototype of the VEH callback function. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms681419(v=vs.85).aspx +// +long WINAPI __hs_exception_handler( struct _EXCEPTION_POINTERS *exception_data ); + +// prototypes to the functions doing the registration and unregistration of the VEH handlers +void __register_hs_exception_handler( void ); +void __unregister_hs_exception_handler( void ); + +#endif /* WIN32_VEH_EXCN_H */ + |
