Sync to trunk r38250
[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 #ifdef _M_AMD64
23 #include "pseh2_64.h"
24 #else
25
26 #ifndef KJK_PSEH2_H_
27 #define KJK_PSEH2_H_
28
29 struct _EXCEPTION_RECORD;
30 struct _EXCEPTION_POINTERS;
31 struct _CONTEXT;
32
33 typedef int (__cdecl * _SEH2FrameHandler_t)
34 (
35 struct _EXCEPTION_RECORD *,
36 void *,
37 struct _CONTEXT *,
38 void *
39 );
40
41 typedef struct __SEH2Registration
42 {
43 struct __SEH2Registration * SER_Prev;
44 _SEH2FrameHandler_t SER_Handler;
45 }
46 _SEH2Registration_t;
47
48 typedef struct __SEH2Frame
49 {
50 _SEH2Registration_t SF_Registration;
51 volatile struct __SEH2TryLevel * volatile SF_TopTryLevel;
52 struct _EXCEPTION_POINTERS * volatile SF_ExceptionInformation;
53 volatile unsigned long SF_Code;
54 }
55 _SEH2Frame_t;
56
57 typedef struct __SEH2TryLevel
58 {
59 volatile struct __SEH2TryLevel * ST_Next;
60 void * ST_Filter;
61 void * ST_Body;
62 void * volatile ST_Ebp;
63 void * volatile ST_Esp;
64 }
65 _SEH2TryLevel_t;
66
67 #ifdef __cplusplus
68 extern "C"
69 {
70 #endif
71
72 extern __attribute__((returns_twice)) void __cdecl _SEH2EnterFrame(_SEH2Frame_t *);
73 extern void __cdecl _SEH2LeaveFrame(void);
74 extern void __cdecl _SEH2Return(void);
75
76 #ifdef __cplusplus
77 }
78 #endif
79
80 #if defined(__GNUC__)
81
82 #if defined(__i386__)
83 typedef struct __SEHTrampoline
84 {
85 unsigned char STR_MovEcx;
86 unsigned char STR_Closure[4];
87 unsigned char STR_Jmp;
88 unsigned char STR_Function[4];
89 }
90 _SEHTrampoline_t;
91
92 static
93 __inline__
94 __attribute__((always_inline))
95 int _SEHIsTrampoline(_SEHTrampoline_t * trampoline_)
96 {
97 return trampoline_->STR_MovEcx == 0xb9 && trampoline_->STR_Jmp == 0xe9;
98 }
99
100 static
101 __inline__
102 __attribute__((always_inline))
103 void * _SEHFunctionFromTrampoline(_SEHTrampoline_t * trampoline_)
104 {
105 return (void *)(*(int *)(&trampoline_->STR_Function[0]) + (int)(trampoline_ + 1));
106 }
107
108 static
109 __inline__
110 __attribute__((always_inline))
111 void * _SEHClosureFromTrampoline(_SEHTrampoline_t * trampoline_)
112 {
113 return (void *)*(int *)(&trampoline_->STR_Closure[0]);
114 }
115 #else
116 #error TODO
117 #endif
118
119 /* A no-op side effect that scares GCC */
120 #define __SEH_SIDE_EFFECT __asm__ __volatile__("#")
121
122 /* A no-op without any real side effects, but silences warnings */
123 #define __SEH_PRETEND_SIDE_EFFECT (void)0
124
125 /* Forces GCC to consider the specified label reachable */
126 #define __SEH_USE_LABEL(L_) if(__SEH_VOLATILE_FALSE) goto L_;
127
128 /* Makes GCC pretend the specified label is reachable, to silence warnings */
129 #define __SEH_PRETEND_USE_LABEL(L_) (void)(&&L_)
130
131 /* Soft memory barrier */
132 #define __SEH_BARRIER __asm__ __volatile__("#":::"memory")
133
134 /* GCC doesn't know that this equals zero */
135 #define __SEH_VOLATILE_ZERO ({ int zero = 0; __asm__ __volatile__("#" : "+g" (zero)); zero; })
136
137 #define __SEH_VOLATILE_FALSE __builtin_expect(__SEH_VOLATILE_ZERO, 0)
138 #define __SEH_VOLATILE_TRUE __builtin_expect(!__SEH_VOLATILE_ZERO, 1)
139
140 #define ___SEH_STRINGIFY(X_) # X_
141 #define __SEH_STRINGIFY(X_) ___SEH_STRINGIFY(X_)
142
143 #define __SEH_FORCE_NEST \
144 __asm__ __volatile__("#%0" : : "r" (&_SEHFrame))
145
146 #define __SEH_DECLARE_EXCEPT_PFN(NAME_) int (__cdecl * NAME_)(void)
147 #define __SEH_DECLARE_EXCEPT(NAME_) int __cdecl NAME_(void)
148 #define __SEH_DEFINE_EXCEPT(NAME_) int __cdecl NAME_(void)
149
150 #define __SEH_DECLARE_FINALLY_PFN(NAME_) void (__cdecl * NAME_)(void)
151 #define __SEH_DECLARE_FINALLY(NAME_) void __cdecl NAME_(void)
152 #define __SEH_DEFINE_FINALLY(NAME_) void __cdecl NAME_(void)
153
154 #define __SEH_RETURN_EXCEPT(R_) return (int)(R_)
155 #define __SEH_RETURN_FINALLY() return
156
157 #define __SEH_BEGIN_TRY \
158 { \
159 __label__ _SEHEndTry; \
160 \
161 __SEH_PRETEND_USE_LABEL(_SEHEndTry); \
162 \
163 { \
164 __SEH_BARRIER;
165
166 #define __SEH_END_TRY \
167 __SEH_BARRIER; \
168 } \
169 _SEHEndTry:; \
170 }
171
172 #define __SEH_SET_TRYLEVEL(TRYLEVEL_) \
173 { \
174 __SEH_BARRIER; _SEH2FrameP->SF_TopTryLevel = (TRYLEVEL_); __SEH_BARRIER; \
175 }
176
177 #define __SEH_ENTER_TRYLEVEL() __SEH_SET_TRYLEVEL(&_SEHTryLevel)
178 #define __SEH_LEAVE_TRYLEVEL() __SEH_SET_TRYLEVEL(_SEHPrevTryLevelP)
179
180 #define __SEH_END_SCOPE_CHAIN \
181 static const int _SEH2ScopeKind = 1; \
182 static _SEH2Frame_t * const _SEH2FrameP = 0; \
183 static _SEH2TryLevel_t * const _SEH2TryLevelP = 0;
184
185 #define __SEH_BEGIN_SCOPE \
186 for(;;) \
187 { \
188 const int _SEHTopTryLevel = (_SEH2ScopeKind != 0); \
189 _SEH2Frame_t * const _SEHCurFrameP = _SEH2FrameP; \
190 volatile _SEH2TryLevel_t * const _SEHPrevTryLevelP = _SEH2TryLevelP; \
191 __attribute__((unused)) int _SEHAbnormalTermination; \
192 \
193 (void)_SEHTopTryLevel; \
194 (void)_SEHCurFrameP; \
195 (void)_SEHPrevTryLevelP; \
196 \
197 { \
198 __label__ _SEHBeforeTry; \
199 __label__ _SEHDoTry; \
200 __label__ _SEHAfterTry; \
201 static const int _SEH2ScopeKind = 0; \
202 _SEH2Frame_t _SEHFrame; \
203 volatile _SEH2TryLevel_t _SEHTryLevel; \
204 _SEH2Frame_t * const _SEH2FrameP = _SEHTopTryLevel ? &_SEHFrame : _SEHCurFrameP; \
205 volatile _SEH2TryLevel_t * const _SEH2TryLevelP = &_SEHTryLevel; \
206 \
207 (void)_SEH2ScopeKind; \
208 (void)_SEHFrame; \
209 (void)_SEHTryLevel; \
210 (void)_SEH2FrameP; \
211 (void)_SEH2TryLevelP; \
212 \
213 _SEHTryLevel.ST_Next = _SEHPrevTryLevelP; \
214 goto _SEHBeforeTry; \
215 \
216 _SEHDoTry:; \
217 __SEH_ENTER_TRYLEVEL(); \
218 \
219 if(_SEHTopTryLevel) \
220 _SEH2EnterFrame(&_SEHFrame); \
221
222 #define __SEH_END_SCOPE \
223 } \
224 \
225 break; \
226 }
227
228 #define __SEH_SCOPE_LOCALS \
229 __label__ _SEHBeginExcept; \
230 __label__ _SEHEndExcept; \
231 \
232 auto __SEH_DECLARE_FINALLY(_SEHFinally);
233
234 #define _SEH2_TRY \
235 __SEH_BEGIN_SCOPE \
236 { \
237 __SEH_SCOPE_LOCALS; \
238 \
239 __SEH_BEGIN_TRY \
240 {
241
242 #define _SEH2_FINALLY \
243 } \
244 __SEH_END_TRY; \
245 \
246 goto _SEHAfterTry; \
247 _SEHBeforeTry:; \
248 \
249 __SEH_PRETEND_USE_LABEL(_SEHBeginExcept); \
250 __SEH_PRETEND_USE_LABEL(_SEHEndExcept); \
251 \
252 _SEHTryLevel.ST_Filter = 0; \
253 _SEHTryLevel.ST_Body = &_SEHFinally; \
254 \
255 _SEHAbnormalTermination = 1; \
256 \
257 goto _SEHDoTry; \
258 _SEHAfterTry:; \
259 \
260 _SEHAbnormalTermination = 0; \
261 \
262 if(_SEHTopTryLevel) \
263 _SEH2LeaveFrame(); \
264 else \
265 { \
266 __SEH_LEAVE_TRYLEVEL(); \
267 } \
268 \
269 _SEHFinally(); \
270 goto _SEHEndExcept; \
271 \
272 _SEHBeginExcept:; \
273 \
274 __attribute__((noinline)) __SEH_DEFINE_FINALLY(_SEHFinally) \
275 { \
276 __SEH_END_SCOPE_CHAIN; \
277 \
278 (void)_SEH2ScopeKind; \
279 (void)_SEH2FrameP; \
280 (void)_SEH2TryLevelP; \
281 \
282 for(;; ({ __SEH_RETURN_FINALLY(); })) \
283 {
284
285 #define _SEH2_EXCEPT(...) \
286 } \
287 __SEH_END_TRY; \
288 \
289 goto _SEHAfterTry; \
290 \
291 _SEHBeforeTry:; \
292 \
293 if(__builtin_constant_p((__VA_ARGS__))) \
294 { \
295 if((__VA_ARGS__) > 0) \
296 { \
297 _SEHTryLevel.ST_Filter = (void *)1; \
298 _SEHTryLevel.ST_Body = &&_SEHBeginExcept; \
299 __SEH_USE_LABEL(_SEHBeginExcept); \
300 } \
301 else if((__VA_ARGS__) < 0) \
302 { \
303 _SEHTryLevel.ST_Filter = (void *)-1; \
304 _SEHTryLevel.ST_Body = NULL; \
305 } \
306 else \
307 { \
308 _SEHTryLevel.ST_Filter = (void *)0; \
309 _SEHTryLevel.ST_Body = NULL; \
310 } \
311 } \
312 else \
313 { \
314 __SEH_DEFINE_EXCEPT(_SEHExcept) \
315 { \
316 __SEH_RETURN_EXCEPT((__VA_ARGS__)); \
317 } \
318 \
319 _SEHTryLevel.ST_Filter = &_SEHExcept; \
320 _SEHTryLevel.ST_Body = &&_SEHBeginExcept; \
321 __SEH_USE_LABEL(_SEHBeginExcept); \
322 } \
323 \
324 __SEH_BARRIER; \
325 \
326 __asm__ __volatile__ \
327 ( \
328 "mov %%ebp, %0\n" \
329 "mov %%esp, %1" : \
330 "=m" (_SEHTryLevel.ST_Ebp), \
331 "=m" (_SEHTryLevel.ST_Esp) \
332 ); \
333 \
334 __SEH_BARRIER; \
335 \
336 goto _SEHDoTry; \
337 \
338 __attribute__((unused)) __SEH_DEFINE_FINALLY(_SEHFinally) { __SEH_RETURN_FINALLY(); } \
339 \
340 _SEHAfterTry:; \
341 if(_SEHTopTryLevel) \
342 _SEH2LeaveFrame(); \
343 else \
344 { \
345 __SEH_LEAVE_TRYLEVEL(); \
346 } \
347 \
348 goto _SEHEndExcept; \
349 \
350 _SEHBeginExcept:; \
351 { \
352 { \
353 _SEH2Frame_t * const _SEH2FrameP = _SEHTopTryLevel ? &_SEHFrame : _SEHCurFrameP; \
354 (void)_SEH2FrameP; \
355 __SEH_BARRIER;
356
357 #define _SEH2_END \
358 __SEH_BARRIER; \
359 } \
360 } \
361 \
362 _SEHEndExcept:; \
363 } \
364 __SEH_END_SCOPE;
365
366 #define _SEH2_GetExceptionInformation() ((_SEH2FrameP)->SF_ExceptionInformation)
367 #define _SEH2_GetExceptionCode() ((_SEH2FrameP)->SF_Code)
368 #define _SEH2_AbnormalTermination() (_SEHAbnormalTermination)
369
370 #define _SEH2_YIELD(STMT_) \
371 for(;;) \
372 { \
373 if(!_SEH2ScopeKind) \
374 _SEH2Return(); \
375 \
376 STMT_; \
377 }
378
379 #define _SEH2_LEAVE goto _SEHEndTry
380
381 __SEH_END_SCOPE_CHAIN;
382
383 #else
384
385 #include <excpt.h>
386
387 #define _SEH2_TRY __try
388 #define _SEH2_FINALLY __finally
389 #define _SEH2_EXCEPT(...) __except(__VA_ARGS__)
390 #define _SEH2_END
391
392 #define _SEH2_GetExceptionInformation() (GetExceptionInformation())
393 #define _SEH2_GetExceptionCode() (GetExceptionCode())
394 #define _SEH2_AbnormalTermination() (AbnormalTermination())
395
396 #define _SEH2_YIELD(STMT_) STMT_
397 #define _SEH2_LEAVE __leave
398
399 #endif
400
401 #endif
402
403 #endif
404 /* EOF */