113 lines
3.2 KiB
C
113 lines
3.2 KiB
C
|
int
|
||
|
__except_handler3(
|
||
|
struct _EXCEPTION_RECORD* pExceptionRecord,
|
||
|
struct EXCEPTION_REGISTRATION* pRegistrationFrame,
|
||
|
struct _CONTEXT* pContextRecord,
|
||
|
void* pDispatcherContext
|
||
|
)
|
||
|
{
|
||
|
LONG filterFuncRet;
|
||
|
LONG trylevel;
|
||
|
EXCEPTION_POINTERS exceptPtrs;
|
||
|
PSCOPETABLE pScopeTable;
|
||
|
|
||
|
|
||
|
CLD // Clear the direction flag (make no assumptions!)
|
||
|
|
||
|
// if neither the EXCEPTION_UNWINDING nor EXCEPTION_EXIT_UNWIND bit
|
||
|
// is set... This is true the first time through the handler (the
|
||
|
// non-unwinding case)
|
||
|
|
||
|
if ( ! (pExceptionRecord->ExceptionFlags
|
||
|
& (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)
|
||
|
) )
|
||
|
{
|
||
|
// Build the EXCEPTION_POINTERS structure on the stack
|
||
|
exceptPtrs.ExceptionRecord = pExceptionRecord;
|
||
|
exceptPtrs.ContextRecord = pContextRecord;
|
||
|
|
||
|
// Put the pointer to the EXCEPTION_POINTERS 4 bytes below the
|
||
|
// establisher frame. See ASM code for GetExceptionInformation
|
||
|
*(PDWORD)((PBYTE)pRegistrationFrame - 4) = &exceptPtrs;
|
||
|
|
||
|
// Get initial "trylevel" value
|
||
|
trylevel = pRegistrationFrame->trylevel
|
||
|
|
||
|
// Get a pointer to the scopetable array
|
||
|
scopeTable = pRegistrationFrame->scopetable;
|
||
|
|
||
|
search_for_handler:
|
||
|
if ( pRegistrationFrame->trylevel != TRYLEVEL_NONE )
|
||
|
{
|
||
|
if ( pRegistrationFrame->scopetable[trylevel].lpfnFilter )
|
||
|
{
|
||
|
|
||
|
PUSH EBP // Save this frame EBP
|
||
|
|
||
|
// !!!Very Important!!! Switch to original EBP. This is
|
||
|
// what allows all locals in the frame to have the same
|
||
|
// value as before the exception occurred.
|
||
|
|
||
|
EBP = &pRegistrationFrame->_ebp
|
||
|
|
||
|
// Call the filter function
|
||
|
filterFuncRet = scopetable[trylevel].lpfnFilter();
|
||
|
|
||
|
POP EBP // Restore handler frame EBP
|
||
|
|
||
|
if ( filterFuncRet != EXCEPTION_CONTINUE_SEARCH )
|
||
|
{
|
||
|
if ( filterFuncRet < 0 ) // EXCEPTION_CONTINUE_EXECUTION
|
||
|
return ExceptionContinueExecution;
|
||
|
|
||
|
// If we get here, EXCEPTION_EXECUTE_HANDLER was specified
|
||
|
scopetable == pRegistrationFrame->scopetable
|
||
|
|
||
|
// Does the actual OS cleanup of registration frames
|
||
|
// Causes this function to recurse
|
||
|
__global_unwind2( pRegistrationFrame );
|
||
|
|
||
|
|
||
|
// Once we get here, everything is all cleaned up, except
|
||
|
// for the last frame, where we'll continue execution
|
||
|
EBP = &pRegistrationFrame->_ebp
|
||
|
|
||
|
__local_unwind2( pRegistrationFrame, trylevel );
|
||
|
|
||
|
// NLG == "non-local-goto" (setjmp/longjmp stuff)
|
||
|
__NLG_Notify( 1 ); // EAX == scopetable->lpfnHandler
|
||
|
|
||
|
// Set the current trylevel to whatever SCOPETABLE entry
|
||
|
// was being used when a handler was found
|
||
|
pRegistrationFrame->trylevel = scopetable->previousTryLevel;
|
||
|
|
||
|
// Call the _except {} block. Never returns.
|
||
|
pRegistrationFrame->scopetable[trylevel].lpfnHandler();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
scopeTable = pRegistrationFrame->scopetable;
|
||
|
trylevel = scopeTable->previousTryLevel
|
||
|
|
||
|
goto search_for_handler;
|
||
|
}
|
||
|
else // trylevel == TRYLEVEL_NONE
|
||
|
{
|
||
|
retvalue == DISPOSITION_CONTINUE_SEARCH;
|
||
|
}
|
||
|
}
|
||
|
else // EXCEPTION_UNWINDING or EXCEPTION_EXIT_UNWIND flags are set
|
||
|
{
|
||
|
PUSH EBP // Save EBP
|
||
|
|
||
|
EBP = pRegistrationFrame->_ebp // Set EBP for __local_unwind2
|
||
|
|
||
|
__local_unwind2( pRegistrationFrame, TRYLEVEL_NONE )
|
||
|
|
||
|
POP EBP // Restore EBP
|
||
|
|
||
|
retvalue == DISPOSITION_CONTINUE_SEARCH;
|
||
|
}
|
||
|
}
|
||
|
|