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.
25 #define WIN32_LEAN_AND_MEAN
28 #include <pseh/pseh.h>
29 #include <pseh/framebased/internal.h>
30 #include <pseh/excpt.h>
31 #include <pseh/framebased.h>
36 #ifdef _SEH_ENABLE_TRACE
37 extern unsigned long __cdecl
DbgPrint(const char * format
, ...);
39 #define _SEH_TRACE_HEADER_(FRAME_) \
40 DbgPrint("[PSEH:%p]%s:%d:", FRAME_, __FILE__, __LINE__);
42 #define _SEH_TRACE_TRAILER_ \
45 #define _SEH_FILTER_RET_STRING_(RET_) \
46 (((int)(RET_) < 0) ? "_SEH_CONTINUE_EXECUTION" : (((int)(RET_) > 0) ? "_SEH_EXECUTE_HANDLER" : "_SEH_CONTINUE_SEARCH"))
48 #define _SEH_TRACE_LINE_(FRAME_, ARGS_) \
50 _SEH_TRACE_HEADER_(FRAME_); \
52 _SEH_TRACE_TRAILER_; \
55 #define _SEH_TRACE_ENTER(FRAME_, FUNCNAME_, ARGS_) \
57 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_ENTER_LEAVE) \
59 _SEH_TRACE_HEADER_(FRAME_); \
60 DbgPrint(">>> %s(", (FUNCNAME_)); \
63 _SEH_TRACE_TRAILER_; \
67 #define _SEH_TRACE_LEAVE(FRAME_, FUNCNAME_, ARGS_) \
69 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_ENTER_LEAVE) \
71 _SEH_TRACE_HEADER_(FRAME_); \
72 DbgPrint("<<< %s => ", (FUNCNAME_)); \
74 _SEH_TRACE_TRAILER_; \
78 #define _SEH_TRACE_EXCEPTION_RECORD(FRAME_, ER_) \
80 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_EXCEPTION_RECORD) \
86 "ExceptionRecord %p = { ExceptionCode : %08X, ExceptionFlags : %08X, ExceptionRecord : %p, ExceptionAddress : %p }", \
88 (ER_)->ExceptionCode, \
89 (ER_)->ExceptionFlags, \
90 (ER_)->ExceptionRecord, \
91 (ER_)->ExceptionAddress \
98 #define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_) \
100 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CONTEXT) \
102 if(((CONTEXT_)->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) \
108 "eax=%08X ebx=%08X ecx=%08X edx=%08X esi=%08X edi=%08X", \
119 if(((CONTEXT_)->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) \
125 "eip=%08X esp=%08X ebp=%08X efl=%08X cs=%08X ss=%08X", \
129 (CONTEXT_)->EFlags, \
136 if(((CONTEXT_)->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) \
142 "ds=%08X es=%08X fs=%08X gs=%08X", \
153 #define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_)
156 #define _SEH_TRACE_UNWIND(FRAME_, ARGS_) \
158 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_UNWIND) \
160 _SEH_TRACE_LINE_((FRAME_), ARGS_); \
164 #define _SEH_TRACE_TRYLEVEL(FRAME_, TRYLEVEL_) \
166 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_TRYLEVEL) \
168 _SEH_TRACE_LINE_((FRAME_), ("trylevel %p, filter %p", (TRYLEVEL_), (TRYLEVEL_)->SPT_Handlers.SH_Filter)); \
172 #define _SEH_TRACE_ENTER_CALL_FILTER(FRAME_, TRYLEVEL_, ER_) \
174 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FILTER) \
180 "trylevel %p, calling filter %p, ExceptionCode %08X", \
182 (TRYLEVEL_)->SPT_Handlers.SH_Filter, \
183 (ER_)->ExceptionCode \
189 #define _SEH_TRACE_LEAVE_CALL_FILTER(FRAME_, TRYLEVEL_, RET_) \
191 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FILTER) \
197 "trylevel %p, filter %p => %s", \
199 (TRYLEVEL_)->SPT_Handlers.SH_Filter, \
200 _SEH_FILTER_RET_STRING_(RET_) \
206 #define _SEH_TRACE_FILTER(FRAME_, TRYLEVEL_, RET_) \
208 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_FILTER) \
214 "trylevel %p => %s", \
216 _SEH_FILTER_RET_STRING_(RET_) \
222 #define _SEH_TRACE_ENTER_CALL_HANDLER(FRAME_, TRYLEVEL_) \
224 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_HANDLER) \
226 _SEH_TRACE_LINE_((FRAME_), ("trylevel %p, handling", (TRYLEVEL_))); \
230 #define _SEH_TRACE_ENTER_CALL_FINALLY(FRAME_, TRYLEVEL_) \
232 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FINALLY) \
238 "trylevel %p, calling exit routine %p", \
240 (TRYLEVEL_)->SPT_Handlers.SH_Finally \
246 #define _SEH_TRACE_LEAVE_CALL_FINALLY(FRAME_, TRYLEVEL_) \
248 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FINALLY) \
254 "trylevel %p, exit routine %p returned", \
256 (TRYLEVEL_)->SPT_Handlers.SH_Finally \
263 #define _SEH_TRACE_ENTER(FRAME_, FUNCNAME_, ARGS_)
264 #define _SEH_TRACE_LEAVE(FRAME_, FUNCNAME_, ARGS_)
265 #define _SEH_TRACE_EXCEPTION_RECORD(FRAME_, ER_)
266 #define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_)
267 #define _SEH_TRACE_UNWIND(FRAME_, ARGS_)
268 #define _SEH_TRACE_TRYLEVEL(FRAME_, TRYLEVEL_)
269 #define _SEH_TRACE_ENTER_CALL_FILTER(FRAME_, TRYLEVEL_, ER_)
270 #define _SEH_TRACE_LEAVE_CALL_FILTER(FRAME_, TRYLEVEL_, RET_)
271 #define _SEH_TRACE_FILTER(FRAME_, TRYLEVEL_, RET_)
272 #define _SEH_TRACE_ENTER_CALL_HANDLER(FRAME_, TRYLEVEL_)
273 #define _SEH_TRACE_ENTER_CALL_FINALLY(FRAME_, TRYLEVEL_)
274 #define _SEH_TRACE_LEAVE_CALL_FINALLY(FRAME_, TRYLEVEL_)
277 /* Assembly helpers, see i386/framebased.asm */
278 extern void __cdecl
_SEHCleanHandlerEnvironment(void);
279 extern struct __SEHRegistration
* __cdecl
_SEHRegisterFrame(_SEHRegistration_t
*);
280 extern void __cdecl
_SEHUnregisterFrame(void);
281 extern void __cdecl
_SEHGlobalUnwind(_SEHPortableFrame_t
*);
282 extern _SEHRegistration_t
* __cdecl
_SEHCurrentRegistration(void);
284 /* Borland C++ uses a different decoration (i.e. none) for stdcall functions */
285 extern void __stdcall
RtlUnwind(void *, void *, PEXCEPTION_RECORD
, void *);
286 void const * _SEHRtlUnwind
= RtlUnwind
;
288 static void __stdcall _SEHLocalUnwind
290 _SEHPortableFrame_t
* frame
,
291 _SEHPortableTryLevel_t
* dsttrylevel
294 _SEHPortableTryLevel_t
* trylevel
;
296 _SEH_TRACE_UNWIND(frame
, ("enter local unwind from %p to %p", frame
->SPF_TopTryLevel
, dsttrylevel
));
300 trylevel
= frame
->SPF_TopTryLevel
;
301 trylevel
!= dsttrylevel
;
302 trylevel
= trylevel
->SPT_Next
305 _SEHFinally_t pfnFinally
;
307 /* ASSERT(trylevel); */
309 pfnFinally
= trylevel
->SPT_Handlers
.SH_Finally
;
313 _SEH_TRACE_ENTER_CALL_FINALLY(frame
, trylevel
);
315 _SEH_TRACE_LEAVE_CALL_FINALLY(frame
, trylevel
);
319 _SEH_TRACE_UNWIND(frame
, ("leave local unwind from %p to %p", frame
->SPF_TopTryLevel
, dsttrylevel
));
322 static void __cdecl _SEHCallHandler
324 _SEHPortableFrame_t
* frame
,
325 _SEHPortableTryLevel_t
* trylevel
328 _SEHGlobalUnwind(frame
);
329 _SEHLocalUnwind(frame
, trylevel
);
330 _SEH_TRACE_ENTER_CALL_HANDLER(frame
, trylevel
);
331 frame
->SPF_Handler(trylevel
);
335 static int __cdecl _SEHFrameHandler
337 struct _EXCEPTION_RECORD
* ExceptionRecord
,
338 void * EstablisherFrame
,
339 struct _CONTEXT
* ContextRecord
,
340 void * DispatcherContext
343 _SEHPortableFrame_t
* frame
;
345 _SEHCleanHandlerEnvironment();
347 frame
= EstablisherFrame
;
362 _SEH_TRACE_EXCEPTION_RECORD(frame
, ExceptionRecord
);
363 _SEH_TRACE_CONTEXT(frame
, ContextRecord
);
366 if(ExceptionRecord
->ExceptionFlags
& (4 | 2))
368 _SEH_TRACE_UNWIND(frame
, ("enter forced unwind"));
369 _SEHLocalUnwind(frame
, NULL
);
370 _SEH_TRACE_UNWIND(frame
, ("leave forced unwind"));
376 _SEHPortableTryLevel_t
* trylevel
;
378 if(ExceptionRecord
->ExceptionCode
)
379 frame
->SPF_Code
= ExceptionRecord
->ExceptionCode
;
381 frame
->SPF_Code
= 0xC0000001;
385 trylevel
= frame
->SPF_TopTryLevel
;
387 trylevel
= trylevel
->SPT_Next
390 _SEHFilter_t pfnFilter
= trylevel
->SPT_Handlers
.SH_Filter
;
392 _SEH_TRACE_TRYLEVEL(frame
, trylevel
);
394 switch((UINT_PTR
)pfnFilter
)
396 case (UINT_PTR
)_SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER
):
397 case (UINT_PTR
)_SEH_STATIC_FILTER(_SEH_CONTINUE_SEARCH
):
398 case (UINT_PTR
)_SEH_STATIC_FILTER(_SEH_CONTINUE_EXECUTION
):
400 ret
= (int)((UINT_PTR
)pfnFilter
) - 2;
406 if(trylevel
->SPT_Handlers
.SH_Filter
)
408 EXCEPTION_POINTERS ep
;
410 ep
.ExceptionRecord
= ExceptionRecord
;
411 ep
.ContextRecord
= ContextRecord
;
413 _SEH_TRACE_ENTER_CALL_FILTER(frame
, trylevel
, ExceptionRecord
);
414 ret
= pfnFilter(&ep
, frame
);
415 _SEH_TRACE_LEAVE_CALL_FILTER(frame
, trylevel
, ret
);
418 ret
= _SEH_CONTINUE_SEARCH
;
424 _SEH_TRACE_FILTER(frame
, trylevel
, ret
);
426 /* _SEH_CONTINUE_EXECUTION */
429 _SEH_TRACE_LEAVE(frame
, "_SEHFrameHandler", ("ExceptionContinueExecution"));
430 return ExceptionContinueExecution
;
432 /* _SEH_EXECUTE_HANDLER */
434 _SEHCallHandler(frame
, trylevel
);
435 /* _SEH_CONTINUE_SEARCH */
443 _SEH_TRACE_LEAVE(frame
, "_SEHFrameHandler", ("ExceptionContinueSearch"));
444 return ExceptionContinueSearch
;
447 void __stdcall
_SEHEnterFrame_s(_SEHPortableFrame_t
* frame
)
449 _SEHEnterFrame_f(frame
);
452 void __stdcall
_SEHLeaveFrame_s(void)
457 void __stdcall
_SEHReturn_s(void)
462 void _SEH_FASTCALL
_SEHEnterFrame_f(_SEHPortableFrame_t
* frame
)
465 /* ASSERT(trylevel); */
466 frame
->SPF_Registration
.SER_Handler
= _SEHFrameHandler
;
468 _SEHRegisterFrame(&frame
->SPF_Registration
);
471 void _SEH_FASTCALL
_SEHLeaveFrame_f(void)
473 _SEHPortableFrame_t
* frame
;
475 frame
= _SEH_CONTAINING_RECORD
477 _SEHCurrentRegistration(),
483 /* ASSERT(frame->SPF_TopTryLevel == NULL) */
485 _SEHUnregisterFrame();
488 void _SEH_FASTCALL
_SEHReturn_f(void)
490 _SEHPortableFrame_t
* frame
;
492 frame
= _SEH_CONTAINING_RECORD
494 _SEHCurrentRegistration(),
499 _SEHLocalUnwind(frame
, NULL
);
500 _SEHUnregisterFrame();