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