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