Sync to trunk r38200
[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 struct _EXCEPTION_POINTERS * volatile SF_ExceptionInformation;
53 volatile unsigned long SF_Code;
54 }
55 _SEH2Frame_t;
56
57 typedef struct __SEH2TryLevel
58 {
59 volatile struct __SEH2TryLevel * ST_Next;
60 void * ST_Filter;
61 void * ST_Body;
62 void * volatile ST_Ebp;
63 void * volatile ST_Esp;
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_) if(__SEH_VOLATILE_FALSE) goto 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 /* Soft memory barrier */
132 #define __SEH_BARRIER __asm__ __volatile__("#":::"memory")
133
134 /* GCC doesn't know that this equals zero */
135 #define __SEH_VOLATILE_ZERO ({ int zero = 0; __asm__ __volatile__("#" : "+g" (zero)); zero; })
136
137 /* GCC believes this is setjmp */
138 #define __SEH_PRETEND_SETJMP() (_SEH2PretendSetjmp(), 0)
139
140 #define __SEH_VOLATILE_FALSE __builtin_expect(__SEH_VOLATILE_ZERO, 0)
141 #define __SEH_VOLATILE_TRUE __builtin_expect(!__SEH_VOLATILE_ZERO, 1)
142
143 #define ___SEH_STRINGIFY(X_) # X_
144 #define __SEH_STRINGIFY(X_) ___SEH_STRINGIFY(X_)
145
146 static
147 __inline__
148 __attribute__((returns_twice))
149 __attribute__((always_inline))
150 void _SEH2PretendSetjmp(void)
151 {
152 }
153
154 #define __SEH_FORCE_NEST \
155 __asm__ __volatile__("#%0" : : "r" (&_SEHFrame))
156
157 #define __SEH_DECLARE_EXCEPT_PFN(NAME_) int (__cdecl * NAME_)(void)
158 #define __SEH_DECLARE_EXCEPT(NAME_) int __cdecl NAME_(void)
159 #define __SEH_DEFINE_EXCEPT(NAME_) int __cdecl NAME_(void)
160
161 #define __SEH_DECLARE_FINALLY_PFN(NAME_) void (__cdecl * NAME_)(void)
162 #define __SEH_DECLARE_FINALLY(NAME_) void __cdecl NAME_(void)
163 #define __SEH_DEFINE_FINALLY(NAME_) void __cdecl NAME_(void)
164
165 #define __SEH_RETURN_EXCEPT(R_) return (int)(R_)
166 #define __SEH_RETURN_FINALLY() return
167
168 #define __SEH_BEGIN_TRY \
169 if(!__SEH_PRETEND_SETJMP()) \
170 { \
171 __label__ _SEHEndTry; \
172 \
173 __SEH_PRETEND_USE_LABEL(_SEHEndTry); \
174 \
175 { \
176 __SEH_BARRIER;
177
178 #define __SEH_END_TRY \
179 __SEH_BARRIER; \
180 } \
181 _SEHEndTry:; \
182 }
183
184 #define __SEH_SET_TRYLEVEL(TRYLEVEL_) \
185 { \
186 __SEH_BARRIER; _SEH2FrameP->SF_TopTryLevel = (TRYLEVEL_); __SEH_BARRIER; \
187 }
188
189 #define __SEH_ENTER_TRYLEVEL() __SEH_SET_TRYLEVEL(&_SEHTryLevel)
190 #define __SEH_LEAVE_TRYLEVEL() __SEH_SET_TRYLEVEL(_SEHPrevTryLevelP)
191
192 #define __SEH_END_SCOPE_CHAIN \
193 static const int _SEH2ScopeKind = 1; \
194 static _SEH2Frame_t * const _SEH2FrameP = 0; \
195 static _SEH2TryLevel_t * const _SEH2TryLevelP = 0;
196
197 #define __SEH_BEGIN_SCOPE \
198 for(;;) \
199 { \
200 const int _SEHTopTryLevel = (_SEH2ScopeKind != 0); \
201 _SEH2Frame_t * const _SEHCurFrameP = _SEH2FrameP; \
202 volatile _SEH2TryLevel_t * const _SEHPrevTryLevelP = _SEH2TryLevelP; \
203 __attribute__((unused)) int _SEHAbnormalTermination; \
204 \
205 (void)_SEHTopTryLevel; \
206 (void)_SEHCurFrameP; \
207 (void)_SEHPrevTryLevelP; \
208 \
209 { \
210 __label__ _SEHBeforeTry; \
211 __label__ _SEHDoTry; \
212 __label__ _SEHAfterTry; \
213 static const int _SEH2ScopeKind = 0; \
214 _SEH2Frame_t _SEHFrame; \
215 volatile _SEH2TryLevel_t _SEHTryLevel; \
216 _SEH2Frame_t * const _SEH2FrameP = _SEHTopTryLevel ? &_SEHFrame : _SEHCurFrameP; \
217 volatile _SEH2TryLevel_t * const _SEH2TryLevelP = &_SEHTryLevel; \
218 \
219 (void)_SEH2ScopeKind; \
220 (void)_SEHFrame; \
221 (void)_SEHTryLevel; \
222 (void)_SEH2FrameP; \
223 (void)_SEH2TryLevelP; \
224 \
225 _SEHTryLevel.ST_Next = _SEHPrevTryLevelP; \
226 goto _SEHBeforeTry; \
227 \
228 _SEHDoTry:; \
229 __SEH_ENTER_TRYLEVEL(); \
230 \
231 if(_SEHTopTryLevel) \
232 _SEH2EnterFrame(&_SEHFrame); \
233
234 #define __SEH_END_SCOPE \
235 } \
236 \
237 break; \
238 }
239
240 #define __SEH_SCOPE_LOCALS \
241 __label__ _SEHBeginExcept; \
242 __label__ _SEHEndExcept; \
243 \
244 auto __SEH_DECLARE_FINALLY(_SEHFinally);
245
246 #define _SEH2_TRY \
247 __SEH_BEGIN_SCOPE \
248 { \
249 __SEH_SCOPE_LOCALS; \
250 \
251 __SEH_BEGIN_TRY \
252 {
253
254 #define _SEH2_FINALLY \
255 } \
256 __SEH_END_TRY; \
257 \
258 goto _SEHAfterTry; \
259 _SEHBeforeTry:; \
260 \
261 __SEH_PRETEND_USE_LABEL(_SEHBeginExcept); \
262 __SEH_PRETEND_USE_LABEL(_SEHEndExcept); \
263 \
264 _SEHTryLevel.ST_Filter = 0; \
265 _SEHTryLevel.ST_Body = &_SEHFinally; \
266 \
267 _SEHAbnormalTermination = 1; \
268 \
269 goto _SEHDoTry; \
270 _SEHAfterTry:; \
271 \
272 _SEHAbnormalTermination = 0; \
273 \
274 if(_SEHTopTryLevel) \
275 _SEH2LeaveFrame(); \
276 else \
277 { \
278 __SEH_LEAVE_TRYLEVEL(); \
279 } \
280 \
281 _SEHFinally(); \
282 goto _SEHEndExcept; \
283 \
284 _SEHBeginExcept:; \
285 \
286 __attribute__((noinline)) __SEH_DEFINE_FINALLY(_SEHFinally) \
287 { \
288 __SEH_END_SCOPE_CHAIN; \
289 \
290 (void)_SEH2ScopeKind; \
291 (void)_SEH2FrameP; \
292 (void)_SEH2TryLevelP; \
293 \
294 for(;; ({ __SEH_RETURN_FINALLY(); })) \
295 {
296
297 #define _SEH2_EXCEPT(...) \
298 } \
299 __SEH_END_TRY; \
300 \
301 goto _SEHAfterTry; \
302 \
303 _SEHBeforeTry:; \
304 \
305 if(__builtin_constant_p((__VA_ARGS__))) \
306 { \
307 if((__VA_ARGS__) > 0) \
308 { \
309 _SEHTryLevel.ST_Filter = (void *)1; \
310 _SEHTryLevel.ST_Body = &&_SEHBeginExcept; \
311 __SEH_USE_LABEL(_SEHBeginExcept); \
312 } \
313 else if((__VA_ARGS__) < 0) \
314 { \
315 _SEHTryLevel.ST_Filter = (void *)-1; \
316 _SEHTryLevel.ST_Body = NULL; \
317 } \
318 else \
319 { \
320 _SEHTryLevel.ST_Filter = (void *)0; \
321 _SEHTryLevel.ST_Body = NULL; \
322 } \
323 } \
324 else \
325 { \
326 __SEH_DEFINE_EXCEPT(_SEHExcept) \
327 { \
328 __SEH_RETURN_EXCEPT((__VA_ARGS__)); \
329 } \
330 \
331 _SEHTryLevel.ST_Filter = &_SEHExcept; \
332 _SEHTryLevel.ST_Body = &&_SEHBeginExcept; \
333 __SEH_USE_LABEL(_SEHBeginExcept); \
334 } \
335 \
336 __SEH_BARRIER; \
337 \
338 __asm__ __volatile__ \
339 ( \
340 "mov %%ebp, %0\n" \
341 "mov %%esp, %1" : \
342 "=m" (_SEHTryLevel.ST_Ebp), \
343 "=m" (_SEHTryLevel.ST_Esp) \
344 ); \
345 \
346 __SEH_BARRIER; \
347 \
348 goto _SEHDoTry; \
349 \
350 __attribute__((unused)) __SEH_DEFINE_FINALLY(_SEHFinally) { __SEH_RETURN_FINALLY(); } \
351 \
352 _SEHAfterTry:; \
353 if(_SEHTopTryLevel) \
354 _SEH2LeaveFrame(); \
355 else \
356 { \
357 __SEH_LEAVE_TRYLEVEL(); \
358 } \
359 \
360 goto _SEHEndExcept; \
361 \
362 _SEHBeginExcept:; \
363 { \
364 { \
365 _SEH2Frame_t * const _SEH2FrameP = _SEHTopTryLevel ? &_SEHFrame : _SEHCurFrameP; \
366 (void)_SEH2FrameP; \
367 __SEH_BARRIER;
368
369 #define _SEH2_END \
370 __SEH_BARRIER; \
371 } \
372 } \
373 \
374 _SEHEndExcept:; \
375 } \
376 __SEH_END_SCOPE;
377
378 #define _SEH2_GetExceptionInformation() ((_SEH2FrameP)->SF_ExceptionInformation)
379 #define _SEH2_GetExceptionCode() ((_SEH2FrameP)->SF_Code)
380 #define _SEH2_AbnormalTermination() (_SEHAbnormalTermination)
381
382 #define _SEH2_YIELD(STMT_) \
383 for(;;) \
384 { \
385 if(!_SEH2ScopeKind) \
386 _SEH2Return(); \
387 \
388 STMT_; \
389 }
390
391 #define _SEH2_LEAVE goto _SEHEndTry
392
393 __SEH_END_SCOPE_CHAIN;
394
395 #else
396
397 #include <excpt.h>
398
399 #define _SEH2_TRY __try
400 #define _SEH2_FINALLY __finally
401 #define _SEH2_EXCEPT(...) __except(__VA_ARGS__)
402 #define _SEH2_END
403
404 #define _SEH2_GetExceptionInformation() (GetExceptionInformation())
405 #define _SEH2_GetExceptionCode() (GetExceptionCode())
406 #define _SEH2_AbnormalTermination() (AbnormalTermination())
407
408 #define _SEH2_YIELD(STMT_) STMT_
409 #define _SEH2_LEAVE __leave
410
411 #endif
412
413 #endif
414
415 #endif
416 /* EOF */