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) && !defined(__SEH__)
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