841721727815e41f7464915cd11611ac6fca63b1
[reactos.git] / reactos / lib / sdk / crt / startup / 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 <excpt.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <malloc.h>
11 #include <memory.h>
12 #include <signal.h>
13 #include <stdio.h>
14
15 #include <windef.h>
16 #include <winbase.h>
17
18 #if defined (_WIN64) && defined (__ia64__)
19 #error FIXME: Unsupported __ImageBase implementation.
20 #else
21 #ifndef _MSC_VER
22 #define __ImageBase __MINGW_LSYMBOL(_image_base__)
23 #endif
24 /* This symbol is defined by the linker. */
25 extern IMAGE_DOS_HEADER __ImageBase;
26 #endif
27
28 #pragma pack(push,1)
29 typedef struct _UNWIND_INFO {
30 BYTE VersionAndFlags;
31 BYTE PrologSize;
32 BYTE CountOfUnwindCodes;
33 BYTE FrameRegisterAndOffset;
34 ULONG AddressOfExceptionHandler;
35 } UNWIND_INFO,*PUNWIND_INFO;
36 #pragma pack(pop)
37
38 PIMAGE_SECTION_HEADER _FindPESectionByName (const char *);
39 PIMAGE_SECTION_HEADER _FindPESectionExec (size_t);
40 PBYTE _GetPEImageBase (void);
41
42 int __mingw_init_ehandler (void);
43 extern void _fpreset (void);
44
45 #if defined(_WIN64) && !defined(_MSC_VER)
46 EXCEPTION_DISPOSITION __mingw_SEH_error_handler(struct _EXCEPTION_RECORD *, void *, struct _CONTEXT *, void *);
47
48 #define MAX_PDATA_ENTRIES 32
49 static RUNTIME_FUNCTION emu_pdata[MAX_PDATA_ENTRIES];
50 static UNWIND_INFO emu_xdata[MAX_PDATA_ENTRIES];
51
52 int
53 __mingw_init_ehandler (void)
54 {
55 static int was_here = 0;
56 size_t e = 0;
57 PIMAGE_SECTION_HEADER pSec;
58 PBYTE _ImageBase = _GetPEImageBase ();
59
60 if (was_here || !_ImageBase)
61 return was_here;
62 was_here = 1;
63 if (_FindPESectionByName (".pdata") != NULL)
64 return 1;
65
66 /* Allocate # of e tables and entries. */
67 memset (emu_pdata, 0, sizeof (RUNTIME_FUNCTION) * MAX_PDATA_ENTRIES);
68 memset (emu_xdata, 0, sizeof (UNWIND_INFO) * MAX_PDATA_ENTRIES);
69
70 e = 0;
71 /* Fill tables and entries. */
72 while (e < MAX_PDATA_ENTRIES && (pSec = _FindPESectionExec (e)) != NULL)
73 {
74 emu_xdata[e].VersionAndFlags = 9; /* UNW_FLAG_EHANDLER | UNW_VERSION */
75 emu_xdata[e].AddressOfExceptionHandler =
76 (DWORD)(size_t) ((LPBYTE)__mingw_SEH_error_handler - _ImageBase);
77 emu_pdata[e].BeginAddress = pSec->VirtualAddress;
78 emu_pdata[e].EndAddress = pSec->VirtualAddress + pSec->Misc.VirtualSize;
79 emu_pdata[e].UnwindData =
80 (DWORD)(size_t)((LPBYTE)&emu_xdata[e] - _ImageBase);
81 ++e;
82 }
83 #ifdef _DEBUG_CRT
84 if (!e || e > MAX_PDATA_ENTRIES)
85 abort ();
86 #endif
87 /* RtlAddFunctionTable. */
88 if (e != 0)
89 RtlAddFunctionTable (emu_pdata, e, (DWORD64)_ImageBase);
90 return 1;
91 }
92
93 extern void _fpreset (void);
94
95 EXCEPTION_DISPOSITION
96 __mingw_SEH_error_handler (struct _EXCEPTION_RECORD* ExceptionRecord,
97 void *EstablisherFrame __attribute__ ((unused)),
98 struct _CONTEXT* ContextRecord __attribute__ ((unused)),
99 void *DispatcherContext __attribute__ ((unused)))
100 {
101 EXCEPTION_DISPOSITION action = ExceptionContinueSearch; /* EXCEPTION_CONTINUE_SEARCH; */
102 void (*old_handler) (int);
103 int reset_fpu = 0;
104
105 switch (ExceptionRecord->ExceptionCode)
106 {
107 case EXCEPTION_ACCESS_VIOLATION:
108 /* test if the user has set SIGSEGV */
109 old_handler = signal (SIGSEGV, SIG_DFL);
110 if (old_handler == SIG_IGN)
111 {
112 /* this is undefined if the signal was raised by anything other
113 than raise (). */
114 signal (SIGSEGV, SIG_IGN);
115 action = 0; //EXCEPTION_CONTINUE_EXECUTION;
116 }
117 else if (old_handler != SIG_DFL)
118 {
119 /* This means 'old' is a user defined function. Call it */
120 (*old_handler) (SIGSEGV);
121 action = 0; // EXCEPTION_CONTINUE_EXECUTION;
122 }
123 else
124 action = 4; /* EXCEPTION_EXECUTE_HANDLER; */
125 break;
126 case EXCEPTION_ILLEGAL_INSTRUCTION:
127 case EXCEPTION_PRIV_INSTRUCTION:
128 /* test if the user has set SIGILL */
129 old_handler = signal (SIGILL, SIG_DFL);
130 if (old_handler == SIG_IGN)
131 {
132 /* this is undefined if the signal was raised by anything other
133 than raise (). */
134 signal (SIGILL, SIG_IGN);
135 action = 0; // EXCEPTION_CONTINUE_EXECUTION;
136 }
137 else if (old_handler != SIG_DFL)
138 {
139 /* This means 'old' is a user defined function. Call it */
140 (*old_handler) (SIGILL);
141 action = 0; // EXCEPTION_CONTINUE_EXECUTION;
142 }
143 else
144 action = 4; /* EXCEPTION_EXECUTE_HANDLER;*/
145 break;
146 case EXCEPTION_FLT_INVALID_OPERATION:
147 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
148 case EXCEPTION_FLT_DENORMAL_OPERAND:
149 case EXCEPTION_FLT_OVERFLOW:
150 case EXCEPTION_FLT_UNDERFLOW:
151 case EXCEPTION_FLT_INEXACT_RESULT:
152 reset_fpu = 1;
153 /* fall through. */
154
155 case EXCEPTION_INT_DIVIDE_BY_ZERO:
156 /* test if the user has set SIGFPE */
157 old_handler = signal (SIGFPE, SIG_DFL);
158 if (old_handler == SIG_IGN)
159 {
160 signal (SIGFPE, SIG_IGN);
161 if (reset_fpu)
162 _fpreset ();
163 action = 0; // EXCEPTION_CONTINUE_EXECUTION;
164 }
165 else if (old_handler != SIG_DFL)
166 {
167 /* This means 'old' is a user defined function. Call it */
168 (*old_handler) (SIGFPE);
169 action = 0; // EXCEPTION_CONTINUE_EXECUTION;
170 }
171 break;
172 case EXCEPTION_DATATYPE_MISALIGNMENT:
173 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
174 case EXCEPTION_FLT_STACK_CHECK:
175 case EXCEPTION_INT_OVERFLOW:
176 case EXCEPTION_INVALID_HANDLE:
177 /*case EXCEPTION_POSSIBLE_DEADLOCK: */
178 action = 0; // EXCEPTION_CONTINUE_EXECUTION;
179 break;
180 default:
181 break;
182 }
183 return action;
184 }
185
186 #endif
187
188 LPTOP_LEVEL_EXCEPTION_FILTER __mingw_oldexcpt_handler = NULL;
189
190 long CALLBACK
191 _gnu_exception_handler (EXCEPTION_POINTERS *exception_data);
192
193 #define GCC_MAGIC (('G' << 16) | ('C' << 8) | 'C' | (1U << 29))
194
195 long CALLBACK
196 _gnu_exception_handler (EXCEPTION_POINTERS *exception_data)
197 {
198 void (*old_handler) (int);
199 long action = EXCEPTION_CONTINUE_SEARCH;
200 int reset_fpu = 0;
201
202 #ifdef __SEH__
203 if ((exception_data->ExceptionRecord->ExceptionCode & 0x20ffffff) == GCC_MAGIC)
204 {
205 if ((exception_data->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) == 0)
206 return EXCEPTION_CONTINUE_EXECUTION;
207 }
208 #endif
209
210 switch (exception_data->ExceptionRecord->ExceptionCode)
211 {
212 case EXCEPTION_ACCESS_VIOLATION:
213 /* test if the user has set SIGSEGV */
214 old_handler = signal (SIGSEGV, SIG_DFL);
215 if (old_handler == SIG_IGN)
216 {
217 /* this is undefined if the signal was raised by anything other
218 than raise (). */
219 signal (SIGSEGV, SIG_IGN);
220 action = EXCEPTION_CONTINUE_EXECUTION;
221 }
222 else if (old_handler != SIG_DFL)
223 {
224 /* This means 'old' is a user defined function. Call it */
225 (*old_handler) (SIGSEGV);
226 action = EXCEPTION_CONTINUE_EXECUTION;
227 }
228 break;
229
230 case EXCEPTION_ILLEGAL_INSTRUCTION:
231 case EXCEPTION_PRIV_INSTRUCTION:
232 /* test if the user has set SIGILL */
233 old_handler = signal (SIGILL, SIG_DFL);
234 if (old_handler == SIG_IGN)
235 {
236 /* this is undefined if the signal was raised by anything other
237 than raise (). */
238 signal (SIGILL, SIG_IGN);
239 action = EXCEPTION_CONTINUE_EXECUTION;
240 }
241 else if (old_handler != SIG_DFL)
242 {
243 /* This means 'old' is a user defined function. Call it */
244 (*old_handler) (SIGILL);
245 action = EXCEPTION_CONTINUE_EXECUTION;
246 }
247 break;
248
249 case EXCEPTION_FLT_INVALID_OPERATION:
250 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
251 case EXCEPTION_FLT_DENORMAL_OPERAND:
252 case EXCEPTION_FLT_OVERFLOW:
253 case EXCEPTION_FLT_UNDERFLOW:
254 case EXCEPTION_FLT_INEXACT_RESULT:
255 reset_fpu = 1;
256 /* fall through. */
257
258 case EXCEPTION_INT_DIVIDE_BY_ZERO:
259 /* test if the user has set SIGFPE */
260 old_handler = signal (SIGFPE, SIG_DFL);
261 if (old_handler == SIG_IGN)
262 {
263 signal (SIGFPE, SIG_IGN);
264 if (reset_fpu)
265 _fpreset ();
266 action = EXCEPTION_CONTINUE_EXECUTION;
267 }
268 else if (old_handler != SIG_DFL)
269 {
270 /* This means 'old' is a user defined function. Call it */
271 (*old_handler) (SIGFPE);
272 action = EXCEPTION_CONTINUE_EXECUTION;
273 }
274 break;
275 #ifdef _WIN64
276 case EXCEPTION_DATATYPE_MISALIGNMENT:
277 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
278 case EXCEPTION_FLT_STACK_CHECK:
279 case EXCEPTION_INT_OVERFLOW:
280 case EXCEPTION_INVALID_HANDLE:
281 /*case EXCEPTION_POSSIBLE_DEADLOCK: */
282 action = EXCEPTION_CONTINUE_EXECUTION;
283 break;
284 #endif
285 default:
286 break;
287 }
288
289 if (action == EXCEPTION_CONTINUE_SEARCH && __mingw_oldexcpt_handler)
290 action = (*__mingw_oldexcpt_handler)(exception_data);
291 return action;
292 }