[PSEH3]
[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 #if defined(_USE_NATIVE_SEH) || defined(_MSC_VER)
27
28 #include <excpt.h>
29 #define _SEH2_TRY __try
30 #define _SEH2_FINALLY __finally
31 #define _SEH2_EXCEPT(...) __except(__VA_ARGS__)
32 #define _SEH2_END
33 #define _SEH2_GetExceptionInformation() (GetExceptionInformation())
34 #define _SEH2_GetExceptionCode() (GetExceptionCode())
35 #define _SEH2_AbnormalTermination() (AbnormalTermination())
36 #define _SEH2_YIELD(STMT_) STMT_
37 #define _SEH2_LEAVE __leave
38
39 #elif defined(_USE_DUMMY_PSEH) || defined (__arm__) || defined(__clang__) || defined(_M_AMD64)
40
41 #define _SEH2_TRY {
42 #define _SEH2_FINALLY } {
43 #define _SEH2_EXCEPT(...) } if (0) {
44 #define _SEH2_END }
45 #define _SEH2_GetExceptionInformation()
46 #define _SEH2_GetExceptionCode() 0
47 #define _SEH2_AbnormalTermination()
48 #define _SEH2_YIELD(STMT_) STMT_
49 #define _SEH2_LEAVE
50
51 #elif defined(_USE_PSEH3)
52
53 #include "pseh3.h"
54
55 /* Compatibility macros */
56 #define _SEH2_TRY _SEH3_TRY
57 #define _SEH2_EXCEPT _SEH3_EXCEPT
58 #define _SEH2_FINALLY _SEH3_FINALLY
59 #define _SEH2_END _SEH3_END
60 #define _SEH2_GetExceptionInformation() ((struct _EXCEPTION_POINTERS*)_exception_info())
61 #define _SEH2_GetExceptionCode _exception_code
62 #define _SEH2_AbnormalTermination _abnormal_termination
63 #define _SEH2_LEAVE _SEH3_LEAVE
64 #define _SEH2_YIELD(x) x
65
66 #elif defined(__GNUC__)
67
68 struct _EXCEPTION_RECORD;
69 struct _EXCEPTION_POINTERS;
70 struct _CONTEXT;
71
72 typedef int (__cdecl * _SEH2FrameHandler_t)
73 (
74 struct _EXCEPTION_RECORD *,
75 void *,
76 struct _CONTEXT *,
77 void *
78 );
79
80 typedef struct __SEH2Registration
81 {
82 struct __SEH2Registration * SER_Prev;
83 _SEH2FrameHandler_t SER_Handler;
84 }
85 _SEH2Registration_t;
86
87 typedef struct __SEH2Frame
88 {
89 _SEH2Registration_t SF_Registration;
90 volatile struct __SEH2TryLevel * volatile SF_TopTryLevel;
91 volatile unsigned long SF_Code;
92 }
93 _SEH2Frame_t;
94
95 typedef struct __SEH2TryLevel
96 {
97 volatile struct __SEH2TryLevel * ST_Next;
98 void * ST_Filter;
99 void * ST_Body;
100 }
101 _SEH2TryLevel_t;
102
103 typedef struct __SEH2HandleTryLevel
104 {
105 _SEH2TryLevel_t SHT_Common;
106 void * volatile SHT_Esp;
107 void * volatile SHT_Ebp;
108 void * volatile SHT_Ebx;
109 void * volatile SHT_Esi;
110 void * volatile SHT_Edi;
111 }
112 _SEH2HandleTryLevel_t;
113
114 #ifdef __cplusplus
115 extern "C" {
116 #endif
117
118 extern int __cdecl _SEH2EnterFrameAndTrylevel(_SEH2Frame_t *, volatile _SEH2TryLevel_t *);
119 extern __attribute__((returns_twice)) int __cdecl _SEH2EnterFrameAndHandleTrylevel(_SEH2Frame_t *, volatile _SEH2HandleTryLevel_t *, void *);
120 extern __attribute__((returns_twice)) int __cdecl _SEH2EnterHandleTrylevel(_SEH2Frame_t *, volatile _SEH2HandleTryLevel_t *, void *);
121 extern void __cdecl _SEH2LeaveFrame(void);
122 extern void __cdecl _SEH2Return(void);
123
124 #ifdef __cplusplus
125 }
126 #endif
127
128 /* Prevent gcc from inlining functions that use SEH. */
129 #if ((__GNUC__ >= 4) && (__GNUC_MINOR__ >= 7))
130 static inline __attribute__((always_inline)) __attribute__((returns_twice)) void _SEH_DontInline() {}
131 #define __PREVENT_GCC_FROM_INLINING_SEH_FUNCTIONS() _SEH_DontInline();
132 #else
133 #define __PREVENT_GCC_FROM_INLINING_SEH_FUNCTIONS()
134 #endif
135
136 /* A no-op side effect that scares GCC */
137 #define __SEH_SIDE_EFFECT __asm__ __volatile__("#")
138
139 /* A no-op without any real side effects, but silences warnings */
140 #define __SEH_PRETEND_SIDE_EFFECT (void)0
141
142 /* Forces GCC to consider the specified label reachable */
143 #define __SEH_USE_LABEL(L_) if(__SEH_VOLATILE_FALSE) goto L_;
144
145 /* Makes GCC pretend the specified label is reachable, to silence warnings */
146 #define __SEH_PRETEND_USE_LABEL(L_) (void)(&&L_)
147
148 /* Soft memory barrier */
149 #define __SEH_BARRIER __asm__ __volatile__("#":::"memory")
150
151 /* GCC doesn't know that this equals zero */
152 #define __SEH_VOLATILE_ZERO ({ int zero = 0; __asm__ __volatile__("#" : "+g" (zero)); zero; })
153
154 #define __SEH_VOLATILE_FALSE __builtin_expect(__SEH_VOLATILE_ZERO, 0)
155 #define __SEH_VOLATILE_TRUE __builtin_expect(!__SEH_VOLATILE_ZERO, 1)
156
157 #define ___SEH_STRINGIFY(X_) # X_
158 #define __SEH_STRINGIFY(X_) ___SEH_STRINGIFY(X_)
159
160 #define __SEH_EXCEPT_RET long
161 #define __SEH_EXCEPT_ARGS __attribute__((unused)) _SEH2Frame_t * _SEH2FrameP, __attribute__((unused)) struct _EXCEPTION_POINTERS * _SEHExceptionInformation
162 #define __SEH_EXCEPT_ARGS_ , __SEH_EXCEPT_ARGS
163 #define __SEH_EXCEPT_PFN __SEH_DECLARE_EXCEPT_PFN
164 #define __SEH_DECLARE_EXCEPT_PFN(NAME_) __SEH_EXCEPT_RET (__cdecl * NAME_)(__SEH_EXCEPT_ARGS)
165 #define __SEH_DECLARE_EXCEPT(NAME_) __SEH_EXCEPT_RET __cdecl NAME_(__SEH_EXCEPT_ARGS)
166 #define __SEH_DEFINE_EXCEPT(NAME_) __SEH_EXCEPT_RET __cdecl NAME_(__SEH_EXCEPT_ARGS)
167
168 #define __SEH_FINALLY_RET void
169 #define __SEH_FINALLY_ARGS void
170 #define __SEH_FINALLY_ARGS_
171 #define __SEH_FINALLY_PFN __SEH_DECLARE_FINALLY_PFN
172 #define __SEH_DECLARE_FINALLY_PFN(NAME_) __SEH_FINALLY_RET (__cdecl * NAME_)(__SEH_FINALLY_ARGS)
173 #define __SEH_DECLARE_FINALLY(NAME_) __SEH_FINALLY_RET __cdecl NAME_(__SEH_FINALLY_ARGS)
174 #define __SEH_DEFINE_FINALLY(NAME_) __SEH_FINALLY_RET __cdecl NAME_(__SEH_FINALLY_ARGS)
175
176 #define __SEH_RETURN_EXCEPT(R_) return (long)(R_)
177 #define __SEH_RETURN_FINALLY() return
178
179 #define __SEH_BEGIN_TRY \
180 { \
181 __label__ _SEHEndTry; \
182 \
183 __SEH_PRETEND_USE_LABEL(_SEHEndTry); \
184 \
185 { \
186 __SEH_BARRIER;
187
188 #define __SEH_END_TRY \
189 __SEH_BARRIER; \
190 } \
191 _SEHEndTry:; \
192 }
193
194 #define __SEH_SET_TRYLEVEL(TRYLEVEL_) \
195 { \
196 __SEH_BARRIER; _SEH2FrameP->SF_TopTryLevel = (TRYLEVEL_); __SEH_BARRIER; \
197 }
198
199 #define __SEH_ENTER_FRAME_AND_TRYLEVEL(TRYLEVEL_) (_SEH2EnterFrameAndTrylevel(_SEH2FrameP, (TRYLEVEL_)))
200 #define __SEH_ENTER_TRYLEVEL(TRYLEVEL_) ((__SEH_SET_TRYLEVEL((TRYLEVEL_))), 0)
201
202 #define __SEH_ENTER_FRAME_AND_HANDLE_TRYLEVEL(TRYLEVEL_, HANDLE_) _SEH2EnterFrameAndHandleTrylevel(_SEH2FrameP, (TRYLEVEL_), (HANDLE_))
203 #define __SEH_ENTER_HANDLE_TRYLEVEL(TRYLEVEL_, HANDLE_) _SEH2EnterHandleTrylevel(_SEH2FrameP, (TRYLEVEL_), (HANDLE_))
204
205 #define __SEH_ENTER_SCOPE(TRYLEVEL_) (_SEHTopTryLevel ? __SEH_ENTER_FRAME_AND_TRYLEVEL(TRYLEVEL_) : __SEH_ENTER_TRYLEVEL(TRYLEVEL_))
206 #define __SEH_ENTER_HANDLE_SCOPE(TRYLEVEL_, HANDLE_) (({ __SEH_BARRIER; __asm__ __volatile__("mov %%esp, %0" : "=m" ((TRYLEVEL_)->SHT_Esp)); __SEH_BARRIER; }), (_SEHTopTryLevel ? __SEH_ENTER_FRAME_AND_HANDLE_TRYLEVEL((TRYLEVEL_), (HANDLE_)) : __SEH_ENTER_HANDLE_TRYLEVEL((TRYLEVEL_), (HANDLE_))))
207
208 #define __SEH_LEAVE_TRYLEVEL() \
209 if(!_SEHTopTryLevel) \
210 { \
211 __SEH_SET_TRYLEVEL(_SEHPrevTryLevelP); \
212 } \
213
214 #define __SEH_LEAVE_FRAME() \
215 if(_SEHTopTryLevel) \
216 { \
217 _SEH2LeaveFrame(); \
218 }
219
220 #define __SEH_END_SCOPE_CHAIN \
221 static __attribute__((unused)) const int _SEH2ScopeKind = 1; \
222 static __attribute__((unused)) _SEH2Frame_t * const _SEH2FrameP = 0; \
223 static __attribute__((unused)) _SEH2TryLevel_t * const _SEH2TryLevelP = 0;
224
225 #define __SEH_BEGIN_SCOPE \
226 for(;;) \
227 { \
228 const int _SEHTopTryLevel = (_SEH2ScopeKind != 0); \
229 _SEH2Frame_t * const _SEHCurFrameP = _SEH2FrameP; \
230 volatile _SEH2TryLevel_t * const _SEHPrevTryLevelP = _SEH2TryLevelP; \
231 __attribute__((unused)) int _SEHAbnormalTermination; \
232 \
233 (void)_SEHTopTryLevel; \
234 (void)_SEHCurFrameP; \
235 (void)_SEHPrevTryLevelP; \
236 \
237 { \
238 __label__ _SEHBeforeTry; \
239 __label__ _SEHDoTry; \
240 __label__ _SEHAfterTry; \
241 static const int _SEH2ScopeKind = 0; \
242 volatile _SEH2TryLevel_t _SEHTryLevel; \
243 volatile _SEH2HandleTryLevel_t _SEHHandleTryLevel; \
244 _SEH2Frame_t _SEH2Frame[_SEHTopTryLevel ? 1 : 0]; \
245 volatile _SEH2TryLevel_t * _SEH2TryLevelP; \
246 _SEH2Frame_t * const _SEH2FrameP = _SEHTopTryLevel ? \
247 _SEH2Frame : _SEHCurFrameP; \
248 \
249 (void)_SEH2ScopeKind; \
250 (void)_SEHTryLevel; \
251 (void)_SEHHandleTryLevel; \
252 (void)_SEH2FrameP; \
253 (void)_SEH2TryLevelP; \
254 \
255 goto _SEHBeforeTry; \
256 \
257 _SEHDoTry:;
258
259 #define __SEH_END_SCOPE \
260 } \
261 \
262 break; \
263 }
264
265 #define __SEH_SCOPE_LOCALS \
266 __label__ _SEHBeginExcept; \
267 __label__ _SEHEndExcept; \
268 \
269 auto __SEH_DECLARE_FINALLY(_SEHFinally);
270
271 #define _SEH2_TRY \
272 __PREVENT_GCC_FROM_INLINING_SEH_FUNCTIONS() \
273 __SEH_BEGIN_SCOPE \
274 { \
275 __SEH_SCOPE_LOCALS; \
276 \
277 __SEH_BEGIN_TRY \
278 {
279
280 #define _SEH2_FINALLY \
281 } \
282 __SEH_END_TRY; \
283 \
284 goto _SEHAfterTry; \
285 _SEHBeforeTry:; \
286 \
287 __SEH_PRETEND_USE_LABEL(_SEHBeginExcept); \
288 __SEH_PRETEND_USE_LABEL(_SEHEndExcept); \
289 \
290 _SEHTryLevel.ST_Filter = 0; \
291 _SEHTryLevel.ST_Body = &_SEHFinally; \
292 _SEHTryLevel.ST_Next = _SEHPrevTryLevelP; \
293 __SEH_ENTER_SCOPE(&_SEHTryLevel); \
294 _SEH2TryLevelP = &_SEHTryLevel; \
295 \
296 _SEHAbnormalTermination = 1; \
297 \
298 goto _SEHDoTry; \
299 _SEHAfterTry:; \
300 \
301 _SEHAbnormalTermination = 0; \
302 \
303 __SEH_LEAVE_TRYLEVEL(); \
304 \
305 _SEHFinally(); \
306 goto _SEHEndExcept; \
307 \
308 _SEHBeginExcept:; \
309 \
310 __attribute__((noinline)) __SEH_DEFINE_FINALLY(_SEHFinally) \
311 { \
312 __SEH_END_SCOPE_CHAIN; \
313 \
314 (void)_SEH2ScopeKind; \
315 (void)_SEH2FrameP; \
316 (void)_SEH2TryLevelP; \
317 \
318 for(;; ({ __SEH_RETURN_FINALLY(); })) \
319 {
320
321 #define _SEH2_EXCEPT(...) \
322 } \
323 __SEH_END_TRY; \
324 \
325 goto _SEHAfterTry; \
326 \
327 _SEHBeforeTry:; \
328 \
329 { \
330 __attribute__((unused)) struct _EXCEPTION_POINTERS * volatile _SEHExceptionInformation; \
331 \
332 if(__builtin_constant_p((__VA_ARGS__)) && (__VA_ARGS__) <= 0) \
333 { \
334 if((__VA_ARGS__) < 0) \
335 { \
336 _SEHTryLevel.ST_Filter = (void *)-1; \
337 _SEHTryLevel.ST_Body = 0; \
338 } \
339 else \
340 { \
341 _SEHTryLevel.ST_Filter = (void *)0; \
342 _SEHTryLevel.ST_Body = 0; \
343 } \
344 \
345 _SEHTryLevel.ST_Next = _SEHPrevTryLevelP; \
346 __SEH_ENTER_SCOPE(&_SEHTryLevel); \
347 _SEH2TryLevelP = &_SEHTryLevel; \
348 } \
349 else \
350 { \
351 if(__builtin_constant_p((__VA_ARGS__)) && (__VA_ARGS__) > 0) \
352 _SEHHandleTryLevel.SHT_Common.ST_Filter = (void *)1; \
353 else \
354 { \
355 __SEH_DEFINE_EXCEPT(_SEHExcept) \
356 { \
357 __SEH_RETURN_EXCEPT((__VA_ARGS__)); \
358 } \
359 \
360 _SEHHandleTryLevel.SHT_Common.ST_Filter = &_SEHExcept; \
361 } \
362 \
363 _SEHHandleTryLevel.SHT_Common.ST_Next = _SEHPrevTryLevelP; \
364 _SEH2TryLevelP = &_SEHHandleTryLevel.SHT_Common; \
365 \
366 if(__builtin_expect(__SEH_ENTER_HANDLE_SCOPE(&_SEHHandleTryLevel, &&_SEHBeginExcept), 0)) \
367 goto _SEHBeginExcept; \
368 } \
369 } \
370 \
371 goto _SEHDoTry; \
372 \
373 __attribute__((unused)) __SEH_DEFINE_FINALLY(_SEHFinally) { __SEH_RETURN_FINALLY(); } \
374 \
375 _SEHAfterTry:; \
376 __SEH_LEAVE_TRYLEVEL(); \
377 \
378 goto _SEHEndExcept; \
379 \
380 _SEHBeginExcept:; \
381 { \
382 { \
383 __SEH_BARRIER;
384
385 #define _SEH2_END \
386 __SEH_BARRIER; \
387 } \
388 } \
389 \
390 _SEHEndExcept:; \
391 \
392 __SEH_LEAVE_FRAME(); \
393 } \
394 __SEH_END_SCOPE;
395
396 #define _SEH2_GetExceptionInformation() (_SEHExceptionInformation)
397 #define _SEH2_GetExceptionCode() ((_SEH2FrameP)->SF_Code)
398 #define _SEH2_AbnormalTermination() (_SEHAbnormalTermination)
399
400 #define _SEH2_YIELD(STMT_) \
401 for(;;) \
402 { \
403 if(!_SEH2ScopeKind) \
404 _SEH2Return(); \
405 \
406 STMT_; \
407 }
408
409 #define _SEH2_LEAVE goto _SEHEndTry
410
411 __SEH_END_SCOPE_CHAIN;
412
413
414 #else
415 #error no PSEH support
416 #endif
417
418 #endif /* !KJK_PSEH2_H_ */
419
420 /* EOF */