[MINGW]
[reactos.git] / reactos / lib / 3rdparty / mingw / 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 <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 #define __ImageBase __MINGW_LSYMBOL(_image_base__)
20 /* This symbol is defined by the linker. */
21 extern IMAGE_DOS_HEADER __ImageBase;
22 #endif
23
24 #pragma pack(push,1)
25 typedef struct _UNWIND_INFO {
26 BYTE VersionAndFlags;
27 BYTE PrologSize;
28 BYTE CountOfUnwindCodes;
29 BYTE FrameRegisterAndOffset;
30 ULONG AddressOfExceptionHandler;
31 } UNWIND_INFO,*PUNWIND_INFO;
32 #pragma pack(pop)
33
34 PIMAGE_SECTION_HEADER _FindPESectionByName (const char *);
35 PIMAGE_SECTION_HEADER _FindPESectionExec (size_t);
36 PBYTE _GetPEImageBase (void);
37
38 int __mingw_init_ehandler (void);
39
40 #ifdef _WIN64
41 EXCEPTION_DISPOSITION __mingw_SEH_error_handler(struct _EXCEPTION_RECORD *, void *, struct _CONTEXT *, void *);
42
43 #define MAX_PDATA_ENTRIES 32
44 static RUNTIME_FUNCTION emu_pdata[MAX_PDATA_ENTRIES];
45 static UNWIND_INFO emu_xdata[MAX_PDATA_ENTRIES];
46
47 int
48 __mingw_init_ehandler (void)
49 {
50 static int was_here = 0;
51 size_t e = 0;
52 PIMAGE_SECTION_HEADER pSec;
53 PBYTE _ImageBase = _GetPEImageBase ();
54
55 if (was_here || !_ImageBase)
56 return was_here;
57 was_here = 1;
58 if (_FindPESectionByName (".pdata") != NULL)
59 return 1;
60
61 /* Allocate # of e tables and entries. */
62 memset (emu_pdata, 0, sizeof (RUNTIME_FUNCTION) * MAX_PDATA_ENTRIES);
63 memset (emu_xdata, 0, sizeof (UNWIND_INFO) * MAX_PDATA_ENTRIES);
64
65 e = 0;
66 /* Fill tables and entries. */
67 while (e < MAX_PDATA_ENTRIES && (pSec = _FindPESectionExec (e)) != NULL)
68 {
69 emu_xdata[e].VersionAndFlags = 9; /* UNW_FLAG_EHANDLER | UNW_VERSION */
70 emu_xdata[e].AddressOfExceptionHandler =
71 (DWORD)(size_t) ((LPBYTE)__mingw_SEH_error_handler - _ImageBase);
72 emu_pdata[e].BeginAddress = pSec->VirtualAddress;
73 emu_pdata[e].EndAddress = pSec->VirtualAddress + pSec->Misc.VirtualSize;
74 emu_pdata[e].UnwindData =
75 (DWORD)(size_t)((LPBYTE)&emu_xdata[e] - _ImageBase);
76 ++e;
77 }
78 #ifdef _DEBUG_CRT
79 if (!e || e > MAX_PDATA_ENTRIES)
80 abort ();
81 #endif
82 /* RtlAddFunctionTable. */
83 if (e != 0)
84 RtlAddFunctionTable (emu_pdata, e, (DWORD64)_ImageBase);
85 return 1;
86 }
87
88 extern void _fpreset (void);
89
90 EXCEPTION_DISPOSITION
91 __mingw_SEH_error_handler (struct _EXCEPTION_RECORD* ExceptionRecord,
92 void *EstablisherFrame __attribute__ ((unused)),
93 struct _CONTEXT* ContextRecord __attribute__ ((unused)),
94 void *DispatcherContext __attribute__ ((unused)))
95 {
96 EXCEPTION_DISPOSITION action = EXCEPTION_CONTINUE_SEARCH;
97 void (*old_handler) (int);
98 int reset_fpu = 0;
99
100 switch (ExceptionRecord->ExceptionCode)
101 {
102 case EXCEPTION_ACCESS_VIOLATION:
103 /* test if the user has set SIGSEGV */
104 old_handler = signal (SIGSEGV, SIG_DFL);
105 if (old_handler == SIG_IGN)
106 {
107 /* this is undefined if the signal was raised by anything other
108 than raise (). */
109 signal (SIGSEGV, SIG_IGN);
110 action = EXCEPTION_CONTINUE_EXECUTION;
111 }
112 else if (old_handler != SIG_DFL)
113 {
114 /* This means 'old' is a user defined function. Call it */
115 (*old_handler) (SIGSEGV);
116 action = EXCEPTION_CONTINUE_EXECUTION;
117 }
118 else
119 action = EXCEPTION_EXECUTE_HANDLER;
120 break;
121 case EXCEPTION_ILLEGAL_INSTRUCTION:
122 case EXCEPTION_PRIV_INSTRUCTION:
123 /* test if the user has set SIGILL */
124 old_handler = signal (SIGILL, SIG_DFL);
125 if (old_handler == SIG_IGN)
126 {
127 /* this is undefined if the signal was raised by anything other
128 than raise (). */
129 signal (SIGILL, SIG_IGN);
130 action = EXCEPTION_CONTINUE_EXECUTION;
131 }
132 else if (old_handler != SIG_DFL)
133 {
134 /* This means 'old' is a user defined function. Call it */
135 (*old_handler) (SIGILL);
136 action = EXCEPTION_CONTINUE_EXECUTION;
137 }
138 else
139 action = EXCEPTION_EXECUTE_HANDLER;
140 break;
141 case EXCEPTION_FLT_INVALID_OPERATION:
142 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
143 case EXCEPTION_FLT_DENORMAL_OPERAND:
144 case EXCEPTION_FLT_OVERFLOW:
145 case EXCEPTION_FLT_UNDERFLOW:
146 case EXCEPTION_FLT_INEXACT_RESULT:
147 reset_fpu = 1;
148 /* fall through. */
149
150 case EXCEPTION_INT_DIVIDE_BY_ZERO:
151 /* test if the user has set SIGFPE */
152 old_handler = signal (SIGFPE, SIG_DFL);
153 if (old_handler == SIG_IGN)
154 {
155 signal (SIGFPE, SIG_IGN);
156 if (reset_fpu)
157 _fpreset ();
158 action = EXCEPTION_CONTINUE_EXECUTION;
159 }
160 else if (old_handler != SIG_DFL)
161 {
162 /* This means 'old' is a user defined function. Call it */
163 (*old_handler) (SIGFPE);
164 action = EXCEPTION_CONTINUE_EXECUTION;
165 }
166 break;
167 case EXCEPTION_DATATYPE_MISALIGNMENT:
168 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
169 case EXCEPTION_FLT_STACK_CHECK:
170 case EXCEPTION_INT_OVERFLOW:
171 case EXCEPTION_INVALID_HANDLE:
172 /*case EXCEPTION_POSSIBLE_DEADLOCK: */
173 action = EXCEPTION_CONTINUE_EXECUTION;
174 break;
175 default:
176 break;
177 }
178 return action;
179 }
180
181 #endif