added include/reactos/libs/pseh/pseh2.h
[reactos.git] / reactos / include / reactos / libs / pseh / pseh2.h
1 /*
2 Copyright (c) 2008 KJK::Hyperion
3
4 Permission is hereby granted, free of charge, to any person obtaining a
5 copy of this software and associated documentation files (the "Software"),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 DEALINGS IN THE SOFTWARE.
21 */
22
23 #ifndef KJK_PSEH2_H_
24 #define KJK_PSEH2_H_
25
26 #ifndef __GNUC__
27 #error TODO
28 #endif
29
30 struct _EXCEPTION_RECORD;
31 struct _EXCEPTION_POINTERS;
32 struct _CONTEXT;
33
34 typedef int (__cdecl * _SEHFrameHandler_t)
35 (
36 struct _EXCEPTION_RECORD *,
37 void *,
38 struct _CONTEXT *,
39 void *
40 );
41
42 #if defined(__i386__)
43 typedef struct __SEHTrampoline
44 {
45 unsigned char STR_MovEcx;
46 unsigned char STR_Closure[4];
47 unsigned char STR_Jmp;
48 unsigned char STR_Function[4];
49 }
50 _SEHTrampoline_t;
51
52 static
53 __inline__
54 __attribute__((always_inline))
55 int _SEHIsTrampoline(_SEHTrampoline_t * trampoline_)
56 {
57 return trampoline_->STR_MovEcx == 0xb9 && trampoline_->STR_Jmp == 0xe9;
58 }
59
60 static
61 __inline__
62 __attribute__((always_inline))
63 void * _SEHFunctionFromTrampoline(_SEHTrampoline_t * trampoline_)
64 {
65 return (void *)(*(int *)(&trampoline_->STR_Function[0]) + (int)(trampoline_ + 1));
66 }
67
68 static
69 __inline__
70 __attribute__((always_inline))
71 void * _SEHClosureFromTrampoline(_SEHTrampoline_t * trampoline_)
72 {
73 return (void *)*(int *)(&trampoline_->STR_Closure[0]);
74 }
75 #else
76 #error TODO
77 #endif
78
79 /* A no-op side effect that scares GCC */
80 #define __SEH_SIDE_EFFECT __asm__ __volatile__("#")
81
82 /* A no-op without any real side effects, but silences warnings */
83 #define __SEH_PRETEND_SIDE_EFFECT (void)0
84
85 /* Forces GCC to consider the specified label reachable */
86 #define __SEH_USE_LABEL(L_) __asm__ __volatile__("# %0\n" : : "i" (&&L_))
87
88 /* Makes GCC pretend the specified label is reachable, to silence warnings */
89 #define __SEH_PRETEND_USE_LABEL(L_) (void)(&&L_)
90
91 /* Forces GCC to emit the specified nested function as a function */
92 #define __SEH_USE_NESTED_FUNCTION(F_) (void)(&F_) /* __attribute__((noinline)) seems to do the trick */
93
94 /* Soft memory barrier */
95 #define __SEH_BARRIER __asm__ __volatile__("#":::"memory")
96
97 typedef struct __SEHRegistration
98 {
99 struct __SEHRegistration * SER_Prev;
100 _SEHFrameHandler_t SER_Handler;
101 }
102 _SEHRegistration_t;
103
104 #define __SEH_FORCE_NEST \
105 __asm__ __volatile__("#%0" : : "r" (&_SEHFrame))
106
107 #define __SEH_NESTED_PROLOG \
108 __SEH_FORCE_NEST;
109
110 #define __SEH_DECLARE_EXCEPT_PFN(NAME_) int (__cdecl * NAME_)(void *)
111 #define __SEH_DECLARE_EXCEPT(NAME_) int __cdecl NAME_(void *)
112 #define __SEH_DEFINE_EXCEPT(NAME_) int __cdecl NAME_(void * _SEHExceptionPointers)
113
114 #define __SEH_DECLARE_FINALLY_PFN(NAME_) void (__cdecl * NAME_)(void)
115 #define __SEH_DECLARE_FINALLY(NAME_) void __cdecl NAME_(void)
116 #define __SEH_DEFINE_FINALLY(NAME_) void __cdecl NAME_(void)
117
118 #define __SEH_RETURN_EXCEPT(R_) return (int)(R_)
119 #define __SEH_RETURN_FINALLY() return
120
121 typedef struct __SEHFrame
122 {
123 _SEHRegistration_t SF_Registration;
124 volatile struct __SEHTryLevel * volatile SF_TopTryLevel;
125 void * SF_FramePointer;
126 void * volatile SF_StackPointer;
127 volatile unsigned long SF_Code;
128 }
129 _SEHFrame_t;
130
131 typedef struct __SEHTryLevel
132 {
133 volatile struct __SEHTryLevel * ST_Next;
134 void * ST_FramePointer;
135 void * ST_Filter;
136 void * ST_Body;
137 }
138 _SEHTryLevel_t;
139
140 #define __SEH_BEGIN_TRY \
141 { \
142 __label__ _SEHBeginTry; \
143 __label__ _SEHEndTry; \
144 \
145 __SEH_USE_LABEL(_SEHBeginTry); \
146 __SEH_USE_LABEL(_SEHEndTry); \
147 \
148 _SEHBeginTry: __SEH_SIDE_EFFECT; \
149 { \
150 __SEH_BARRIER;
151
152 #define __SEH_END_TRY \
153 __SEH_BARRIER; \
154 } \
155 _SEHEndTry: __SEH_SIDE_EFFECT; \
156 }
157
158 #define __SEH_SET_TRYLEVEL(TRYLEVEL_) \
159 { \
160 __SEH_BARRIER; _SEHFrameP->SF_TopTryLevel = (TRYLEVEL_); __SEH_BARRIER; \
161 }
162
163 #define __SEH_ENTER_TRYLEVEL() __SEH_SET_TRYLEVEL(&_SEHTryLevel)
164 #define __SEH_LEAVE_TRYLEVEL() __SEH_SET_TRYLEVEL(_SEHPrevTryLevelP)
165
166 #define __SEH_END_SCOPE_CHAIN \
167 static const int _SEHScopeKind = 1; \
168 static _SEHFrame_t * const _SEHFrameP = 0; \
169 static _SEHTryLevel_t * const _SEHTryLevelP = 0;
170
171 #define __SEH_BEGIN_SCOPE \
172 for(;;) \
173 { \
174 __label__ _SEHBeginScope; \
175 __label__ _SEHEndScope; \
176 \
177 _SEHBeginScope: __SEH_SIDE_EFFECT; \
178 \
179 static const int _SEHTopTryLevel = (_SEHScopeKind != 0); \
180 _SEHFrame_t * const _SEHCurFrameP = _SEHFrameP; \
181 volatile _SEHTryLevel_t * const _SEHPrevTryLevelP = _SEHTryLevelP; \
182 \
183 (void)_SEHTopTryLevel; \
184 (void)_SEHCurFrameP; \
185 (void)_SEHPrevTryLevelP; \
186 \
187 __SEH_USE_LABEL(_SEHBeginScope); \
188 __SEH_USE_LABEL(_SEHEndScope); \
189 \
190 { \
191 __label__ _SEHBeforeTry; \
192 __label__ _SEHDoTry; \
193 __label__ _SEHAfterTry; \
194 static const int _SEHScopeKind = 0; \
195 _SEHFrame_t _SEHFrame; \
196 volatile _SEHTryLevel_t _SEHTryLevel; \
197 _SEHFrame_t * const _SEHFrameP = _SEHTopTryLevel ? &_SEHFrame : _SEHCurFrameP; \
198 volatile _SEHTryLevel_t * const _SEHTryLevelP = &_SEHTryLevel; \
199 \
200 (void)_SEHScopeKind; \
201 (void)_SEHFrame; \
202 (void)_SEHTryLevel; \
203 (void)_SEHFrameP; \
204 (void)_SEHTryLevelP; \
205 \
206 _SEHTryLevel.ST_Next = _SEHPrevTryLevelP; \
207 goto _SEHBeforeTry; \
208 \
209 _SEHDoTry:; \
210 __SEH_ENTER_TRYLEVEL(); \
211 \
212 if(_SEHTopTryLevel) \
213 { \
214 __SEH_BARRIER; __asm__ __volatile__("mov %%ebp, %0\n#%1" : "=m" (_SEHFrame.SF_FramePointer) : "r" (__builtin_frame_address(0))); __SEH_BARRIER; \
215 _SEH2EnterFrame(&_SEHFrame); \
216 } \
217
218 #define __SEH_END_SCOPE \
219 } \
220 \
221 _SEHEndScope: __SEH_SIDE_EFFECT; \
222 \
223 break; \
224 }
225
226 #define __SEH_SCOPE_LOCALS \
227 __label__ _SEHBeginExcept; \
228 __label__ _SEHEndExcept; \
229 \
230 auto __SEH_DECLARE_EXCEPT(_SEHExcept); \
231 auto __SEH_DECLARE_FINALLY(_SEHFinally);
232
233 #define _SEH2_TRY \
234 __SEH_BEGIN_SCOPE \
235 { \
236 __SEH_SCOPE_LOCALS; \
237 \
238 void _SEHJumpToHandler() { goto _SEHBeginExcept; } \
239 \
240 __SEH_BEGIN_TRY \
241 {
242
243 #define _SEH2_FINALLY \
244 } \
245 __SEH_END_TRY; \
246 \
247 goto _SEHAfterTry; \
248 _SEHBeforeTry:; \
249 \
250 __SEH_PRETEND_USE_LABEL(_SEHBeginExcept); \
251 __SEH_PRETEND_USE_LABEL(_SEHEndExcept); \
252 \
253 __SEH_USE_NESTED_FUNCTION(_SEHFinally); \
254 \
255 _SEHTryLevel.ST_FramePointer = _SEHClosureFromTrampoline((_SEHTrampoline_t *)&_SEHFinally); \
256 _SEHTryLevel.ST_Filter = NULL; \
257 _SEHTryLevel.ST_Body = _SEHFunctionFromTrampoline((_SEHTrampoline_t *)&_SEHFinally); \
258 \
259 goto _SEHDoTry; \
260 _SEHAfterTry:; \
261 \
262 if(_SEHTopTryLevel) \
263 _SEH2LeaveFrame(); \
264 else \
265 { \
266 __SEH_LEAVE_TRYLEVEL(); \
267 } \
268 \
269 _SEHFinally(); \
270 goto _SEHEndExcept; \
271 \
272 _SEHBeginExcept: __SEH_PRETEND_SIDE_EFFECT; \
273 __attribute__((unused)) __SEH_DEFINE_EXCEPT(_SEHExcept) { __SEH_RETURN_EXCEPT(0); } \
274 \
275 __attribute__((noinline)) __attribute__((used)) __SEH_DEFINE_FINALLY(_SEHFinally) \
276 { \
277 __SEH_END_SCOPE_CHAIN; \
278 \
279 (void)_SEHScopeKind; \
280 (void)_SEHFrameP; \
281 (void)_SEHTryLevelP; \
282 \
283 __SEH_NESTED_PROLOG; \
284 \
285 for(;; ({ __SEH_RETURN_FINALLY(); })) \
286 {
287
288 #define _SEH2_EXCEPT(E_) \
289 } \
290 __SEH_END_TRY; \
291 \
292 goto _SEHAfterTry; \
293 \
294 _SEHBeforeTry:; \
295 \
296 __SEH_USE_LABEL(_SEHBeginExcept); \
297 __SEH_USE_LABEL(_SEHEndExcept); \
298 \
299 __SEH_USE_NESTED_FUNCTION(_SEHExcept); \
300 \
301 _SEHTryLevel.ST_FramePointer = _SEHClosureFromTrampoline((_SEHTrampoline_t *)&_SEHExcept); \
302 _SEHTryLevel.ST_Filter = _SEHFunctionFromTrampoline((_SEHTrampoline_t *)&_SEHExcept); \
303 _SEHTryLevel.ST_Body = &&_SEHBeginExcept; \
304 __SEH_BARRIER; __asm__ __volatile__("mov %%esp, %0" : "=m" (_SEHFrameP->SF_StackPointer)); __SEH_BARRIER; \
305 \
306 goto _SEHDoTry; \
307 \
308 __attribute__((noinline)) __attribute__((used)) __SEH_DEFINE_EXCEPT(_SEHExcept) \
309 { \
310 __SEH_NESTED_PROLOG; \
311 __SEH_RETURN_EXCEPT(E_); \
312 } \
313 \
314 __attribute__((unused)) __SEH_DEFINE_FINALLY(_SEHFinally) { __SEH_RETURN_FINALLY(); } \
315 \
316 _SEHAfterTry:; \
317 if(_SEHTopTryLevel) \
318 _SEH2LeaveFrame(); \
319 else \
320 { \
321 __SEH_LEAVE_TRYLEVEL(); \
322 } \
323 \
324 goto _SEHEndExcept; \
325 \
326 _SEHBeginExcept: __SEH_SIDE_EFFECT; \
327 { \
328 { \
329 _SEHFrame_t * const _SEHFrameP = _SEHTopTryLevel ? &_SEHFrame : _SEHCurFrameP; \
330 __SEH_BARRIER;
331
332 #define _SEH2_END \
333 __SEH_BARRIER; \
334 } \
335 } \
336 _SEHEndExcept: __SEH_SIDE_EFFECT; \
337 } \
338 __SEH_END_SCOPE;
339
340 #define _SEH2_GetExceptionPointers() ((struct _EXCEPTION_POINTERS *)_SEHExceptionPointers)
341 #define _SEH2_GetExceptionCode() ((_SEHFrameP)->SF_Code)
342
343 __SEH_END_SCOPE_CHAIN;
344
345 #ifdef __cplusplus
346 extern "C"
347 {
348 #endif
349
350 extern void __cdecl _SEH2EnterFrame(_SEHFrame_t *);
351 extern void __cdecl _SEH2LeaveFrame(void);
352
353 #ifdef __cplusplus
354 }
355 #endif
356
357 #endif
358
359 /* EOF */