Merge MSVC fixes from cmake branch
[reactos.git] / reactos / lib / 3rdparty / mingw / crt_handler.c
1 /**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the w64 mingw-runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6
7 #include <windows.h>
8 #include <excpt.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <malloc.h>
12 #include <memory.h>
13 #include <signal.h>
14 #include <stdio.h>
15
16 #if defined (_WIN64) && defined (__ia64__)
17 #error FIXME: Unsupported __ImageBase implementation.
18 #else
19 #ifndef _MSC_VER
20 #define __ImageBase __MINGW_LSYMBOL(_image_base__)
21 #endif
22 /* This symbol is defined by the linker. */
23 extern IMAGE_DOS_HEADER __ImageBase;
24 #endif
25
26 #pragma pack(push,1)
27 typedef struct _UNWIND_INFO {
28 BYTE VersionAndFlags;
29 BYTE PrologSize;
30 BYTE CountOfUnwindCodes;
31 BYTE FrameRegisterAndOffset;
32 ULONG AddressOfExceptionHandler;
33 } UNWIND_INFO,*PUNWIND_INFO;
34 #pragma pack(pop)
35
36 PIMAGE_SECTION_HEADER _FindPESectionByName (const char *);
37 PIMAGE_SECTION_HEADER _FindPESectionExec (size_t);
38 PBYTE _GetPEImageBase (void);
39
40 int __mingw_init_ehandler (void);
41
42 #ifdef _WIN64
43 EXCEPTION_DISPOSITION __mingw_SEH_error_handler(struct _EXCEPTION_RECORD *, void *, struct _CONTEXT *, void *);
44
45 #define MAX_PDATA_ENTRIES 32
46 static RUNTIME_FUNCTION emu_pdata[MAX_PDATA_ENTRIES];
47 static UNWIND_INFO emu_xdata[MAX_PDATA_ENTRIES];
48
49 int
50 __mingw_init_ehandler (void)
51 {
52 static int was_here = 0;
53 size_t e = 0;
54 PIMAGE_SECTION_HEADER pSec;
55 PBYTE _ImageBase = _GetPEImageBase ();
56
57 if (was_here || !_ImageBase)
58 return was_here;
59 was_here = 1;
60 if (_FindPESectionByName (".pdata") != NULL)
61 return 1;
62
63 /* Allocate # of e tables and entries. */
64 memset (emu_pdata, 0, sizeof (RUNTIME_FUNCTION) * MAX_PDATA_ENTRIES);
65 memset (emu_xdata, 0, sizeof (UNWIND_INFO) * MAX_PDATA_ENTRIES);
66
67 e = 0;
68 /* Fill tables and entries. */
69 while (e < MAX_PDATA_ENTRIES && (pSec = _FindPESectionExec (e)) != NULL)
70 {
71 emu_xdata[e].VersionAndFlags = 9; /* UNW_FLAG_EHANDLER | UNW_VERSION */
72 emu_xdata[e].AddressOfExceptionHandler =
73 (DWORD)(size_t) ((LPBYTE)__mingw_SEH_error_handler - _ImageBase);
74 emu_pdata[e].BeginAddress = pSec->VirtualAddress;
75 emu_pdata[e].EndAddress = pSec->VirtualAddress + pSec->Misc.VirtualSize;
76 emu_pdata[e].UnwindData =
77 (DWORD)(size_t)((LPBYTE)&emu_xdata[e] - _ImageBase);
78 ++e;
79 }
80 #ifdef _DEBUG_CRT
81 if (!e || e > MAX_PDATA_ENTRIES)
82 abort ();
83 #endif
84 /* RtlAddFunctionTable. */
85 if (e != 0)
86 RtlAddFunctionTable (emu_pdata, e, (DWORD64)_ImageBase);
87 return 1;
88 }
89
90 extern void _fpreset (void);
91
92 EXCEPTION_DISPOSITION
93 __mingw_SEH_error_handler (struct _EXCEPTION_RECORD* ExceptionRecord,
94 void *EstablisherFrame __attribute__ ((unused)),
95 struct _CONTEXT* ContextRecord __attribute__ ((unused)),
96 void *DispatcherContext __attribute__ ((unused)))
97 {
98 EXCEPTION_DISPOSITION action = EXCEPTION_CONTINUE_SEARCH;
99 void (*old_handler) (int);
100 int reset_fpu = 0;
101
102 switch (ExceptionRecord->ExceptionCode)
103 {
104 case EXCEPTION_ACCESS_VIOLATION:
105 /* test if the user has set SIGSEGV */
106 old_handler = signal (SIGSEGV, SIG_DFL);
107 if (old_handler == SIG_IGN)
108 {
109 /* this is undefined if the signal was raised by anything other
110 than raise (). */
111 signal (SIGSEGV, SIG_IGN);
112 action = EXCEPTION_CONTINUE_EXECUTION;
113 }
114 else if (old_handler != SIG_DFL)
115 {
116 /* This means 'old' is a user defined function. Call it */
117 (*old_handler) (SIGSEGV);
118 action = EXCEPTION_CONTINUE_EXECUTION;
119 }
120 else
121 action = EXCEPTION_EXECUTE_HANDLER;
122 break;
123 case EXCEPTION_ILLEGAL_INSTRUCTION:
124 case EXCEPTION_PRIV_INSTRUCTION:
125 /* test if the user has set SIGILL */
126 old_handler = signal (SIGILL, SIG_DFL);
127 if (old_handler == SIG_IGN)
128 {
129 /* this is undefined if the signal was raised by anything other
130 than raise (). */
131 signal (SIGILL, SIG_IGN);
132 action = EXCEPTION_CONTINUE_EXECUTION;
133 }
134 else if (old_handler != SIG_DFL)
135 {
136 /* This means 'old' is a user defined function. Call it */
137 (*old_handler) (SIGILL);
138 action = EXCEPTION_CONTINUE_EXECUTION;
139 }
140 else
141 action = EXCEPTION_EXECUTE_HANDLER;
142 break;
143 case EXCEPTION_FLT_INVALID_OPERATION:
144 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
145 case EXCEPTION_FLT_DENORMAL_OPERAND:
146 case EXCEPTION_FLT_OVERFLOW:
147 case EXCEPTION_FLT_UNDERFLOW:
148 case EXCEPTION_FLT_INEXACT_RESULT:
149 reset_fpu = 1;
150 /* fall through. */
151
152 case EXCEPTION_INT_DIVIDE_BY_ZERO:
153 /* test if the user has set SIGFPE */
154 old_handler = signal (SIGFPE, SIG_DFL);
155 if (old_handler == SIG_IGN)
156 {
157 signal (SIGFPE, SIG_IGN);
158 if (reset_fpu)
159 _fpreset ();
160 action = EXCEPTION_CONTINUE_EXECUTION;
161 }
162 else if (old_handler != SIG_DFL)
163 {
164 /* This means 'old' is a user defined function. Call it */
165 (*old_handler) (SIGFPE);
166 action = EXCEPTION_CONTINUE_EXECUTION;
167 }
168 break;
169 case EXCEPTION_DATATYPE_MISALIGNMENT:
170 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
171 case EXCEPTION_FLT_STACK_CHECK:
172 case EXCEPTION_INT_OVERFLOW:
173 case EXCEPTION_INVALID_HANDLE:
174 /*case EXCEPTION_POSSIBLE_DEADLOCK: */
175 action = EXCEPTION_CONTINUE_EXECUTION;
176 break;
177 default:
178 break;
179 }
180 return action;
181 }
182
183 #endif