xref: /reactos/sdk/lib/crt/startup/crt_handler.c (revision cce399e7)
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 #define _NTSYSTEM_
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 __cdecl _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 __cdecl _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 }
293