source: trunk/include/excpt.h@ 21503

Last change on this file since 21503 was 21474, checked in by dmik, 15 years ago

kernel32/SEH: Added support for setjmp()/longjmp() within the try block. See #26.

File size: 9.8 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 Dmitry A. 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;
45typedef int (*__seh_PEXCEPTION_HANDLER)(PEXCEPTION_RECORD,
46 struct ___seh_EXCEPTION_FRAME *,
47 PCONTEXT, PVOID);
48
49#pragma pack(1)
50
51typedef struct ___seh_EXCEPTION_FRAME
52{
53 /* + 0 */ struct ___seh_EXCEPTION_FRAME *pPrev;
54 /* + 4 */ __seh_PEXCEPTION_HANDLER pHandler;
55 /* + 8 */ void *pFilterCallback;
56 /* +12 */ void *pHandlerCallback;
57 /* +16 */ void *pHandlerContext;
58 /* +20 */ int filterResult;
59 /* +24 */ DWORD EBX;
60 /* +28 */ DWORD ESI;
61 /* +32 */ DWORD EDI;
62 /* +36 */ DWORD EBP;
63 /* +40 */ DWORD ESP;
64 /* +44 */ DWORD pPrevFrameOS2;
65 /* +48 */ EXCEPTION_POINTERS Pointers;
66 /* +56 */ int state;
67 /* +60 */ DWORD pPrevFrameWin32;
68}
69__seh_EXCEPTION_FRAME;
70
71#pragma pack()
72
73extern int __seh_handler(PEXCEPTION_RECORD pRec,
74 struct ___seh_EXCEPTION_FRAME *pFrame,
75 PCONTEXT pContext, PVOID pVoid);
76
77#define _exception_code() (__seh_frame.Pointers.ExceptionRecord->ExceptionCode)
78#define _exception_info() ((void *)&__seh_frame.Pointers)
79
80#define exception_code _exception_code
81#define exception_info (PEXCEPTION_POINTERS)_exception_info
82
83#define GetExceptionCode _exception_code
84#define GetExceptionInformation (PEXCEPTION_POINTERS)_exception_info
85
86#define __try \
87 volatile __seh_EXCEPTION_FRAME __seh_frame; \
88 __seh_frame.pHandler = __seh_handler; \
89 __seh_frame.Pointers.ExceptionRecord = NULL; \
90 __seh_frame.Pointers.ContextRecord = NULL; \
91 __seh_frame.state = 0; \
92 __asm__("\n0:\n"); /* pFilterCallback */ \
93 for (; __seh_frame.state <= 3; ++__seh_frame.state) \
94 if (__seh_frame.state == 0) \
95 { \
96 /* install exception handler (both Win32 and OS/2 chains) */ \
97 __asm__ ("leal %0, %%ecx; " \
98 "movl %%fs:0, %%eax; " \
99 "movl %%eax, 0(%%ecx); " \
100 "movl %%eax, 60(%%ecx); " \
101 "movl $0b, 8(%%ecx); " \
102 "" \
103 "movl %%ebx, 24(%%ecx); " \
104 "movl %%esi, 28(%%ecx); " \
105 "movl %%edi, 32(%%ecx); " \
106 "movl %%ebp, 36(%%ecx); " \
107 "movl %%esp, 40(%%ecx); " \
108 "" \
109 "pushl %%fs; " \
110 "pushl $Dos32TIB; " \
111 "popl %%fs; " \
112 "movl %%fs:0, %%eax; " \
113 "movl %%eax, 44(%%ecx); " \
114 "movl %%ecx, %%fs:0; " \
115 "popl %%fs; " \
116 "" \
117 "movl %%ecx, %%fs:0; " \
118 : : "m" (__seh_frame) \
119 : "%eax", "%ecx"); \
120 {
121
122#define __except(filter_expr) \
123 } \
124 /* cause the next state to be 3 */ \
125 __seh_frame.state = 2; \
126 } \
127 else if (__seh_frame.state == 1) { \
128 /* execption caught, call filter expression */ \
129 __seh_frame.filterResult = (filter_expr); \
130 __asm__("leal %0, %%ebx; jmp *%1" \
131 : : "m"(__seh_frame), "m"(__seh_frame.pHandlerCallback) \
132 : "%ebx"); \
133 } \
134 else if (__seh_frame.state == 3) \
135 /* remove exception handler */ \
136 __asm__ ("movl %%fs:0, %%ecx; " \
137 "movl 60(%%ecx), %%eax; " \
138 "movl %%eax, %%fs:0; " \
139 "" \
140 "pushl %%fs; " \
141 "pushl $Dos32TIB; " \
142 "popl %%fs; " \
143 "movl 44(%%ecx), %%eax; " \
144 "movl %%eax, %%fs:0; " \
145 "popl %%fs; " \
146 : : \
147 : "%eax", "%ecx"); \
148 else /* __seh_frame.state == 2 -> execute except block */
149
150#define __finally \
151 } \
152 /* cause the next state to be 2 */ \
153 __seh_frame.state = 1; \
154 } \
155 else if (__seh_frame.state == 1) { \
156 /* execption caught, handle and proceed to the filally block */ \
157 __seh_frame.filterResult = EXCEPTION_EXECUTE_HANDLER; \
158 __asm__("leal %0, %%ebx; jmp *%1" \
159 : : "m"(__seh_frame), "m"(__seh_frame.pHandlerCallback) \
160 : "%ebx"); \
161 } \
162 else if (__seh_frame.state == 3) \
163 /* remove exception handler */ \
164 __asm__ ("movl %%fs:0, %%ecx; " \
165 "movl 60(%%ecx), %%eax; " \
166 "movl %%eax, %%fs:0; " \
167 "" \
168 "pushl %%fs; " \
169 "pushl $Dos32TIB; " \
170 "popl %%fs; " \
171 "movl 44(%%ecx), %%eax; " \
172 "movl %%eax, %%fs:0; " \
173 "popl %%fs; " \
174 : : \
175 : "%eax", "%ecx"); \
176 else /* __seh_frame.state == 2 -> execute finally block */
177
178#define __leave \
179 /* cause the next state to be 2 */ \
180 __seh_frame.state = 1; \
181 continue;
182
183#else /* defined(__GNUC__) */
184
185#warning "Structured exception handling is not supported for this compiler!"
186
187#endif /* defined(__GNUC__) */
188
189#ifdef __cplusplus
190}
191#endif
192
193#endif /* __EXCPT_H__ */
194
Note: See TracBrowser for help on using the repository browser.