2 Copyright (c) 2004/2005 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.
24 #define WIN32_LEAN_AND_MEAN
27 #include <pseh/pseh.h>
28 #include <pseh/framebased/internal.h>
29 #include <pseh/excpt.h>
30 #include <pseh/framebased.h>
35 #ifdef _SEH_ENABLE_TRACE
36 extern unsigned long __cdecl
DbgPrint(const char * format
, ...);
38 #define _SEH_TRACE_HEADER_(FRAME_) \
39 DbgPrint("[PSEH:%p]%s:%d:", FRAME_, __FILE__, __LINE__);
41 #define _SEH_TRACE_TRAILER_ \
44 #define _SEH_FILTER_RET_STRING_(RET_) \
45 (((int)(RET_) < 0) ? "_SEH_CONTINUE_EXECUTION" : (((int)(RET_) > 0) ? "_SEH_EXECUTE_HANDLER" : "_SEH_CONTINUE_SEARCH"))
47 #define _SEH_TRACE_LINE_(FRAME_, ARGS_) \
49 _SEH_TRACE_HEADER_(FRAME_); \
51 _SEH_TRACE_TRAILER_; \
54 #define _SEH_TRACE_ENTER(FRAME_, FUNCNAME_, ARGS_) \
56 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_ENTER_LEAVE) \
58 _SEH_TRACE_HEADER_(FRAME_); \
59 DbgPrint(">>> %s(", (FUNCNAME_)); \
62 _SEH_TRACE_TRAILER_; \
66 #define _SEH_TRACE_LEAVE(FRAME_, FUNCNAME_, ARGS_) \
68 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_ENTER_LEAVE) \
70 _SEH_TRACE_HEADER_(FRAME_); \
71 DbgPrint("<<< %s => ", (FUNCNAME_)); \
73 _SEH_TRACE_TRAILER_; \
77 #define _SEH_TRACE_EXCEPTION_RECORD(FRAME_, ER_) \
79 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_EXCEPTION_RECORD) \
85 "ExceptionRecord %p = { ExceptionCode : %08X, ExceptionFlags : %08X, ExceptionRecord : %p, ExceptionAddress : %p }", \
87 (ER_)->ExceptionCode, \
88 (ER_)->ExceptionFlags, \
89 (ER_)->ExceptionRecord, \
90 (ER_)->ExceptionAddress \
97 #define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_) \
99 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CONTEXT) \
101 if(((CONTEXT_)->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) \
107 "eax=%08X ebx=%08X ecx=%08X edx=%08X esi=%08X edi=%08X", \
118 if(((CONTEXT_)->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) \
124 "eip=%08X esp=%08X ebp=%08X efl=%08X cs=%08X ss=%08X", \
128 (CONTEXT_)->EFlags, \
135 if(((CONTEXT_)->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) \
141 "ds=%08X es=%08X fs=%08X gs=%08X", \
152 #error Unsupported platform.
155 #define _SEH_TRACE_UNWIND(FRAME_, ARGS_) \
157 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_UNWIND) \
159 _SEH_TRACE_LINE_((FRAME_), ARGS_); \
163 #define _SEH_TRACE_TRYLEVEL(FRAME_, TRYLEVEL_) \
165 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_TRYLEVEL) \
167 _SEH_TRACE_LINE_((FRAME_), ("trylevel %p, filter %p", (TRYLEVEL_), (TRYLEVEL_)->SPT_Handlers->SH_Filter)); \
171 #define _SEH_TRACE_ENTER_CALL_FILTER(FRAME_, TRYLEVEL_, ER_) \
173 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FILTER) \
179 "trylevel %p, calling filter %p, ExceptionCode %08X", \
181 (TRYLEVEL_)->SPT_Handlers->SH_Filter, \
182 (ER_)->ExceptionCode \
188 #define _SEH_TRACE_LEAVE_CALL_FILTER(FRAME_, TRYLEVEL_, RET_) \
190 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FILTER) \
196 "trylevel %p, filter %p => %s", \
198 (TRYLEVEL_)->SPT_Handlers->SH_Filter, \
199 _SEH_FILTER_RET_STRING_(RET_) \
205 #define _SEH_TRACE_FILTER(FRAME_, TRYLEVEL_, RET_) \
207 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_FILTER) \
213 "trylevel %p => %s", \
215 _SEH_FILTER_RET_STRING_(RET_) \
221 #define _SEH_TRACE_ENTER_CALL_HANDLER(FRAME_, TRYLEVEL_) \
223 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_HANDLER) \
225 _SEH_TRACE_LINE_((FRAME_), ("trylevel %p, handling", (TRYLEVEL_))); \
229 #define _SEH_TRACE_ENTER_CALL_FINALLY(FRAME_, TRYLEVEL_) \
231 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FINALLY) \
237 "trylevel %p, calling exit routine %p", \
239 (TRYLEVEL_)->SPT_Handlers->SH_Finally \
245 #define _SEH_TRACE_LEAVE_CALL_FINALLY(FRAME_, TRYLEVEL_) \
247 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FINALLY) \
253 "trylevel %p, exit routine %p returned", \
255 (TRYLEVEL_)->SPT_Handlers->SH_Finally \
262 #define _SEH_TRACE_ENTER(FRAME_, FUNCNAME_, ARGS_)
263 #define _SEH_TRACE_LEAVE(FRAME_, FUNCNAME_, ARGS_)
264 #define _SEH_TRACE_EXCEPTION_RECORD(FRAME_, ER_)
265 #define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_)
266 #define _SEH_TRACE_UNWIND(FRAME_, ARGS_)
267 #define _SEH_TRACE_TRYLEVEL(FRAME_, TRYLEVEL_)
268 #define _SEH_TRACE_ENTER_CALL_FILTER(FRAME_, TRYLEVEL_, ER_)
269 #define _SEH_TRACE_LEAVE_CALL_FILTER(FRAME_, TRYLEVEL_, RET_)
270 #define _SEH_TRACE_FILTER(FRAME_, TRYLEVEL_, RET_)
271 #define _SEH_TRACE_ENTER_CALL_HANDLER(FRAME_, TRYLEVEL_)
272 #define _SEH_TRACE_ENTER_CALL_FINALLY(FRAME_, TRYLEVEL_)
273 #define _SEH_TRACE_LEAVE_CALL_FINALLY(FRAME_, TRYLEVEL_)
276 /* Assembly helpers, see i386/framebased.asm */
277 extern void __cdecl
_SEHCleanHandlerEnvironment(void);
278 extern struct __SEHRegistration
* __cdecl
_SEHRegisterFrame(_SEHRegistration_t
*);
279 extern void __cdecl
_SEHUnregisterFrame(void);
280 extern void __cdecl
_SEHGlobalUnwind(_SEHPortableFrame_t
*);
281 extern _SEHRegistration_t
* __cdecl
_SEHCurrentRegistration(void);
283 /* Borland C++ uses a different decoration (i.e. none) for stdcall functions */
284 extern void __stdcall
RtlUnwind(void *, void *, void *, void *);
285 void const * _SEHRtlUnwind
= RtlUnwind
;
287 static void __stdcall _SEHLocalUnwind
289 _SEHPortableFrame_t
* frame
,
290 _SEHPortableTryLevel_t
* dsttrylevel
293 _SEHPortableTryLevel_t
* trylevel
;
295 _SEH_TRACE_UNWIND(frame
, ("enter local unwind from %p to %p", frame
->SPF_TopTryLevel
, dsttrylevel
));
299 trylevel
= frame
->SPF_TopTryLevel
;
300 trylevel
!= dsttrylevel
;
301 trylevel
= trylevel
->SPT_Next
304 _SEHFinally_t pfnFinally
;
306 /* ASSERT(trylevel); */
308 pfnFinally
= trylevel
->SPT_Handlers
->SH_Finally
;
312 _SEH_TRACE_ENTER_CALL_FINALLY(frame
, trylevel
);
314 _SEH_TRACE_LEAVE_CALL_FINALLY(frame
, trylevel
);
318 _SEH_TRACE_UNWIND(frame
, ("leave local unwind from %p to %p", frame
->SPF_TopTryLevel
, dsttrylevel
));
321 static void __cdecl _SEHCallHandler
323 _SEHPortableFrame_t
* frame
,
324 _SEHPortableTryLevel_t
* trylevel
327 _SEHGlobalUnwind(frame
);
328 _SEHLocalUnwind(frame
, trylevel
);
329 _SEH_TRACE_ENTER_CALL_HANDLER(frame
, trylevel
);
330 frame
->SPF_Handler(trylevel
);
334 static int __cdecl _SEHFrameHandler
336 struct _EXCEPTION_RECORD
* ExceptionRecord
,
337 void * EstablisherFrame
,
338 struct _CONTEXT
* ContextRecord
,
339 void * DispatcherContext
342 _SEHPortableFrame_t
* frame
;
344 _SEHCleanHandlerEnvironment();
346 frame
= EstablisherFrame
;
361 _SEH_TRACE_EXCEPTION_RECORD(frame
, ExceptionRecord
);
362 _SEH_TRACE_CONTEXT(frame
, ContextRecord
);
365 if(ExceptionRecord
->ExceptionFlags
& (4 | 2))
367 _SEH_TRACE_UNWIND(frame
, ("enter forced unwind"));
368 _SEHLocalUnwind(frame
, NULL
);
369 _SEH_TRACE_UNWIND(frame
, ("leave forced unwind"));
375 _SEHPortableTryLevel_t
* trylevel
;
377 if(ExceptionRecord
->ExceptionCode
)
378 frame
->SPF_Code
= ExceptionRecord
->ExceptionCode
;
380 frame
->SPF_Code
= 0xC0000001;
384 trylevel
= frame
->SPF_TopTryLevel
;
386 trylevel
= trylevel
->SPT_Next
389 _SEHFilter_t pfnFilter
= trylevel
->SPT_Handlers
->SH_Filter
;
391 _SEH_TRACE_TRYLEVEL(frame
, trylevel
);
393 switch((UINT_PTR
)pfnFilter
)
395 case (UINT_PTR
)_SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER
):
396 case (UINT_PTR
)_SEH_STATIC_FILTER(_SEH_CONTINUE_SEARCH
):
397 case (UINT_PTR
)_SEH_STATIC_FILTER(_SEH_CONTINUE_EXECUTION
):
399 ret
= (int)((UINT_PTR
)pfnFilter
) - 2;
405 if(trylevel
->SPT_Handlers
->SH_Filter
)
407 EXCEPTION_POINTERS ep
;
409 ep
.ExceptionRecord
= ExceptionRecord
;
410 ep
.ContextRecord
= ContextRecord
;
412 _SEH_TRACE_ENTER_CALL_FILTER(frame
, trylevel
, ExceptionRecord
);
413 ret
= pfnFilter(&ep
, frame
);
414 _SEH_TRACE_LEAVE_CALL_FILTER(frame
, trylevel
, ret
);
417 ret
= _SEH_CONTINUE_SEARCH
;
423 _SEH_TRACE_FILTER(frame
, trylevel
, ret
);
425 /* _SEH_CONTINUE_EXECUTION */
428 _SEH_TRACE_LEAVE(frame
, "_SEHFrameHandler", ("ExceptionContinueExecution"));
429 return ExceptionContinueExecution
;
431 /* _SEH_EXECUTE_HANDLER */
433 _SEHCallHandler(frame
, trylevel
);
434 /* _SEH_CONTINUE_SEARCH */
442 _SEH_TRACE_LEAVE(frame
, "_SEHFrameHandler", ("ExceptionContinueSearch"));
443 return ExceptionContinueSearch
;
446 void __stdcall _SEHEnterFrame_s
448 _SEHPortableFrame_t
* frame
,
449 _SEHPortableTryLevel_t
* trylevel
452 _SEHEnterFrame_f(frame
, trylevel
);
455 void __stdcall
_SEHEnterTry_s(_SEHPortableTryLevel_t
* trylevel
)
457 _SEHEnterTry_f(trylevel
);
460 void __stdcall
_SEHLeave_s(void)
465 void _SEH_FASTCALL _SEHEnterFrame_f
467 _SEHPortableFrame_t
* frame
,
468 _SEHPortableTryLevel_t
* trylevel
472 /* ASSERT(trylevel); */
473 frame
->SPF_Registration
.SER_Handler
= _SEHFrameHandler
;
475 frame
->SPF_TopTryLevel
= trylevel
;
476 trylevel
->SPT_Next
= NULL
;
477 _SEHRegisterFrame(&frame
->SPF_Registration
);
480 void _SEH_FASTCALL
_SEHEnterTry_f(_SEHPortableTryLevel_t
* trylevel
)
482 _SEHPortableFrame_t
* frame
;
484 frame
= _SEH_CONTAINING_RECORD
486 _SEHCurrentRegistration(),
491 trylevel
->SPT_Next
= frame
->SPF_TopTryLevel
;
492 frame
->SPF_TopTryLevel
= trylevel
;
495 void _SEH_FASTCALL
_SEHLeave_f(void)
497 _SEHPortableFrame_t
* frame
;
498 _SEHPortableTryLevel_t
* trylevel
;
500 frame
= _SEH_CONTAINING_RECORD
502 _SEHCurrentRegistration(),
509 trylevel
= frame
->SPF_TopTryLevel
;
511 /* ASSERT(trylevel); */
513 if(trylevel
->SPT_Next
)
514 frame
->SPF_TopTryLevel
= trylevel
->SPT_Next
;
516 _SEHUnregisterFrame();