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