| /* | |
| Copyright (c) 2008 KJK::Hyperion | |
| Permission is hereby granted, free of charge, to any person obtaining a | |
| copy of this software and associated documentation files (the "Software"), | |
| to deal in the Software without restriction, including without limitation | |
| the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| and/or sell copies of the Software, and to permit persons to whom the | |
| Software is furnished to do so, subject to the following conditions: | |
| The above copyright notice and this permission notice shall be included in | |
| all copies or substantial portions of the Software. | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| DEALINGS IN THE SOFTWARE. | |
| */ | |
| #ifndef KJK_PSEH2_H_ | |
| #define KJK_PSEH2_H_ | |
| #if !defined (__arm__) | |
| #include <pseh/pseh2-common.h> | |
| #if defined(__GNUC__) | |
| /* A no-op side effect that scares GCC */ | |
| #define __SEH_SIDE_EFFECT __asm__ __volatile__("#") | |
| /* A no-op without any real side effects, but silences warnings */ | |
| #define __SEH_PRETEND_SIDE_EFFECT (void)0 | |
| /* Forces GCC to consider the specified label reachable */ | |
| #define __SEH_USE_LABEL(L_) if(__SEH_VOLATILE_FALSE) goto L_; | |
| /* Makes GCC pretend the specified label is reachable, to silence warnings */ | |
| #define __SEH_PRETEND_USE_LABEL(L_) (void)(&&L_) | |
| /* Soft memory barrier */ | |
| #define __SEH_BARRIER __asm__ __volatile__("#":::"memory") | |
| /* GCC doesn't know that this equals zero */ | |
| #define __SEH_VOLATILE_ZERO ({ int zero = 0; __asm__ __volatile__("#" : "+g" (zero)); zero; }) | |
| #define __SEH_VOLATILE_FALSE __builtin_expect(__SEH_VOLATILE_ZERO, 0) | |
| #define __SEH_VOLATILE_TRUE __builtin_expect(!__SEH_VOLATILE_ZERO, 1) | |
| #define ___SEH_STRINGIFY(X_) # X_ | |
| #define __SEH_STRINGIFY(X_) ___SEH_STRINGIFY(X_) | |
| #define __SEH_EXCEPT_ARGS __attribute__((unused)) _SEH2Frame_t * _SEH2FrameP, __attribute__((unused)) struct _EXCEPTION_POINTERS * _SEHExceptionInformation | |
| #define __SEH_EXCEPT_ARGS_ , __SEH_EXCEPT_ARGS | |
| #define __SEH_EXCEPT_PFN __SEH_DECLARE_EXCEPT_PFN | |
| #define __SEH_DECLARE_EXCEPT_PFN(NAME_) __SEH_EXCEPT_RET (__cdecl * NAME_)(__SEH_EXCEPT_ARGS) | |
| #define __SEH_DECLARE_EXCEPT(NAME_) __SEH_EXCEPT_RET __cdecl NAME_(__SEH_EXCEPT_ARGS) | |
| #define __SEH_DEFINE_EXCEPT(NAME_) __SEH_EXCEPT_RET __cdecl NAME_(__SEH_EXCEPT_ARGS) | |
| #define __SEH_FINALLY_RET void | |
| #define __SEH_FINALLY_ARGS void | |
| #define __SEH_FINALLY_ARGS_ | |
| #define __SEH_FINALLY_PFN __SEH_DECLARE_FINALLY_PFN | |
| #define __SEH_DECLARE_FINALLY_PFN(NAME_) __SEH_FINALLY_RET (__cdecl * NAME_)(__SEH_FINALLY_ARGS) | |
| #define __SEH_DECLARE_FINALLY(NAME_) __SEH_FINALLY_RET __cdecl NAME_(__SEH_FINALLY_ARGS) | |
| #define __SEH_DEFINE_FINALLY(NAME_) __SEH_FINALLY_RET __cdecl NAME_(__SEH_FINALLY_ARGS) | |
| #define __SEH_RETURN_EXCEPT(R_) return (long)(R_) | |
| #define __SEH_RETURN_FINALLY() return | |
| #define __SEH_BEGIN_TRY \ | |
| { \ | |
| __label__ _SEHEndTry; \ | |
| \ | |
| __SEH_PRETEND_USE_LABEL(_SEHEndTry); \ | |
| \ | |
| { \ | |
| __SEH_BARRIER; | |
| #define __SEH_END_TRY \ | |
| __SEH_BARRIER; \ | |
| } \ | |
| _SEHEndTry:; \ | |
| } | |
| #define __SEH_SET_TRYLEVEL(TRYLEVEL_) \ | |
| { \ | |
| __SEH_BARRIER; _SEH2FrameP->SF_TopTryLevel = (TRYLEVEL_); __SEH_BARRIER; \ | |
| } | |
| #define __SEH_ENTER_FRAME_AND_TRYLEVEL(TRYLEVEL_) (_SEH2EnterFrameAndTrylevel(_SEH2FrameP, (TRYLEVEL_))) | |
| #define __SEH_ENTER_TRYLEVEL(TRYLEVEL_) ((__SEH_SET_TRYLEVEL((TRYLEVEL_))), 0) | |
| #define __SEH_ENTER_FRAME_AND_HANDLE_TRYLEVEL(TRYLEVEL_, HANDLE_) _SEH2EnterFrameAndHandleTrylevel(_SEH2FrameP, (TRYLEVEL_), (HANDLE_)) | |
| #define __SEH_ENTER_HANDLE_TRYLEVEL(TRYLEVEL_, HANDLE_) _SEH2EnterHandleTrylevel(_SEH2FrameP, (TRYLEVEL_), (HANDLE_)) | |
| #define __SEH_ENTER_SCOPE(TRYLEVEL_) (_SEHTopTryLevel ? __SEH_ENTER_FRAME_AND_TRYLEVEL(TRYLEVEL_) : __SEH_ENTER_TRYLEVEL(TRYLEVEL_)) | |
| #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_)))) | |
| #define __SEH_LEAVE_TRYLEVEL() \ | |
| if(!_SEHTopTryLevel) \ | |
| { \ | |
| __SEH_SET_TRYLEVEL(_SEHPrevTryLevelP); \ | |
| } \ | |
| #define __SEH_LEAVE_FRAME() \ | |
| if(_SEHTopTryLevel) \ | |
| { \ | |
| _SEH2LeaveFrame(); \ | |
| __asm__ __volatile__("mov %0, %%esp" : : "g" (_SEHStackPointer)); \ | |
| } | |
| #define __SEH_END_SCOPE_CHAIN \ | |
| static __attribute__((unused)) const int _SEH2ScopeKind = 1; \ | |
| static __attribute__((unused)) _SEH2Frame_t * const _SEH2FrameP = 0; \ | |
| static __attribute__((unused)) _SEH2TryLevel_t * const _SEH2TryLevelP = 0; | |
| #define __SEH_BEGIN_SCOPE \ | |
| for(;;) \ | |
| { \ | |
| const int _SEHTopTryLevel = (_SEH2ScopeKind != 0); \ | |
| _SEH2Frame_t * const _SEHCurFrameP = _SEH2FrameP; \ | |
| volatile _SEH2TryLevel_t * const _SEHPrevTryLevelP = _SEH2TryLevelP; \ | |
| __attribute__((unused)) int _SEHAbnormalTermination; \ | |
| \ | |
| (void)_SEHTopTryLevel; \ | |
| (void)_SEHCurFrameP; \ | |
| (void)_SEHPrevTryLevelP; \ | |
| \ | |
| { \ | |
| __label__ _SEHBeforeTry; \ | |
| __label__ _SEHDoTry; \ | |
| __label__ _SEHAfterTry; \ | |
| static const int _SEH2ScopeKind = 0; \ | |
| volatile _SEH2TryLevel_t _SEHTryLevel; \ | |
| volatile _SEH2HandleTryLevel_t _SEHHandleTryLevel; \ | |
| void * _SEHStackPointer; \ | |
| volatile _SEH2TryLevel_t * _SEH2TryLevelP; \ | |
| _SEH2Frame_t * const _SEH2FrameP = _SEHTopTryLevel ? \ | |
| ({ __asm__ __volatile__("mov %%esp, %0" : "=g" (_SEHStackPointer)); __builtin_alloca(sizeof(_SEH2Frame_t)); }) : \ | |
| _SEHCurFrameP; \ | |
| \ | |
| (void)_SEH2ScopeKind; \ | |
| (void)_SEHTryLevel; \ | |
| (void)_SEHHandleTryLevel; \ | |
| (void)_SEHStackPointer; \ | |
| (void)_SEH2FrameP; \ | |
| (void)_SEH2TryLevelP; \ | |
| \ | |
| goto _SEHBeforeTry; \ | |
| \ | |
| _SEHDoTry:; | |
| #define __SEH_END_SCOPE \ | |
| } \ | |
| \ | |
| break; \ | |
| } | |
| #define __SEH_SCOPE_LOCALS \ | |
| __label__ _SEHBeginExcept; \ | |
| __label__ _SEHEndExcept; \ | |
| \ | |
| auto __SEH_DECLARE_FINALLY(_SEHFinally); | |
| #define _SEH2_TRY \ | |
| __SEH_BEGIN_SCOPE \ | |
| { \ | |
| __SEH_SCOPE_LOCALS; \ | |
| \ | |
| __SEH_BEGIN_TRY \ | |
| { | |
| #define _SEH2_FINALLY \ | |
| } \ | |
| __SEH_END_TRY; \ | |
| \ | |
| goto _SEHAfterTry; \ | |
| _SEHBeforeTry:; \ | |
| \ | |
| __SEH_PRETEND_USE_LABEL(_SEHBeginExcept); \ | |
| __SEH_PRETEND_USE_LABEL(_SEHEndExcept); \ | |
| \ | |
| _SEHTryLevel.ST_Filter = 0; \ | |
| _SEHTryLevel.ST_Body = &_SEHFinally; \ | |
| _SEHTryLevel.ST_Next = _SEHPrevTryLevelP; \ | |
| __SEH_ENTER_SCOPE(&_SEHTryLevel); \ | |
| _SEH2TryLevelP = &_SEHTryLevel; \ | |
| \ | |
| _SEHAbnormalTermination = 1; \ | |
| \ | |
| goto _SEHDoTry; \ | |
| _SEHAfterTry:; \ | |
| \ | |
| _SEHAbnormalTermination = 0; \ | |
| \ | |
| __SEH_LEAVE_TRYLEVEL(); \ | |
| \ | |
| _SEHFinally(); \ | |
| goto _SEHEndExcept; \ | |
| \ | |
| _SEHBeginExcept:; \ | |
| \ | |
| __attribute__((noinline)) __SEH_DEFINE_FINALLY(_SEHFinally) \ | |
| { \ | |
| __SEH_END_SCOPE_CHAIN \ | |
| \ | |
| (void)_SEH2ScopeKind; \ | |
| (void)_SEH2FrameP; \ | |
| (void)_SEH2TryLevelP; \ | |
| \ | |
| for(;; ({ __SEH_RETURN_FINALLY(); })) \ | |
| { | |
| #define _SEH2_EXCEPT(FILTER_...) \ | |
| } \ | |
| __SEH_END_TRY; \ | |
| \ | |
| goto _SEHAfterTry; \ | |
| \ | |
| _SEHBeforeTry:; \ | |
| \ | |
| { \ | |
| __attribute__((unused)) struct _EXCEPTION_POINTERS * volatile _SEHExceptionInformation; \ | |
| \ | |
| if(__builtin_constant_p((FILTER_)) && (FILTER_) <= 0) \ | |
| { \ | |
| if((FILTER_) < 0) \ | |
| { \ | |
| _SEHTryLevel.ST_Filter = (void *)-1; \ | |
| _SEHTryLevel.ST_Body = 0; \ | |
| } \ | |
| else \ | |
| { \ | |
| _SEHTryLevel.ST_Filter = (void *)0; \ | |
| _SEHTryLevel.ST_Body = 0; \ | |
| } \ | |
| \ | |
| _SEHTryLevel.ST_Next = _SEHPrevTryLevelP; \ | |
| __SEH_ENTER_SCOPE(&_SEHTryLevel); \ | |
| _SEH2TryLevelP = &_SEHTryLevel; \ | |
| } \ | |
| else \ | |
| { \ | |
| if(__builtin_constant_p((FILTER_)) && (FILTER_) > 0) \ | |
| _SEHHandleTryLevel.SHT_Common.ST_Filter = (void *)1; \ | |
| else \ | |
| { \ | |
| __SEH_DEFINE_EXCEPT(_SEHExcept) \ | |
| { \ | |
| __SEH_RETURN_EXCEPT((FILTER_)); \ | |
| } \ | |
| \ | |
| _SEHHandleTryLevel.SHT_Common.ST_Filter = &_SEHExcept; \ | |
| } \ | |
| \ | |
| _SEHHandleTryLevel.SHT_Common.ST_Next = _SEHPrevTryLevelP; \ | |
| _SEH2TryLevelP = &_SEHHandleTryLevel.SHT_Common; \ | |
| \ | |
| if(__builtin_expect(__SEH_ENTER_HANDLE_SCOPE(&_SEHHandleTryLevel, &&_SEHBeginExcept), 0)) \ | |
| goto _SEHBeginExcept; \ | |
| } \ | |
| } \ | |
| \ | |
| goto _SEHDoTry; \ | |
| \ | |
| __attribute__((unused)) __SEH_DEFINE_FINALLY(_SEHFinally) { __SEH_RETURN_FINALLY(); } \ | |
| \ | |
| _SEHAfterTry:; \ | |
| __SEH_LEAVE_TRYLEVEL(); \ | |
| \ | |
| goto _SEHEndExcept; \ | |
| \ | |
| _SEHBeginExcept:; \ | |
| { \ | |
| { \ | |
| __SEH_BARRIER; | |
| #define _SEH2_END \ | |
| __SEH_BARRIER; \ | |
| } \ | |
| } \ | |
| \ | |
| _SEHEndExcept:; \ | |
| \ | |
| __SEH_LEAVE_FRAME(); \ | |
| } \ | |
| __SEH_END_SCOPE; | |
| #define _SEH2_GetExceptionInformation() (_SEHExceptionInformation) | |
| #define _SEH2_GetExceptionCode() ((_SEH2FrameP)->SF_Code) | |
| #define _SEH2_AbnormalTermination() (_SEHAbnormalTermination) | |
| #define _SEH2_YIELD(STMT_) \ | |
| for(;;) \ | |
| { \ | |
| if(!_SEH2ScopeKind) \ | |
| _SEH2Return(); \ | |
| \ | |
| STMT_; \ | |
| } | |
| #define _SEH2_LEAVE goto _SEHEndTry | |
| __SEH_END_SCOPE_CHAIN | |
| #else | |
| #include <excpt.h> | |
| #define _SEH2_TRY __try { | |
| #define _SEH2_FINALLY } __finally { | |
| #define _SEH2_EXCEPT(...) } __except(__VA_ARGS__) { | |
| #define _SEH2_END } | |
| #define _SEH2_GetExceptionInformation() (GetExceptionInformation()) | |
| #define _SEH2_GetExceptionCode() (GetExceptionCode()) | |
| #define _SEH2_AbnormalTermination() (AbnormalTermination()) | |
| #define _SEH2_YIELD(STMT_) STMT_ | |
| #define _SEH2_LEAVE __leave | |
| #endif | |
| #else | |
| #define _SEH2_TRY { | |
| #define _SEH2_FINALLY } { | |
| #define _SEH2_EXCEPT(...) } if (0) { | |
| #define _SEH2_END } | |
| #define _SEH2_GetExceptionInformation() | |
| #define _SEH2_GetExceptionCode() STATUS_SUCCESS | |
| #define _SEH2_AbnormalTermination() | |
| #define _SEH2_YIELD(STMT_) STMT_ | |
| #define _SEH2_LEAVE | |
| #endif | |
| #endif | |
| /* EOF */ |