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