197 lines
5.6 KiB
C
197 lines
5.6 KiB
C
/*****************************************************************************
|
|
*
|
|
* Seh.c
|
|
*
|
|
* Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* Abstract:
|
|
*
|
|
* Structured exception handling.
|
|
*
|
|
*****************************************************************************/
|
|
#ifdef _M_IX86
|
|
#include <windows.h>
|
|
#include <sehcall.h>
|
|
|
|
typedef void *PV;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* SEHFRAME
|
|
*
|
|
* Special stack frame used by lightweight structured exception
|
|
* handling.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
typedef struct SEHFRAME {
|
|
|
|
PV pvSEH; /* Link to previous frame */
|
|
FARPROC Handler; /* MyExceptionFilter */
|
|
FARPROC sehTarget; /* Where to jump on error */
|
|
INEXCEPTION InException; /* In-exception handler */
|
|
|
|
} SEHFRAME, *PSEHFRAME;
|
|
|
|
/***************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func BOOL | _MyExceptionFilter |
|
|
*
|
|
* My tiny exception filter.
|
|
*
|
|
* @parm LPEXCEPTION_RECORD | pExceptionRecord |
|
|
*
|
|
* Exception record describing why we were called.
|
|
*
|
|
* @parm PV | EstablisherFrame |
|
|
*
|
|
* The exception frame (pNext, pHandler)
|
|
* on the stack which is being handled. This is used so that
|
|
* the handler can access its local variables and knows how
|
|
* far to smash the stack if the exception is being eaten.
|
|
*
|
|
* @parm PCONTEXT | pContextRecord |
|
|
*
|
|
* Client context at time of exception.
|
|
*
|
|
* @parm PV | DispatcherContext |
|
|
*
|
|
* Not used. Which is good, because I don't know what it means.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#define EXCEPTION_UNWINDING 0x00000002
|
|
#define EXCEPTION_EXIT_UNWIND 0x00000004
|
|
|
|
WINBASEAPI void WINAPI
|
|
RtlUnwind(PV TargetFrame, PV TargetIp, PEXCEPTION_RECORD per, PV ReturnValue);
|
|
|
|
EXCEPTION_DISPOSITION
|
|
__cdecl
|
|
_MyExceptionFilter(
|
|
LPEXCEPTION_RECORD pExceptionRecord,
|
|
PV EstablisherFrame,
|
|
PCONTEXT pContextRecord,
|
|
PV DispatcherContext
|
|
)
|
|
{
|
|
DispatcherContext;
|
|
pContextRecord;
|
|
|
|
/* Don't interfere with an unwind */
|
|
if ((pExceptionRecord->ExceptionFlags &
|
|
(EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) == 0) {
|
|
PSEHFRAME pseh = EstablisherFrame;
|
|
BOOL fRc = pseh->InException(pExceptionRecord, pContextRecord);
|
|
|
|
/*
|
|
* RtlUnwind will tell all exception frames that may have
|
|
* been created underneath us that they are about to be
|
|
* blown away and should do their __finally handling.
|
|
*
|
|
* On return, the nested frames have been unlinked.
|
|
*/
|
|
RtlUnwind(EstablisherFrame, 0, 0, 0);
|
|
|
|
/*
|
|
* And jump back to the caller. It is the caller's
|
|
* responsibility to restore nonvolatile registers!
|
|
*
|
|
* We also assume that the caller has nothing on the
|
|
* stack beneath the exception record!
|
|
*
|
|
* And the handler address is right after the exception
|
|
* record!
|
|
*/
|
|
__asm {
|
|
mov eax, fRc; /* Get return value */
|
|
mov esp, EstablisherFrame; /* Restore ESP */
|
|
// jmp [esp].sehTarget; /* Back to CallWithSEH */
|
|
|
|
//We should be doing the above, but it faults VC4.2. Gotta love it.
|
|
|
|
jmp DWORD ptr [esp+8]
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* We are unwinding. Don't interfere.
|
|
*/
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func DWORD | CallWithSEH |
|
|
*
|
|
* Call the function with an exception frame active.
|
|
*
|
|
* If the procedure raises an exception, then call
|
|
* InException and propagate whatever InException returns.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#pragma warning(disable:4035) /* no return value (duh) */
|
|
|
|
__declspec(naked) DWORD WINAPI
|
|
CallWithSEH(EXCEPTPROC pfn, PV pv, INEXCEPTION InException)
|
|
{
|
|
__asm {
|
|
|
|
/* Function prologue */
|
|
push ebp;
|
|
mov ebp, esp; /* To keep C compiler happy */
|
|
push ebx;
|
|
push edi;
|
|
push esi;
|
|
|
|
/*
|
|
* Build a SEHFRAME.
|
|
*/
|
|
push InException; /* What to handle */
|
|
push offset Exit; /* Where to go on error */
|
|
|
|
xor edx, edx; /* Keep zero handy */
|
|
push offset _MyExceptionFilter; /* My handler */
|
|
push dword ptr fs:[edx]; /* Build frame */
|
|
mov fs:[edx], esp; /* Link in */
|
|
}
|
|
|
|
pfn(pv); /* Call the victim */
|
|
|
|
__asm {
|
|
/*
|
|
* The validation layer jumps here (all registers in a random
|
|
* state except for ESP) if something went wrong.
|
|
*
|
|
* We don't need to restore nonvolatile registers now;
|
|
* that will be done as part of the procedure exit.
|
|
*/
|
|
Exit:;
|
|
|
|
xor edx, edx; /* Keep zero handy */
|
|
pop dword ptr fs:[edx]; /* Remove frame */
|
|
|
|
/*
|
|
* Discard MyExceptionFilter, Exit, and InException.
|
|
*/
|
|
add esp, 12;
|
|
|
|
pop esi;
|
|
pop edi;
|
|
pop ebx;
|
|
pop ebp;
|
|
ret 12;
|
|
}
|
|
|
|
}
|
|
|
|
#pragma warning(default:4035)
|
|
|
|
#endif
|