xref: /reactos/sdk/lib/pseh/include/pseh/pseh2.h (revision 96676ca2)
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