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