Sync to trunk (r44371)
[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 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 _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 break;
119 case EXCEPTION_ILLEGAL_INSTRUCTION:
120 case EXCEPTION_PRIV_INSTRUCTION:
121 /* test if the user has set SIGILL */
122 old_handler = signal (SIGILL, SIG_DFL);
123 if (old_handler == SIG_IGN)
124 {
125 /* this is undefined if the signal was raised by anything other
126 than raise (). */
127 signal (SIGILL, SIG_IGN);
128 action = EXCEPTION_CONTINUE_EXECUTION;
129 }
130 else if (old_handler != SIG_DFL)
131 {
132 /* This means 'old' is a user defined function. Call it */
133 (*old_handler) (SIGILL);
134 action = EXCEPTION_CONTINUE_EXECUTION;
135 }
136 break;
137 case EXCEPTION_FLT_INVALID_OPERATION:
138 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
139 case EXCEPTION_FLT_DENORMAL_OPERAND:
140 case EXCEPTION_FLT_OVERFLOW:
141 case EXCEPTION_FLT_UNDERFLOW:
142 case EXCEPTION_FLT_INEXACT_RESULT:
143 reset_fpu = 1;
144 /* fall through. */
145
146 case EXCEPTION_INT_DIVIDE_BY_ZERO:
147 /* test if the user has set SIGFPE */
148 old_handler = signal (SIGFPE, SIG_DFL);
149 if (old_handler == SIG_IGN)
150 {
151 signal (SIGFPE, SIG_IGN);
152 if (reset_fpu)
153 _fpreset ();
154 action = EXCEPTION_CONTINUE_EXECUTION;
155 }
156 else if (old_handler != SIG_DFL)
157 {
158 /* This means 'old' is a user defined function. Call it */
159 (*old_handler) (SIGFPE);
160 action = EXCEPTION_CONTINUE_EXECUTION;
161 }
162 break;
163 case EXCEPTION_DATATYPE_MISALIGNMENT:
164 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
165 case EXCEPTION_FLT_STACK_CHECK:
166 case EXCEPTION_INT_OVERFLOW:
167 case EXCEPTION_INVALID_HANDLE:
168 /*case EXCEPTION_POSSIBLE_DEADLOCK: */
169 action = EXCEPTION_CONTINUE_EXECUTION;
170 break;
171 default:
172 break;
173 }
174 return action;
175 }
176
177 #endif