/** * This file has no copyright assigned and is placed in the Public Domain. * This file is part of the mingw-w64 runtime package. * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ #include #include #include #include #include #include #include #include #if defined (_WIN64) && defined (__ia64__) #error FIXME: Unsupported __ImageBase implementation. #else #ifndef _MSC_VER #define __ImageBase __MINGW_LSYMBOL(_image_base__) #endif /* This symbol is defined by the linker. */ extern IMAGE_DOS_HEADER __ImageBase; #endif #pragma pack(push,1) typedef struct _UNWIND_INFO { BYTE VersionAndFlags; BYTE PrologSize; BYTE CountOfUnwindCodes; BYTE FrameRegisterAndOffset; ULONG AddressOfExceptionHandler; } UNWIND_INFO,*PUNWIND_INFO; #pragma pack(pop) PIMAGE_SECTION_HEADER _FindPESectionByName (const char *); PIMAGE_SECTION_HEADER _FindPESectionExec (size_t); PBYTE _GetPEImageBase (void); int __mingw_init_ehandler (void); extern void _fpreset (void); #if defined(__x86_64__) && !defined(_MSC_VER) && !defined(__SEH__) EXCEPTION_DISPOSITION __mingw_SEH_error_handler(struct _EXCEPTION_RECORD *, void *, struct _CONTEXT *, void *); #define MAX_PDATA_ENTRIES 32 static RUNTIME_FUNCTION emu_pdata[MAX_PDATA_ENTRIES]; static UNWIND_INFO emu_xdata[MAX_PDATA_ENTRIES]; int __mingw_init_ehandler (void) { static int was_here = 0; size_t e = 0; PIMAGE_SECTION_HEADER pSec; PBYTE _ImageBase = _GetPEImageBase (); if (was_here || !_ImageBase) return was_here; was_here = 1; if (_FindPESectionByName (".pdata") != NULL) return 1; /* Allocate # of e tables and entries. */ memset (emu_pdata, 0, sizeof (RUNTIME_FUNCTION) * MAX_PDATA_ENTRIES); memset (emu_xdata, 0, sizeof (UNWIND_INFO) * MAX_PDATA_ENTRIES); e = 0; /* Fill tables and entries. */ while (e < MAX_PDATA_ENTRIES && (pSec = _FindPESectionExec (e)) != NULL) { emu_xdata[e].VersionAndFlags = 9; /* UNW_FLAG_EHANDLER | UNW_VERSION */ emu_xdata[e].AddressOfExceptionHandler = (DWORD)(size_t) ((LPBYTE)__mingw_SEH_error_handler - _ImageBase); emu_pdata[e].BeginAddress = pSec->VirtualAddress; emu_pdata[e].EndAddress = pSec->VirtualAddress + pSec->Misc.VirtualSize; emu_pdata[e].UnwindData = (DWORD)(size_t)((LPBYTE)&emu_xdata[e] - _ImageBase); ++e; } #ifdef _DEBUG_CRT if (!e || e > MAX_PDATA_ENTRIES) abort (); #endif /* RtlAddFunctionTable. */ if (e != 0) RtlAddFunctionTable (emu_pdata, e, (DWORD64)_ImageBase); return 1; } extern void _fpreset (void); EXCEPTION_DISPOSITION __mingw_SEH_error_handler (struct _EXCEPTION_RECORD* ExceptionRecord, void *EstablisherFrame __attribute__ ((unused)), struct _CONTEXT* ContextRecord __attribute__ ((unused)), void *DispatcherContext __attribute__ ((unused))) { EXCEPTION_DISPOSITION action = ExceptionContinueSearch; /* EXCEPTION_CONTINUE_SEARCH; */ void (*old_handler) (int); int reset_fpu = 0; switch (ExceptionRecord->ExceptionCode) { case EXCEPTION_ACCESS_VIOLATION: /* test if the user has set SIGSEGV */ old_handler = signal (SIGSEGV, SIG_DFL); if (old_handler == SIG_IGN) { /* this is undefined if the signal was raised by anything other than raise (). */ signal (SIGSEGV, SIG_IGN); action = 0; //EXCEPTION_CONTINUE_EXECUTION; } else if (old_handler != SIG_DFL) { /* This means 'old' is a user defined function. Call it */ (*old_handler) (SIGSEGV); action = 0; // EXCEPTION_CONTINUE_EXECUTION; } else action = 4; /* EXCEPTION_EXECUTE_HANDLER; */ break; case EXCEPTION_ILLEGAL_INSTRUCTION: case EXCEPTION_PRIV_INSTRUCTION: /* test if the user has set SIGILL */ old_handler = signal (SIGILL, SIG_DFL); if (old_handler == SIG_IGN) { /* this is undefined if the signal was raised by anything other than raise (). */ signal (SIGILL, SIG_IGN); action = 0; // EXCEPTION_CONTINUE_EXECUTION; } else if (old_handler != SIG_DFL) { /* This means 'old' is a user defined function. Call it */ (*old_handler) (SIGILL); action = 0; // EXCEPTION_CONTINUE_EXECUTION; } else action = 4; /* EXCEPTION_EXECUTE_HANDLER;*/ break; case EXCEPTION_FLT_INVALID_OPERATION: case EXCEPTION_FLT_DIVIDE_BY_ZERO: case EXCEPTION_FLT_DENORMAL_OPERAND: case EXCEPTION_FLT_OVERFLOW: case EXCEPTION_FLT_UNDERFLOW: case EXCEPTION_FLT_INEXACT_RESULT: reset_fpu = 1; /* fall through. */ case EXCEPTION_INT_DIVIDE_BY_ZERO: /* test if the user has set SIGFPE */ old_handler = signal (SIGFPE, SIG_DFL); if (old_handler == SIG_IGN) { signal (SIGFPE, SIG_IGN); if (reset_fpu) _fpreset (); action = 0; // EXCEPTION_CONTINUE_EXECUTION; } else if (old_handler != SIG_DFL) { /* This means 'old' is a user defined function. Call it */ (*old_handler) (SIGFPE); action = 0; // EXCEPTION_CONTINUE_EXECUTION; } break; case EXCEPTION_DATATYPE_MISALIGNMENT: case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: case EXCEPTION_FLT_STACK_CHECK: case EXCEPTION_INT_OVERFLOW: case EXCEPTION_INVALID_HANDLE: /*case EXCEPTION_POSSIBLE_DEADLOCK: */ action = 0; // EXCEPTION_CONTINUE_EXECUTION; break; default: break; } return action; } #endif LPTOP_LEVEL_EXCEPTION_FILTER __mingw_oldexcpt_handler = NULL; long CALLBACK _gnu_exception_handler (EXCEPTION_POINTERS *exception_data); #define GCC_MAGIC (('G' << 16) | ('C' << 8) | 'C' | (1U << 29)) long CALLBACK _gnu_exception_handler (EXCEPTION_POINTERS *exception_data) { void (*old_handler) (int); long action = EXCEPTION_CONTINUE_SEARCH; int reset_fpu = 0; #ifdef __SEH__ if ((exception_data->ExceptionRecord->ExceptionCode & 0x20ffffff) == GCC_MAGIC) { if ((exception_data->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) == 0) return EXCEPTION_CONTINUE_EXECUTION; } #endif switch (exception_data->ExceptionRecord->ExceptionCode) { case EXCEPTION_ACCESS_VIOLATION: /* test if the user has set SIGSEGV */ old_handler = signal (SIGSEGV, SIG_DFL); if (old_handler == SIG_IGN) { /* this is undefined if the signal was raised by anything other than raise (). */ signal (SIGSEGV, SIG_IGN); action = EXCEPTION_CONTINUE_EXECUTION; } else if (old_handler != SIG_DFL) { /* This means 'old' is a user defined function. Call it */ (*old_handler) (SIGSEGV); action = EXCEPTION_CONTINUE_EXECUTION; } break; case EXCEPTION_ILLEGAL_INSTRUCTION: case EXCEPTION_PRIV_INSTRUCTION: /* test if the user has set SIGILL */ old_handler = signal (SIGILL, SIG_DFL); if (old_handler == SIG_IGN) { /* this is undefined if the signal was raised by anything other than raise (). */ signal (SIGILL, SIG_IGN); action = EXCEPTION_CONTINUE_EXECUTION; } else if (old_handler != SIG_DFL) { /* This means 'old' is a user defined function. Call it */ (*old_handler) (SIGILL); action = EXCEPTION_CONTINUE_EXECUTION; } break; case EXCEPTION_FLT_INVALID_OPERATION: case EXCEPTION_FLT_DIVIDE_BY_ZERO: case EXCEPTION_FLT_DENORMAL_OPERAND: case EXCEPTION_FLT_OVERFLOW: case EXCEPTION_FLT_UNDERFLOW: case EXCEPTION_FLT_INEXACT_RESULT: reset_fpu = 1; /* fall through. */ case EXCEPTION_INT_DIVIDE_BY_ZERO: /* test if the user has set SIGFPE */ old_handler = signal (SIGFPE, SIG_DFL); if (old_handler == SIG_IGN) { signal (SIGFPE, SIG_IGN); if (reset_fpu) _fpreset (); action = EXCEPTION_CONTINUE_EXECUTION; } else if (old_handler != SIG_DFL) { /* This means 'old' is a user defined function. Call it */ (*old_handler) (SIGFPE); action = EXCEPTION_CONTINUE_EXECUTION; } break; #ifdef _WIN64 case EXCEPTION_DATATYPE_MISALIGNMENT: case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: case EXCEPTION_FLT_STACK_CHECK: case EXCEPTION_INT_OVERFLOW: case EXCEPTION_INVALID_HANDLE: /*case EXCEPTION_POSSIBLE_DEADLOCK: */ action = EXCEPTION_CONTINUE_EXECUTION; break; #endif default: break; } if (action == EXCEPTION_CONTINUE_SEARCH && __mingw_oldexcpt_handler) action = (*__mingw_oldexcpt_handler)(exception_data); return action; }