| /* |
| Copyright (c) 2004/2005 KJK::Hyperion |
| |
| Permission is hereby granted, free of charge, to any person obtaining a |
| copy of this software and associated documentation files (the "Software"), |
| to deal in the Software without restriction, including without limitation |
| the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| and/or sell copies of the Software, and to permit persons to whom the |
| Software is furnished to do so, subject to the following conditions: |
| |
| The above copyright notice and this permission notice shall be included in |
| all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #define _NTSYSTEM_ |
| #define STRICT |
| #define WIN32_LEAN_AND_MEAN |
| #include <windows.h> |
| |
| #include <pseh/pseh.h> |
| #include <pseh/framebased/internal.h> |
| #include <pseh/excpt.h> |
| #include <pseh/framebased.h> |
| |
| #include <excpt.h> |
| |
| /* Tracing */ |
| #ifdef _SEH_ENABLE_TRACE |
| extern unsigned long __cdecl DbgPrint(const char * format, ...); |
| |
| #define _SEH_TRACE_HEADER_(FRAME_) \ |
| DbgPrint("[PSEH:%p]%s:%d:", FRAME_, __FILE__, __LINE__); |
| |
| #define _SEH_TRACE_TRAILER_ \ |
| DbgPrint("\n"); |
| |
| #define _SEH_FILTER_RET_STRING_(RET_) \ |
| (((int)(RET_) < 0) ? "_SEH_CONTINUE_EXECUTION" : (((int)(RET_) > 0) ? "_SEH_EXECUTE_HANDLER" : "_SEH_CONTINUE_SEARCH")) |
| |
| #define _SEH_TRACE_LINE_(FRAME_, ARGS_) \ |
| { \ |
| _SEH_TRACE_HEADER_(FRAME_); \ |
| DbgPrint ARGS_; \ |
| _SEH_TRACE_TRAILER_; \ |
| } |
| |
| #define _SEH_TRACE_ENTER(FRAME_, FUNCNAME_, ARGS_) \ |
| { \ |
| if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_ENTER_LEAVE) \ |
| { \ |
| _SEH_TRACE_HEADER_(FRAME_); \ |
| DbgPrint(">>> %s(", (FUNCNAME_)); \ |
| DbgPrint ARGS_; \ |
| DbgPrint(")"); \ |
| _SEH_TRACE_TRAILER_; \ |
| } \ |
| } |
| |
| #define _SEH_TRACE_LEAVE(FRAME_, FUNCNAME_, ARGS_) \ |
| { \ |
| if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_ENTER_LEAVE) \ |
| { \ |
| _SEH_TRACE_HEADER_(FRAME_); \ |
| DbgPrint("<<< %s => ", (FUNCNAME_)); \ |
| DbgPrint ARGS_; \ |
| _SEH_TRACE_TRAILER_; \ |
| } \ |
| } |
| |
| #define _SEH_TRACE_EXCEPTION_RECORD(FRAME_, ER_) \ |
| { \ |
| if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_EXCEPTION_RECORD) \ |
| { \ |
| _SEH_TRACE_LINE_ \ |
| ( \ |
| (FRAME_), \ |
| ( \ |
| "ExceptionRecord %p = { ExceptionCode : %08X, ExceptionFlags : %08X, ExceptionRecord : %p, ExceptionAddress : %p }", \ |
| (ER_), \ |
| (ER_)->ExceptionCode, \ |
| (ER_)->ExceptionFlags, \ |
| (ER_)->ExceptionRecord, \ |
| (ER_)->ExceptionAddress \ |
| ) \ |
| ); \ |
| } \ |
| } |
| |
| #ifdef _X86_ |
| #define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_) \ |
| { \ |
| if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CONTEXT) \ |
| { \ |
| if(((CONTEXT_)->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) \ |
| { \ |
| _SEH_TRACE_LINE_ \ |
| ( \ |
| (FRAME_), \ |
| ( \ |
| "eax=%08X ebx=%08X ecx=%08X edx=%08X esi=%08X edi=%08X", \ |
| (CONTEXT_)->Eax, \ |
| (CONTEXT_)->Ebx, \ |
| (CONTEXT_)->Ecx, \ |
| (CONTEXT_)->Edx, \ |
| (CONTEXT_)->Esi, \ |
| (CONTEXT_)->Edi \ |
| ) \ |
| ); \ |
| } \ |
| \ |
| if(((CONTEXT_)->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) \ |
| { \ |
| _SEH_TRACE_LINE_ \ |
| ( \ |
| (FRAME_), \ |
| ( \ |
| "eip=%08X esp=%08X ebp=%08X efl=%08X cs=%08X ss=%08X", \ |
| (CONTEXT_)->Eip, \ |
| (CONTEXT_)->Esp, \ |
| (CONTEXT_)->Ebp, \ |
| (CONTEXT_)->EFlags, \ |
| (CONTEXT_)->SegCs, \ |
| (CONTEXT_)->SegSs \ |
| ) \ |
| ); \ |
| } \ |
| \ |
| if(((CONTEXT_)->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) \ |
| { \ |
| _SEH_TRACE_LINE_ \ |
| ( \ |
| (FRAME_), \ |
| ( \ |
| "ds=%08X es=%08X fs=%08X gs=%08X", \ |
| (CONTEXT_)->SegDs, \ |
| (CONTEXT_)->SegEs, \ |
| (CONTEXT_)->SegFs, \ |
| (CONTEXT_)->SegGs \ |
| ) \ |
| ); \ |
| } \ |
| } \ |
| } |
| #else |
| #define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_) |
| #endif |
| |
| #define _SEH_TRACE_UNWIND(FRAME_, ARGS_) \ |
| { \ |
| if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_UNWIND) \ |
| { \ |
| _SEH_TRACE_LINE_((FRAME_), ARGS_); \ |
| } \ |
| } |
| |
| #define _SEH_TRACE_TRYLEVEL(FRAME_, TRYLEVEL_) \ |
| { \ |
| if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_TRYLEVEL) \ |
| { \ |
| _SEH_TRACE_LINE_((FRAME_), ("trylevel %p, filter %p", (TRYLEVEL_), (TRYLEVEL_)->SPT_Handlers.SH_Filter)); \ |
| } \ |
| } |
| |
| #define _SEH_TRACE_ENTER_CALL_FILTER(FRAME_, TRYLEVEL_, ER_) \ |
| { \ |
| if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FILTER) \ |
| { \ |
| _SEH_TRACE_LINE_ \ |
| ( \ |
| (FRAME_), \ |
| ( \ |
| "trylevel %p, calling filter %p, ExceptionCode %08X", \ |
| (TRYLEVEL_), \ |
| (TRYLEVEL_)->SPT_Handlers.SH_Filter, \ |
| (ER_)->ExceptionCode \ |
| ) \ |
| ); \ |
| } \ |
| } |
| |
| #define _SEH_TRACE_LEAVE_CALL_FILTER(FRAME_, TRYLEVEL_, RET_) \ |
| { \ |
| if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FILTER) \ |
| { \ |
| _SEH_TRACE_LINE_ \ |
| ( \ |
| (FRAME_), \ |
| ( \ |
| "trylevel %p, filter %p => %s", \ |
| (TRYLEVEL_), \ |
| (TRYLEVEL_)->SPT_Handlers.SH_Filter, \ |
| _SEH_FILTER_RET_STRING_(RET_) \ |
| ) \ |
| ); \ |
| } \ |
| } |
| |
| #define _SEH_TRACE_FILTER(FRAME_, TRYLEVEL_, RET_) \ |
| { \ |
| if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_FILTER) \ |
| { \ |
| _SEH_TRACE_LINE_ \ |
| ( \ |
| (FRAME_), \ |
| ( \ |
| "trylevel %p => %s", \ |
| (TRYLEVEL_), \ |
| _SEH_FILTER_RET_STRING_(RET_) \ |
| ) \ |
| ); \ |
| } \ |
| } |
| |
| #define _SEH_TRACE_ENTER_CALL_HANDLER(FRAME_, TRYLEVEL_) \ |
| { \ |
| if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_HANDLER) \ |
| { \ |
| _SEH_TRACE_LINE_((FRAME_), ("trylevel %p, handling", (TRYLEVEL_))); \ |
| } \ |
| } |
| |
| #define _SEH_TRACE_ENTER_CALL_FINALLY(FRAME_, TRYLEVEL_) \ |
| { \ |
| if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FINALLY) \ |
| { \ |
| _SEH_TRACE_LINE_ \ |
| ( \ |
| (FRAME_), \ |
| ( \ |
| "trylevel %p, calling exit routine %p", \ |
| (TRYLEVEL_), \ |
| (TRYLEVEL_)->SPT_Handlers.SH_Finally \ |
| ) \ |
| ); \ |
| } \ |
| } |
| |
| #define _SEH_TRACE_LEAVE_CALL_FINALLY(FRAME_, TRYLEVEL_) \ |
| { \ |
| if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FINALLY) \ |
| { \ |
| _SEH_TRACE_LINE_ \ |
| ( \ |
| (FRAME_), \ |
| ( \ |
| "trylevel %p, exit routine %p returned", \ |
| (TRYLEVEL_), \ |
| (TRYLEVEL_)->SPT_Handlers.SH_Finally \ |
| ) \ |
| ); \ |
| } \ |
| } |
| |
| #else |
| #define _SEH_TRACE_ENTER(FRAME_, FUNCNAME_, ARGS_) |
| #define _SEH_TRACE_LEAVE(FRAME_, FUNCNAME_, ARGS_) |
| #define _SEH_TRACE_EXCEPTION_RECORD(FRAME_, ER_) |
| #define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_) |
| #define _SEH_TRACE_UNWIND(FRAME_, ARGS_) |
| #define _SEH_TRACE_TRYLEVEL(FRAME_, TRYLEVEL_) |
| #define _SEH_TRACE_ENTER_CALL_FILTER(FRAME_, TRYLEVEL_, ER_) |
| #define _SEH_TRACE_LEAVE_CALL_FILTER(FRAME_, TRYLEVEL_, RET_) |
| #define _SEH_TRACE_FILTER(FRAME_, TRYLEVEL_, RET_) |
| #define _SEH_TRACE_ENTER_CALL_HANDLER(FRAME_, TRYLEVEL_) |
| #define _SEH_TRACE_ENTER_CALL_FINALLY(FRAME_, TRYLEVEL_) |
| #define _SEH_TRACE_LEAVE_CALL_FINALLY(FRAME_, TRYLEVEL_) |
| #endif |
| |
| /* Assembly helpers, see i386/framebased.asm */ |
| extern void __cdecl _SEHCleanHandlerEnvironment(void); |
| extern struct __SEHRegistration * __cdecl _SEHRegisterFrame(_SEHRegistration_t *); |
| extern void __cdecl _SEHUnregisterFrame(void); |
| extern void __cdecl _SEHGlobalUnwind(_SEHPortableFrame_t *); |
| extern _SEHRegistration_t * __cdecl _SEHCurrentRegistration(void); |
| |
| static void __stdcall _SEHLocalUnwind |
| ( |
| _SEHPortableFrame_t * frame, |
| _SEHPortableTryLevel_t * dsttrylevel |
| ) |
| { |
| _SEHPortableTryLevel_t * trylevel; |
| |
| _SEH_TRACE_UNWIND(frame, ("enter local unwind from %p to %p", frame->SPF_TopTryLevel, dsttrylevel)); |
| |
| for |
| ( |
| trylevel = frame->SPF_TopTryLevel; |
| trylevel != dsttrylevel; |
| trylevel = trylevel->SPT_Next |
| ) |
| { |
| _SEHFinally_t pfnFinally; |
| |
| /* ASSERT(trylevel); */ |
| |
| pfnFinally = trylevel->SPT_Handlers.SH_Finally; |
| |
| if(pfnFinally) |
| { |
| _SEH_TRACE_ENTER_CALL_FINALLY(frame, trylevel); |
| pfnFinally(frame); |
| _SEH_TRACE_LEAVE_CALL_FINALLY(frame, trylevel); |
| } |
| } |
| |
| _SEH_TRACE_UNWIND(frame, ("leave local unwind from %p to %p", frame->SPF_TopTryLevel, dsttrylevel)); |
| } |
| |
| static void __cdecl _SEHCallHandler |
| ( |
| _SEHPortableFrame_t * frame, |
| _SEHPortableTryLevel_t * trylevel |
| ) |
| { |
| _SEHGlobalUnwind(frame); |
| _SEHLocalUnwind(frame, trylevel); |
| _SEH_TRACE_ENTER_CALL_HANDLER(frame, trylevel); |
| frame->SPF_Handler(trylevel); |
| /* ASSERT(0); */ |
| } |
| |
| static int __cdecl _SEHFrameHandler |
| ( |
| struct _EXCEPTION_RECORD * ExceptionRecord, |
| void * EstablisherFrame, |
| struct _CONTEXT * ContextRecord, |
| void * DispatcherContext |
| ) |
| { |
| _SEHPortableFrame_t * frame; |
| |
| _SEHCleanHandlerEnvironment(); |
| |
| frame = EstablisherFrame; |
| |
| _SEH_TRACE_ENTER |
| ( |
| frame, |
| "_SEHFrameHandler", |
| ( |
| "%p, %p, %p, %p", |
| ExceptionRecord, |
| EstablisherFrame, |
| ContextRecord, |
| DispatcherContext |
| ) |
| ); |
| |
| _SEH_TRACE_EXCEPTION_RECORD(frame, ExceptionRecord); |
| _SEH_TRACE_CONTEXT(frame, ContextRecord); |
| |
| /* Unwinding */ |
| if(ExceptionRecord->ExceptionFlags & (4 | 2)) |
| { |
| _SEH_TRACE_UNWIND(frame, ("enter forced unwind")); |
| _SEHLocalUnwind(frame, NULL); |
| _SEH_TRACE_UNWIND(frame, ("leave forced unwind")); |
| } |
| /* Handling */ |
| else |
| { |
| int ret; |
| _SEHPortableTryLevel_t * trylevel; |
| |
| if(ExceptionRecord->ExceptionCode) |
| frame->SPF_Code = ExceptionRecord->ExceptionCode; |
| else |
| frame->SPF_Code = 0xC0000001; |
| |
| for |
| ( |
| trylevel = frame->SPF_TopTryLevel; |
| trylevel != NULL; |
| trylevel = trylevel->SPT_Next |
| ) |
| { |
| _SEHFilter_t pfnFilter = trylevel->SPT_Handlers.SH_Filter; |
| |
| _SEH_TRACE_TRYLEVEL(frame, trylevel); |
| |
| switch((UINT_PTR)pfnFilter) |
| { |
| case __SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER): |
| case __SEH_STATIC_FILTER(_SEH_CONTINUE_SEARCH): |
| case __SEH_STATIC_FILTER(_SEH_CONTINUE_EXECUTION): |
| { |
| ret = (int)((UINT_PTR)pfnFilter) - 2; |
| break; |
| } |
| |
| default: |
| { |
| if(trylevel->SPT_Handlers.SH_Filter) |
| { |
| EXCEPTION_POINTERS ep; |
| |
| ep.ExceptionRecord = ExceptionRecord; |
| ep.ContextRecord = ContextRecord; |
| |
| _SEH_TRACE_ENTER_CALL_FILTER(frame, trylevel, ExceptionRecord); |
| ret = pfnFilter(&ep, frame); |
| _SEH_TRACE_LEAVE_CALL_FILTER(frame, trylevel, ret); |
| } |
| else |
| ret = _SEH_CONTINUE_SEARCH; |
| |
| break; |
| } |
| } |
| |
| _SEH_TRACE_FILTER(frame, trylevel, ret); |
| |
| /* _SEH_CONTINUE_EXECUTION */ |
| if(ret < 0) |
| { |
| _SEH_TRACE_LEAVE(frame, "_SEHFrameHandler", ("ExceptionContinueExecution")); |
| return ExceptionContinueExecution; |
| } |
| /* _SEH_EXECUTE_HANDLER */ |
| else if(ret > 0) |
| _SEHCallHandler(frame, trylevel); |
| /* _SEH_CONTINUE_SEARCH */ |
| else |
| continue; |
| } |
| |
| /* FALLTHROUGH */ |
| } |
| |
| _SEH_TRACE_LEAVE(frame, "_SEHFrameHandler", ("ExceptionContinueSearch")); |
| return ExceptionContinueSearch; |
| } |
| |
| void __stdcall _SEHEnterFrame_s(_SEHPortableFrame_t * frame) |
| { |
| _SEHEnterFrame_f(frame); |
| } |
| |
| void __stdcall _SEHLeaveFrame_s(void) |
| { |
| _SEHLeaveFrame_f(); |
| } |
| |
| void __stdcall _SEHReturn_s(void) |
| { |
| _SEHReturn_f(); |
| } |
| |
| void _SEH_FASTCALL _SEHEnterFrame_f(_SEHPortableFrame_t * frame) |
| { |
| /* ASSERT(frame); */ |
| /* ASSERT(trylevel); */ |
| frame->SPF_Registration.SER_Handler = _SEHFrameHandler; |
| frame->SPF_Code = 0; |
| _SEHRegisterFrame(&frame->SPF_Registration); |
| } |
| |
| void _SEH_FASTCALL _SEHLeaveFrame_f(void) |
| { |
| _SEHPortableFrame_t * frame; |
| |
| frame = _SEH_CONTAINING_RECORD |
| ( |
| _SEHCurrentRegistration(), |
| _SEHPortableFrame_t, |
| SPF_Registration |
| ); |
| |
| /* ASSERT(frame); */ |
| /* ASSERT(frame->SPF_TopTryLevel == NULL) */ |
| |
| _SEHUnregisterFrame(); |
| } |
| |
| void _SEH_FASTCALL _SEHReturn_f(void) |
| { |
| _SEHPortableFrame_t * frame; |
| |
| frame = _SEH_CONTAINING_RECORD |
| ( |
| _SEHCurrentRegistration(), |
| _SEHPortableFrame_t, |
| SPF_Registration |
| ); |
| |
| _SEHLocalUnwind(frame, NULL); |
| _SEHUnregisterFrame(); |
| } |
| |
| /* EOF */ |