merge trunk head (37902)
[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 #ifdef _M_AMD64
23 #include "pseh2_64.h"
24 #else
25
26 #ifndef KJK_PSEH2_H_
27 #define KJK_PSEH2_H_
28
29 struct _EXCEPTION_RECORD;
30 struct _EXCEPTION_POINTERS;
31 struct _CONTEXT;
32
33 typedef int (__cdecl * _SEH2FrameHandler_t)
34 (
35 struct _EXCEPTION_RECORD *,
36 void *,
37 struct _CONTEXT *,
38 void *
39 );
40
41 typedef struct __SEH2Registration
42 {
43 struct __SEH2Registration * SER_Prev;
44 _SEH2FrameHandler_t SER_Handler;
45 }
46 _SEH2Registration_t;
47
48 typedef struct __SEH2Frame
49 {
50 _SEH2Registration_t SF_Registration;
51 volatile struct __SEH2TryLevel * volatile SF_TopTryLevel;
52 void * volatile SF_FramePointer;
53 void * volatile SF_StackPointer;
54 volatile unsigned long SF_Code;
55 }
56 _SEH2Frame_t;
57
58 typedef struct __SEH2TryLevel
59 {
60 volatile struct __SEH2TryLevel * ST_Next;
61 void * ST_FramePointer;
62 void * ST_Filter;
63 void * ST_Body;
64 }
65 _SEH2TryLevel_t;
66
67 #ifdef __cplusplus
68 extern "C"
69 {
70 #endif
71
72 extern void __cdecl _SEH2EnterFrame(_SEH2Frame_t *);
73 extern void __cdecl _SEH2LeaveFrame(void);
74 extern void __cdecl _SEH2Return(void);
75
76 #ifdef __cplusplus
77 }
78 #endif
79
80 #if defined(__GNUC__)
81
82 #if defined(__i386__)
83 typedef struct __SEHTrampoline
84 {
85 unsigned char STR_MovEcx;
86 unsigned char STR_Closure[4];
87 unsigned char STR_Jmp;
88 unsigned char STR_Function[4];
89 }
90 _SEHTrampoline_t;
91
92 static
93 __inline__
94 __attribute__((always_inline))
95 int _SEHIsTrampoline(_SEHTrampoline_t * trampoline_)
96 {
97 return trampoline_->STR_MovEcx == 0xb9 && trampoline_->STR_Jmp == 0xe9;
98 }
99
100 static
101 __inline__
102 __attribute__((always_inline))
103 void * _SEHFunctionFromTrampoline(_SEHTrampoline_t * trampoline_)
104 {
105 return (void *)(*(int *)(&trampoline_->STR_Function[0]) + (int)(trampoline_ + 1));
106 }
107
108 static
109 __inline__
110 __attribute__((always_inline))
111 void * _SEHClosureFromTrampoline(_SEHTrampoline_t * trampoline_)
112 {
113 return (void *)*(int *)(&trampoline_->STR_Closure[0]);
114 }
115 #else
116 #error TODO
117 #endif
118
119 /* A no-op side effect that scares GCC */
120 #define __SEH_SIDE_EFFECT __asm__ __volatile__("#")
121
122 /* A no-op without any real side effects, but silences warnings */
123 #define __SEH_PRETEND_SIDE_EFFECT (void)0
124
125 /* Forces GCC to consider the specified label reachable */
126 #define __SEH_USE_LABEL(L_) __asm__ __volatile__("# %0\n" : : "i" (&&L_))
127
128 /* Makes GCC pretend the specified label is reachable, to silence warnings */
129 #define __SEH_PRETEND_USE_LABEL(L_) (void)(&&L_)
130
131 /* Forces GCC to emit the specified nested function as a function */
132 #define __SEH_USE_NESTED_FUNCTION(F_) (void)(&F_) /* __attribute__((noinline)) seems to do the trick */
133
134 /* Soft memory barrier */
135 #define __SEH_BARRIER __asm__ __volatile__("#":::"memory")
136
137 /* GCC doesn't know that this equals zero */
138 #define __SEH_ZERO ({ int zero = 0; __asm__ __volatile__("#" : "+g" (zero)); zero; })
139
140 #define __SEH_FALSE __builtin_expect(__SEH_ZERO, 0)
141 #define __SEH_TRUE __builtin_expect(!__SEH_ZERO, 1)
142
143 #define __SEH_FORCE_NEST \
144 __asm__ __volatile__("#%0" : : "r" (&_SEHFrame))
145
146 #define __SEH_NESTED_PROLOG \
147 __SEH_FORCE_NEST;
148
149 #define __SEH_DECLARE_EXCEPT_PFN(NAME_) int (__cdecl * NAME_)(void *)
150 #define __SEH_DECLARE_EXCEPT(NAME_) int __cdecl NAME_(void *)
151 #define __SEH_DEFINE_EXCEPT(NAME_) int __cdecl NAME_(void * _SEHExceptionPointers)
152
153 #define __SEH_DECLARE_FINALLY_PFN(NAME_) void (__cdecl * NAME_)(void)
154 #define __SEH_DECLARE_FINALLY(NAME_) void __cdecl NAME_(void)
155 #define __SEH_DEFINE_FINALLY(NAME_) void __cdecl NAME_(void)
156
157 #define __SEH_RETURN_EXCEPT(R_) return (int)(R_)
158 #define __SEH_RETURN_FINALLY() return
159
160 #define __SEH_BEGIN_TRY \
161 { \
162 __label__ _SEHBeginTry; \
163 __label__ _SEHEndTry; \
164 \
165 __SEH_USE_LABEL(_SEHBeginTry); \
166 __SEH_USE_LABEL(_SEHEndTry); \
167 \
168 _SEHBeginTry: __SEH_SIDE_EFFECT; \
169 { \
170 __SEH_BARRIER;
171
172 #define __SEH_END_TRY \
173 __SEH_BARRIER; \
174 } \
175 _SEHEndTry: __SEH_SIDE_EFFECT; \
176 }
177
178 #define __SEH_SET_TRYLEVEL(TRYLEVEL_) \
179 { \
180 __SEH_BARRIER; _SEH2FrameP->SF_TopTryLevel = (TRYLEVEL_); __SEH_BARRIER; \
181 }
182
183 #define __SEH_ENTER_TRYLEVEL() __SEH_SET_TRYLEVEL(&_SEHTryLevel)
184 #define __SEH_LEAVE_TRYLEVEL() __SEH_SET_TRYLEVEL(_SEHPrevTryLevelP)
185
186 #define __SEH_END_SCOPE_CHAIN \
187 static const int _SEH2ScopeKind = 1; \
188 static _SEH2Frame_t * const _SEH2FrameP = 0; \
189 static _SEH2TryLevel_t * const _SEH2TryLevelP = 0;
190
191 #define __SEH_BEGIN_SCOPE \
192 for(;;) \
193 { \
194 __label__ _SEHBeginScope; \
195 __label__ _SEHEndScope; \
196 \
197 _SEHBeginScope: __SEH_SIDE_EFFECT; \
198 \
199 const int _SEHTopTryLevel = (_SEH2ScopeKind != 0); \
200 _SEH2Frame_t * const _SEHCurFrameP = _SEH2FrameP; \
201 volatile _SEH2TryLevel_t * const _SEHPrevTryLevelP = _SEH2TryLevelP; \
202 \
203 (void)_SEHTopTryLevel; \
204 (void)_SEHCurFrameP; \
205 (void)_SEHPrevTryLevelP; \
206 \
207 __SEH_USE_LABEL(_SEHBeginScope); \
208 __SEH_USE_LABEL(_SEHEndScope); \
209 \
210 { \
211 __label__ _SEHBeforeTry; \
212 __label__ _SEHDoTry; \
213 __label__ _SEHAfterTry; \
214 static const int _SEH2ScopeKind = 0; \
215 _SEH2Frame_t _SEHFrame; \
216 volatile _SEH2TryLevel_t _SEHTryLevel; \
217 _SEH2Frame_t * const _SEH2FrameP = _SEHTopTryLevel ? &_SEHFrame : _SEHCurFrameP; \
218 volatile _SEH2TryLevel_t * const _SEH2TryLevelP = &_SEHTryLevel; \
219 \
220 (void)_SEH2ScopeKind; \
221 (void)_SEHFrame; \
222 (void)_SEHTryLevel; \
223 (void)_SEH2FrameP; \
224 (void)_SEH2TryLevelP; \
225 \
226 _SEHTryLevel.ST_Next = _SEHPrevTryLevelP; \
227 goto _SEHBeforeTry; \
228 \
229 _SEHDoTry:; \
230 __SEH_ENTER_TRYLEVEL(); \
231 \
232 if(_SEHTopTryLevel) \
233 { \
234 __SEH_BARRIER; __asm__ __volatile__("mov %%ebp, %0\n#%1" : "=m" (_SEHFrame.SF_FramePointer) : "r" (__builtin_frame_address(0))); __SEH_BARRIER; \
235 _SEH2EnterFrame(&_SEHFrame); \
236 } \
237
238 #define __SEH_END_SCOPE \
239 } \
240 \
241 _SEHEndScope: __SEH_SIDE_EFFECT; \
242 \
243 break; \
244 }
245
246 #define __SEH_SCOPE_LOCALS \
247 __label__ _SEHBeginExcept; \
248 __label__ _SEHEndExcept; \
249 \
250 auto __SEH_DECLARE_EXCEPT(_SEHExcept); \
251 auto __SEH_DECLARE_FINALLY(_SEHFinally);
252
253 #define _SEH2_TRY \
254 __SEH_BEGIN_SCOPE \
255 { \
256 __SEH_SCOPE_LOCALS; \
257 \
258 __SEH_BEGIN_TRY \
259 {
260
261 #define _SEH2_FINALLY \
262 } \
263 __SEH_END_TRY; \
264 \
265 goto _SEHAfterTry; \
266 _SEHBeforeTry:; \
267 \
268 __SEH_PRETEND_USE_LABEL(_SEHBeginExcept); \
269 __SEH_PRETEND_USE_LABEL(_SEHEndExcept); \
270 \
271 __SEH_USE_NESTED_FUNCTION(_SEHFinally); \
272 \
273 _SEHTryLevel.ST_FramePointer = _SEHClosureFromTrampoline((_SEHTrampoline_t *)&_SEHFinally); \
274 _SEHTryLevel.ST_Filter = 0; \
275 _SEHTryLevel.ST_Body = _SEHFunctionFromTrampoline((_SEHTrampoline_t *)&_SEHFinally); \
276 \
277 goto _SEHDoTry; \
278 _SEHAfterTry:; \
279 \
280 if(_SEHTopTryLevel) \
281 _SEH2LeaveFrame(); \
282 else \
283 { \
284 __SEH_LEAVE_TRYLEVEL(); \
285 } \
286 \
287 _SEHFinally(); \
288 goto _SEHEndExcept; \
289 \
290 _SEHBeginExcept: __SEH_PRETEND_SIDE_EFFECT; \
291 __attribute__((unused)) __SEH_DEFINE_EXCEPT(_SEHExcept) { __SEH_RETURN_EXCEPT(0); } \
292 \
293 __attribute__((noinline)) __attribute__((used)) __SEH_DEFINE_FINALLY(_SEHFinally) \
294 { \
295 __SEH_END_SCOPE_CHAIN; \
296 \
297 (void)_SEH2ScopeKind; \
298 (void)_SEH2FrameP; \
299 (void)_SEH2TryLevelP; \
300 \
301 __SEH_NESTED_PROLOG; \
302 \
303 for(;; ({ __SEH_RETURN_FINALLY(); })) \
304 {
305
306 #define _SEH2_EXCEPT(E_) \
307 } \
308 __SEH_END_TRY; \
309 \
310 goto _SEHAfterTry; \
311 \
312 _SEHBeforeTry:; \
313 \
314 __SEH_USE_LABEL(_SEHBeginExcept); \
315 __SEH_USE_LABEL(_SEHEndExcept); \
316 \
317 __SEH_USE_NESTED_FUNCTION(_SEHExcept); \
318 \
319 _SEHTryLevel.ST_FramePointer = _SEHClosureFromTrampoline((_SEHTrampoline_t *)&_SEHExcept); \
320 _SEHTryLevel.ST_Filter = _SEHFunctionFromTrampoline((_SEHTrampoline_t *)&_SEHExcept); \
321 _SEHTryLevel.ST_Body = &&_SEHBeginExcept; \
322 __SEH_BARRIER; __asm__ __volatile__("mov %%esp, %0" : "=m" (_SEH2FrameP->SF_StackPointer)); __SEH_BARRIER; \
323 \
324 goto _SEHDoTry; \
325 \
326 __attribute__((noinline)) __attribute__((used)) __SEH_DEFINE_EXCEPT(_SEHExcept) \
327 { \
328 __SEH_NESTED_PROLOG; \
329 __SEH_RETURN_EXCEPT(E_); \
330 } \
331 \
332 __attribute__((unused)) __SEH_DEFINE_FINALLY(_SEHFinally) { __SEH_RETURN_FINALLY(); } \
333 \
334 _SEHAfterTry:; \
335 if(_SEHTopTryLevel) \
336 _SEH2LeaveFrame(); \
337 else \
338 { \
339 __SEH_LEAVE_TRYLEVEL(); \
340 } \
341 \
342 if(__SEH_FALSE) \
343 goto _SEHBeginExcept; \
344 else \
345 goto _SEHEndExcept; \
346 \
347 _SEHBeginExcept: __SEH_SIDE_EFFECT; \
348 { \
349 { \
350 _SEH2Frame_t * const _SEH2FrameP = _SEHTopTryLevel ? &_SEHFrame : _SEHCurFrameP; \
351 (void)_SEH2FrameP; \
352 __SEH_BARRIER;
353
354 #define _SEH2_END \
355 __SEH_BARRIER; \
356 } \
357 } \
358 _SEHEndExcept: __SEH_SIDE_EFFECT; \
359 } \
360 __SEH_END_SCOPE;
361
362 #define _SEH2_GetExceptionInformation() ((struct _EXCEPTION_POINTERS *)_SEHExceptionPointers)
363 #define _SEH2_GetExceptionCode() ((_SEH2FrameP)->SF_Code)
364 #define _SEH2_AbnormalTermination() (!!_SEH2_GetExceptionCode())
365
366 #define _SEH2_YIELD(STMT_) \
367 for(;;) \
368 { \
369 if(!_SEH2ScopeKind) \
370 _SEH2Return(); \
371 \
372 STMT_; \
373 }
374
375 #define _SEH2_LEAVE goto _SEHEndTry
376
377 __SEH_END_SCOPE_CHAIN;
378
379 #else
380
381 #include <excpt.h>
382
383 #define _SEH2_TRY __try
384 #define _SEH2_FINALLY __finally
385 #define _SEH2_EXCEPT(E_) __except((E_))
386 #define _SEH2_END
387
388 #define _SEH2_GetExceptionInformation() (GetExceptionInformation())
389 #define _SEH2_GetExceptionCode() (GetExceptionCode())
390 #define _SEH2_AbnormalTermination() (AbnormalTermination())
391
392 #define _SEH2_YIELD(STMT_) STMT_
393 #define _SEH2_LEAVE __leave
394
395 #endif
396
397 #endif
398
399 #endif
400 /* EOF */