source: trunk/include/excpt.h@ 22145

Last change on this file since 22145 was 22009, checked in by dmik, 13 years ago

kernel32: Fix crash when using the new SEH scheme (regression of r21999).

The stack pointer was shifted when doing a longjmp()-like jump back to the
handler which could cause a bunch of weird things. Many Java apps crashed
because of that.

File size: 18.7 KB
Line 
1/*
2 * Project Odin Software License can be found in LICENSE.TXT
3 *
4 * Compiler-level Win32 SEH support for OS/2
5 *
6 * Copyright 2010 Dmitriy Kuminov
7 */
8
9/*
10 * NOTE: This __try/__except and __try/__finally/__leave implementation is not
11 * backed up by the low level compiler support and therefore the following
12 * limitations exist comparing to the MSVC implementation (breaking them will
13 * crash the application):
14 *
15 * 1. You cannot use the return statement within __try or __except or __finally
16 * blocks.
17 *
18 * 2. You cannot use the goto statement or the longjmp() function within __try
19 * or __except or __finally blocks if it passes control outside these blocks.
20 *
21 * 2. If you use __try and friends inside a do/while/for/switch block, you will
22 * lose the meaning of break and continue statements and must not use them.
23 *
24 * 3. The scopes of C and C++ exception blocks may not overlap (i.e. you cannot
25 * use try/catch inside __try/__except and vice versa).
26 *
27 * 4. There may be some other (yet unknown) limitations.
28 *
29 * Fortunately, in most cases, these limitations may be worked around by
30 * slightly changing the original source code.
31 */
32
33#ifndef __EXCPT_H__
34#define __EXCPT_H__
35
36#include <windows.h>
37
38#ifdef __cplusplus
39extern "C" {
40#endif
41
42#if defined(__GNUC__)
43
44struct ___seh_EXCEPTION_FRAME;
45
46#ifdef ODIN_FORCE_WIN32_TIB
47
48typedef int (*__seh_PEXCEPTION_HANDLER_WIN32)(PEXCEPTION_RECORD,
49 struct ___seh_EXCEPTION_FRAME *,
50 PCONTEXT, PVOID);
51
52#pragma pack(1)
53
54typedef struct ___seh_EXCEPTION_FRAME
55{
56 /* + 0 */ struct ___seh_EXCEPTION_FRAME *pPrev;
57 /* + 4 */ __seh_PEXCEPTION_HANDLER_WIN32 pHandler;
58 /* + 8 */ void *pFilterCallback;
59 /* +12 */ void *pHandlerCallback;
60 /* +16 */ void *pHandlerContext;
61 /* +20 */ int filterResult;
62 /* +24 */ DWORD EBX;
63 /* +28 */ DWORD ESI;
64 /* +32 */ DWORD EDI;
65 /* +36 */ DWORD EBP;
66 /* +40 */ DWORD ESP;
67 /* +44 */ DWORD pPrevFrameOS2;
68 /* +48 */ EXCEPTION_POINTERS Pointers;
69 /* +56 */ int state;
70 /* +60 */ DWORD pPrevFrameWin32;
71 /* +64 */ DWORD Win32FS;
72}
73__seh_EXCEPTION_FRAME;
74
75#pragma pack()
76
77extern int __seh_handler_win32(PEXCEPTION_RECORD pRec,
78 struct ___seh_EXCEPTION_FRAME *pFrame,
79 PCONTEXT pContext, PVOID pVoid);
80
81#else /* ODIN_FORCE_WIN32_TIB */
82
83typedef int (*__seh_PEXCEPTION_HANDLER)(PVOID,
84 struct ___seh_EXCEPTION_FRAME *,
85 PVOID, PVOID);
86
87#pragma pack(1)
88
89typedef struct ___seh_EXCEPTION_FRAME
90{
91 /* + 0 */ struct ___seh_EXCEPTION_FRAME *pPrev;
92 /* + 4 */ __seh_PEXCEPTION_HANDLER pHandler;
93 /* + 8 */ void *pFilterCallback;
94 /* +12 */ void *pHandlerCallback;
95 /* +16 */ void *pHandlerContext;
96 /* +20 */ int filterResult;
97 /* +24 */ DWORD EBX;
98 /* +28 */ DWORD ESI;
99 /* +32 */ DWORD EDI;
100 /* +36 */ DWORD EBP;
101 /* +40 */ DWORD ESP;
102 /* +44 */ EXCEPTION_POINTERS Pointers;
103 /* +52 */ int state;
104}
105__seh_EXCEPTION_FRAME;
106
107#pragma pack()
108
109extern int __seh_handler(PVOID pRec,
110 struct ___seh_EXCEPTION_FRAME *pFrame,
111 PVOID pContext, PVOID pVoid);
112
113#endif /* ODIN_FORCE_WIN32_TIB */
114
115#define _exception_code() (__seh_frame.Pointers.ExceptionRecord->ExceptionCode)
116#define _exception_info() ((void *)&__seh_frame.Pointers)
117
118#define exception_code _exception_code
119#define exception_info (PEXCEPTION_POINTERS)_exception_info
120
121#define GetExceptionCode _exception_code
122#define GetExceptionInformation (PEXCEPTION_POINTERS)_exception_info
123
124#ifdef ODIN_FORCE_WIN32_TIB
125
126#define __try \
127 volatile __seh_EXCEPTION_FRAME __seh_frame; \
128 __seh_frame.pHandler = __seh_handler_win32; \
129 __seh_frame.Pointers.ExceptionRecord = NULL; \
130 __seh_frame.Pointers.ContextRecord = NULL; \
131 __seh_frame.state = 0; \
132 /* install exception handler, both Win32 and OS/2 chains (note: EDX is in \
133 * clobber too since it may carry any value when we jump back to \
134 * pFilterCallback from the handler */ \
135 __asm__ ("leal %0, %%ecx; " \
136 "movl %%fs, %%eax; " \
137 "andl $0x0000FFFF, %%eax; " \
138 "movl %%eax, 64(%%ecx); " \
139 "movl %%fs:0, %%eax; " \
140 "movl %%eax, 0(%%ecx); " \
141 "movl %%eax, 60(%%ecx); " \
142 "movl $0f, 8(%%ecx); " \
143 \
144 "movl %%ebx, 24(%%ecx); " \
145 "movl %%esi, 28(%%ecx); " \
146 "movl %%edi, 32(%%ecx); " \
147 "movl %%ebp, 36(%%ecx); " \
148 "movl %%esp, 40(%%ecx); " \
149 \
150 "pushl %%fs; " \
151 "pushl $Dos32TIB; " \
152 "popl %%fs; " \
153 "movl %%fs:0, %%eax; " \
154 "movl %%eax, 44(%%ecx); " \
155 "movl %%ecx, %%fs:0; " \
156 "popl %%fs; " \
157 \
158 "movl %%ecx, %%fs:0; " \
159 \
160 "\n0: /* pFilterCallback */ \n" \
161 \
162 : : "m" (__seh_frame) \
163 : "%eax", "%ecx", "%edx"); \
164 for (; __seh_frame.state <= 3; ++__seh_frame.state) \
165 if (__seh_frame.state == 0) \
166 { \
167 {
168
169#define __except(filter_expr) \
170 } \
171 /* cause the next state to be 3 */ \
172 __seh_frame.state = 2; \
173 } \
174 else if (__seh_frame.state == 1) { \
175 /* execption caught, call filter expression */ \
176 __seh_frame.filterResult = (filter_expr); \
177 __asm__("leal %0, %%ebx; jmp *%1" \
178 : : "m"(__seh_frame), "m"(__seh_frame.pHandlerCallback) \
179 : "%ebx"); \
180 } \
181 else if (__seh_frame.state == 3) \
182 /* remove exception handler (note that for some reason SMP kernel \
183 * seems to garbage the Win32FS:[0] cell with the OS/2 exception \
184 * registration record, so use the original __seh_frame value) */ \
185 __asm__ ("leal %0, %%ecx; " \
186 \
187 "movl 64(%%ecx), %%eax; " \
188 "movl %%eax, %%fs; " \
189 \
190 "movl 60(%%ecx), %%eax; " \
191 "movl %%eax, %%fs:0; " \
192 \
193 "pushl %%fs; " \
194 "pushl $Dos32TIB; " \
195 "popl %%fs; " \
196 "movl 44(%%ecx), %%eax; " \
197 "movl %%eax, %%fs:0; " \
198 "popl %%fs; " \
199 : : "m"(__seh_frame) \
200 : "%eax", "%ecx"); \
201 else /* __seh_frame.state == 2 -> execute except block */
202
203#define __finally \
204 } \
205 /* cause the next state to be 2 */ \
206 __seh_frame.state = 1; \
207 } \
208 else if (__seh_frame.state == 1) { \
209 /* execption caught, handle and proceed to the filally block */ \
210 __seh_frame.filterResult = EXCEPTION_EXECUTE_HANDLER; \
211 __asm__("leal %0, %%ebx; jmp *%1" \
212 : : "m"(__seh_frame), "m"(__seh_frame.pHandlerCallback) \
213 : "%ebx"); \
214 } \
215 else if (__seh_frame.state == 3) \
216 /* remove exception handler (note that for some reason SMP kernel \
217 * seems to garbage the Win32FS:[0] cell with the OS/2 exception \
218 * registration record, so use the original __seh_frame value) */ \
219 __asm__ ("leal %0, %%ecx; " \
220 \
221 "movl 64(%%ecx), %%eax; " \
222 "movl %%eax, %%fs; " \
223 \
224 "movl 60(%%ecx), %%eax; " \
225 "movl %%eax, %%fs:0; " \
226 \
227 "pushl %%fs; " \
228 "pushl $Dos32TIB; " \
229 "popl %%fs; " \
230 "movl 44(%%ecx), %%eax; " \
231 "movl %%eax, %%fs:0; " \
232 "popl %%fs; " \
233 : : "m"(__seh_frame) \
234 : "%eax", "%ecx"); \
235 else /* __seh_frame.state == 2 -> execute finally block */
236
237#define __leave \
238 /* cause the next state to be 2 */ \
239 __seh_frame.state = 1; \
240 continue;
241
242#else /* ODIN_FORCE_WIN32_TIB */
243
244#define __try \
245 volatile __seh_EXCEPTION_FRAME __seh_frame; \
246 __seh_frame.pHandler = __seh_handler; \
247 __seh_frame.Pointers.ExceptionRecord = NULL; \
248 __seh_frame.Pointers.ContextRecord = NULL; \
249 __seh_frame.state = 0; \
250 /* install OS/2 exception handler (note: EDX is in clobber too since it \
251 * may carry any value when we jump back to pFilterCallback from the \
252 * handler */ \
253 __asm__ ("leal %0, %%ecx; " \
254 "pushl %%fs; " \
255 "pushl $Dos32TIB; " \
256 "popl %%fs; " \
257 "movl %%fs:0, %%eax; " \
258 "movl %%eax, 0(%%ecx); " \
259 "movl $0f, 8(%%ecx); " \
260 "movl %%ebx, 24(%%ecx); " \
261 "movl %%esi, 28(%%ecx); " \
262 "movl %%edi, 32(%%ecx); " \
263 "movl %%ebp, 36(%%ecx); " \
264 "movl %%esp, 40(%%ecx); " \
265 "addl $4, 40(%%ecx); " /* compensate for one PUSHL */ \
266 "movl %%ecx, %%fs:0; " \
267 "popl %%fs; " \
268 \
269 "\n0: /* pFilterCallback */ \n" \
270 \
271 : : "m" (__seh_frame) \
272 : "%eax", "%ecx", "%edx"); \
273 for (; __seh_frame.state <= 3; ++__seh_frame.state) \
274 if (__seh_frame.state == 0) \
275 { \
276 {
277
278#define __except(filter_expr) \
279 } \
280 /* cause the next state to be 3 */ \
281 __seh_frame.state = 2; \
282 } \
283 else if (__seh_frame.state == 1) { \
284 /* execption caught, call filter expression */ \
285 __seh_frame.filterResult = (filter_expr); \
286 __asm__("leal %0, %%ebx; jmp *%1" \
287 : : "m"(__seh_frame), "m"(__seh_frame.pHandlerCallback) \
288 : "%ebx"); \
289 } \
290 else if (__seh_frame.state == 3) \
291 /* remove exception handler */ \
292 __asm__ ("leal %0, %%ecx; " \
293 "pushl %%fs; " \
294 "pushl $Dos32TIB; " \
295 "popl %%fs; " \
296 "movl 0(%%ecx), %%eax; " \
297 "movl %%eax, %%fs:0; " \
298 "popl %%fs; " \
299 : : "m"(__seh_frame) \
300 : "%eax", "%ecx"); \
301 else /* __seh_frame.state == 2 -> execute except block */
302
303#define __finally \
304 } \
305 /* cause the next state to be 2 */ \
306 __seh_frame.state = 1; \
307 } \
308 else if (__seh_frame.state == 1) { \
309 /* execption caught, handle and proceed to the filally block */ \
310 __seh_frame.filterResult = EXCEPTION_EXECUTE_HANDLER; \
311 __asm__("leal %0, %%ebx; jmp *%1" \
312 : : "m"(__seh_frame), "m"(__seh_frame.pHandlerCallback) \
313 : "%ebx"); \
314 } \
315 else if (__seh_frame.state == 3) \
316 /* remove exception handler */ \
317 __asm__ ("leal %0, %%ecx; " \
318 "pushl %%fs; " \
319 "pushl $Dos32TIB; " \
320 "popl %%fs; " \
321 "movl 0(%%ecx), %%eax; " \
322 "movl %%eax, %%fs:0; " \
323 "popl %%fs; " \
324 : : "m"(__seh_frame) \
325 : "%eax", "%ecx"); \
326 else /* __seh_frame.state == 2 -> execute finally block */
327
328#define __leave \
329 /* cause the next state to be 2 */ \
330 __seh_frame.state = 1; \
331 continue;
332
333#endif /* ODIN_FORCE_WIN32_TIB */
334
335#else /* defined(__GNUC__) */
336
337#warning "Structured exception handling is not supported for this compiler!"
338
339#endif /* defined(__GNUC__) */
340
341#ifdef __cplusplus
342}
343#endif
344
345#endif /* __EXCPT_H__ */
346
Note: See TracBrowser for help on using the repository browser.