2 Copyright (c) 2008 KJK::Hyperion
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:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
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.
30 struct _EXCEPTION_RECORD
;
31 struct _EXCEPTION_POINTERS
;
34 typedef int (__cdecl
* _SEHFrameHandler_t
)
36 struct _EXCEPTION_RECORD
*,
43 typedef struct __SEHTrampoline
45 unsigned char STR_MovEcx
;
46 unsigned char STR_Closure
[4];
47 unsigned char STR_Jmp
;
48 unsigned char STR_Function
[4];
54 __attribute__((always_inline
))
55 int _SEHIsTrampoline(_SEHTrampoline_t
* trampoline_
)
57 return trampoline_
->STR_MovEcx
== 0xb9 && trampoline_
->STR_Jmp
== 0xe9;
62 __attribute__((always_inline
))
63 void * _SEHFunctionFromTrampoline(_SEHTrampoline_t
* trampoline_
)
65 return (void *)(*(int *)(&trampoline_
->STR_Function
[0]) + (int)(trampoline_
+ 1));
70 __attribute__((always_inline
))
71 void * _SEHClosureFromTrampoline(_SEHTrampoline_t
* trampoline_
)
73 return (void *)*(int *)(&trampoline_
->STR_Closure
[0]);
79 /* A no-op side effect that scares GCC */
80 #define __SEH_SIDE_EFFECT __asm__ __volatile__("#")
82 /* A no-op without any real side effects, but silences warnings */
83 #define __SEH_PRETEND_SIDE_EFFECT (void)0
85 /* Forces GCC to consider the specified label reachable */
86 #define __SEH_USE_LABEL(L_) __asm__ __volatile__("# %0\n" : : "i" (&&L_))
88 /* Makes GCC pretend the specified label is reachable, to silence warnings */
89 #define __SEH_PRETEND_USE_LABEL(L_) (void)(&&L_)
91 /* Forces GCC to emit the specified nested function as a function */
92 #define __SEH_USE_NESTED_FUNCTION(F_) (void)(&F_) /* __attribute__((noinline)) seems to do the trick */
94 /* Soft memory barrier */
95 #define __SEH_BARRIER __asm__ __volatile__("#":::"memory")
97 typedef struct __SEHRegistration
99 struct __SEHRegistration
* SER_Prev
;
100 _SEHFrameHandler_t SER_Handler
;
104 #define __SEH_FORCE_NEST \
105 __asm__ __volatile__("#%0" : : "r" (&_SEHFrame))
107 #define __SEH_NESTED_PROLOG \
110 #define __SEH_DECLARE_EXCEPT_PFN(NAME_) int (__cdecl * NAME_)(void *)
111 #define __SEH_DECLARE_EXCEPT(NAME_) int __cdecl NAME_(void *)
112 #define __SEH_DEFINE_EXCEPT(NAME_) int __cdecl NAME_(void * _SEHExceptionPointers)
114 #define __SEH_DECLARE_FINALLY_PFN(NAME_) void (__cdecl * NAME_)(void)
115 #define __SEH_DECLARE_FINALLY(NAME_) void __cdecl NAME_(void)
116 #define __SEH_DEFINE_FINALLY(NAME_) void __cdecl NAME_(void)
118 #define __SEH_RETURN_EXCEPT(R_) return (int)(R_)
119 #define __SEH_RETURN_FINALLY() return
121 typedef struct __SEHFrame
123 _SEHRegistration_t SF_Registration
;
124 volatile struct __SEHTryLevel
* volatile SF_TopTryLevel
;
125 void * SF_FramePointer
;
126 void * volatile SF_StackPointer
;
127 volatile unsigned long SF_Code
;
131 typedef struct __SEHTryLevel
133 volatile struct __SEHTryLevel
* ST_Next
;
134 void * ST_FramePointer
;
140 #define __SEH_BEGIN_TRY \
142 __label__ _SEHBeginTry; \
143 __label__ _SEHEndTry; \
145 __SEH_USE_LABEL(_SEHBeginTry); \
146 __SEH_USE_LABEL(_SEHEndTry); \
148 _SEHBeginTry: __SEH_SIDE_EFFECT; \
152 #define __SEH_END_TRY \
155 _SEHEndTry: __SEH_SIDE_EFFECT; \
158 #define __SEH_SET_TRYLEVEL(TRYLEVEL_) \
160 __SEH_BARRIER; _SEHFrameP->SF_TopTryLevel = (TRYLEVEL_); __SEH_BARRIER; \
163 #define __SEH_ENTER_TRYLEVEL() __SEH_SET_TRYLEVEL(&_SEHTryLevel)
164 #define __SEH_LEAVE_TRYLEVEL() __SEH_SET_TRYLEVEL(_SEHPrevTryLevelP)
166 #define __SEH_END_SCOPE_CHAIN \
167 static const int _SEHScopeKind = 1; \
168 static _SEHFrame_t * const _SEHFrameP = 0; \
169 static _SEHTryLevel_t * const _SEHTryLevelP = 0;
171 #define __SEH_BEGIN_SCOPE \
174 __label__ _SEHBeginScope; \
175 __label__ _SEHEndScope; \
177 _SEHBeginScope: __SEH_SIDE_EFFECT; \
179 static const int _SEHTopTryLevel = (_SEHScopeKind != 0); \
180 _SEHFrame_t * const _SEHCurFrameP = _SEHFrameP; \
181 volatile _SEHTryLevel_t * const _SEHPrevTryLevelP = _SEHTryLevelP; \
183 (void)_SEHTopTryLevel; \
184 (void)_SEHCurFrameP; \
185 (void)_SEHPrevTryLevelP; \
187 __SEH_USE_LABEL(_SEHBeginScope); \
188 __SEH_USE_LABEL(_SEHEndScope); \
191 __label__ _SEHBeforeTry; \
192 __label__ _SEHDoTry; \
193 __label__ _SEHAfterTry; \
194 static const int _SEHScopeKind = 0; \
195 _SEHFrame_t _SEHFrame; \
196 volatile _SEHTryLevel_t _SEHTryLevel; \
197 _SEHFrame_t * const _SEHFrameP = _SEHTopTryLevel ? &_SEHFrame : _SEHCurFrameP; \
198 volatile _SEHTryLevel_t * const _SEHTryLevelP = &_SEHTryLevel; \
200 (void)_SEHScopeKind; \
202 (void)_SEHTryLevel; \
204 (void)_SEHTryLevelP; \
206 _SEHTryLevel.ST_Next = _SEHPrevTryLevelP; \
207 goto _SEHBeforeTry; \
210 __SEH_ENTER_TRYLEVEL(); \
212 if(_SEHTopTryLevel) \
214 __SEH_BARRIER; __asm__ __volatile__("mov %%ebp, %0\n#%1" : "=m" (_SEHFrame.SF_FramePointer) : "r" (__builtin_frame_address(0))); __SEH_BARRIER; \
215 _SEH2EnterFrame(&_SEHFrame); \
218 #define __SEH_END_SCOPE \
221 _SEHEndScope: __SEH_SIDE_EFFECT; \
226 #define __SEH_SCOPE_LOCALS \
227 __label__ _SEHBeginExcept; \
228 __label__ _SEHEndExcept; \
230 auto __SEH_DECLARE_EXCEPT(_SEHExcept); \
231 auto __SEH_DECLARE_FINALLY(_SEHFinally);
236 __SEH_SCOPE_LOCALS; \
238 void _SEHJumpToHandler() { goto _SEHBeginExcept; } \
243 #define _SEH2_FINALLY \
250 __SEH_PRETEND_USE_LABEL(_SEHBeginExcept); \
251 __SEH_PRETEND_USE_LABEL(_SEHEndExcept); \
253 __SEH_USE_NESTED_FUNCTION(_SEHFinally); \
255 _SEHTryLevel.ST_FramePointer = _SEHClosureFromTrampoline((_SEHTrampoline_t *)&_SEHFinally); \
256 _SEHTryLevel.ST_Filter = NULL; \
257 _SEHTryLevel.ST_Body = _SEHFunctionFromTrampoline((_SEHTrampoline_t *)&_SEHFinally); \
262 if(_SEHTopTryLevel) \
266 __SEH_LEAVE_TRYLEVEL(); \
270 goto _SEHEndExcept; \
272 _SEHBeginExcept: __SEH_PRETEND_SIDE_EFFECT; \
273 __attribute__((unused)) __SEH_DEFINE_EXCEPT(_SEHExcept) { __SEH_RETURN_EXCEPT(0); } \
275 __attribute__((noinline)) __attribute__((used)) __SEH_DEFINE_FINALLY(_SEHFinally) \
277 __SEH_END_SCOPE_CHAIN; \
279 (void)_SEHScopeKind; \
281 (void)_SEHTryLevelP; \
283 __SEH_NESTED_PROLOG; \
285 for(;; ({ __SEH_RETURN_FINALLY(); })) \
288 #define _SEH2_EXCEPT(E_) \
296 __SEH_USE_LABEL(_SEHBeginExcept); \
297 __SEH_USE_LABEL(_SEHEndExcept); \
299 __SEH_USE_NESTED_FUNCTION(_SEHExcept); \
301 _SEHTryLevel.ST_FramePointer = _SEHClosureFromTrampoline((_SEHTrampoline_t *)&_SEHExcept); \
302 _SEHTryLevel.ST_Filter = _SEHFunctionFromTrampoline((_SEHTrampoline_t *)&_SEHExcept); \
303 _SEHTryLevel.ST_Body = &&_SEHBeginExcept; \
304 __SEH_BARRIER; __asm__ __volatile__("mov %%esp, %0" : "=m" (_SEHFrameP->SF_StackPointer)); __SEH_BARRIER; \
308 __attribute__((noinline)) __attribute__((used)) __SEH_DEFINE_EXCEPT(_SEHExcept) \
310 __SEH_NESTED_PROLOG; \
311 __SEH_RETURN_EXCEPT(E_); \
314 __attribute__((unused)) __SEH_DEFINE_FINALLY(_SEHFinally) { __SEH_RETURN_FINALLY(); } \
317 if(_SEHTopTryLevel) \
321 __SEH_LEAVE_TRYLEVEL(); \
324 goto _SEHEndExcept; \
326 _SEHBeginExcept: __SEH_SIDE_EFFECT; \
329 _SEHFrame_t * const _SEHFrameP = _SEHTopTryLevel ? &_SEHFrame : _SEHCurFrameP; \
336 _SEHEndExcept: __SEH_SIDE_EFFECT; \
340 #define _SEH2_GetExceptionPointers() ((struct _EXCEPTION_POINTERS *)_SEHExceptionPointers)
341 #define _SEH2_GetExceptionCode() ((_SEHFrameP)->SF_Code)
343 __SEH_END_SCOPE_CHAIN
;
350 extern void __cdecl
_SEH2EnterFrame(_SEHFrame_t
*);
351 extern void __cdecl
_SEH2LeaveFrame(void);