mirror of
https://github.com/reactos/reactos.git
synced 2024-08-30 07:08:19 +00:00
504 lines
11 KiB
C
504 lines
11 KiB
C
/*
|
|
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);
|
|
|
|
/* Borland C++ uses a different decoration (i.e. none) for stdcall functions */
|
|
extern void __stdcall RtlUnwind(void *, void *, PEXCEPTION_RECORD, void *);
|
|
void const * _SEHRtlUnwind = RtlUnwind;
|
|
|
|
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 (UINT_PTR)_SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER):
|
|
case (UINT_PTR)_SEH_STATIC_FILTER(_SEH_CONTINUE_SEARCH):
|
|
case (UINT_PTR)_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 */
|