📄 exdsptch.c
字号:
// If the registration pointer is equal to the target frame
// pointer, then continue execution. Otherwise, an exit unwind was
// performed or the target of the unwind did not exist and the
// debugger and subsystem are given a second chance to handle the
// unwind.
if ((TargetFrame && RegistrationPointer == TargetFrame)
|| (TargetCStk && pcstk == TargetCStk)) {
DEBUGMSG(ZONE_SEH, (TEXT("NKUnwind: continuing @%8.8lx\r\n"),
CONTEXT_TO_PROGRAM_COUNTER(ContextRecord)));
return TRUE;
}
return FALSE;
}
#endif
#ifndef x86
extern void MD_CBRtn (void);
extern void MDRestoreCalleeSavedRegisters (PCALLSTACK pcstk, PCONTEXT pCtx);
#if MIPS
#define COMBINED_PDATA // define to enable combined pdata format
#define INST_SIZE 4
#define STK_ALIGN 0x7
#define RetValue IntV0
#define RESTORE_EXTRA_INFO(Context, extra) ((Context)->IntGp = (extra))
#define FIXTOC(Context)
#endif
#if SHx
#define COMPRESSED_PDATA // define to enable compressed pdata format
#define INST_SIZE 2
#define STK_ALIGN 0x3
#define IntRa PR
#define IntSp R15
#define RetValue R0
#define RESTORE_EXTRA_INFO(Context, extra)
#define FIXTOC(Context)
#endif
#if ARM
#define COMPRESSED_PDATA // define to enable compressed pdata format
#define INST_SIZE 4
#define STK_ALIGN 0x3
#define IntRa Lr
#define IntSp Sp
#define RetValue R0
#define RESTORE_EXTRA_INFO(Context, extra) ((Context)->R9 = (extra))
#define FIXTOC(Context)
#endif
#ifdef INST_SIZE
//
// Define private function prototypes.
//
ULONG
RtlpVirtualUnwind(
IN ULONG ControlPc,
IN PRUNTIME_FUNCTION FunctionEntry,
IN PCONTEXT ContextRecord,
OUT PBOOLEAN InFunction,
OUT PULONG EstablisherFrame);
EXCEPTION_DISPOSITION RtlpExecuteHandlerForException(
IN PEXCEPTION_RECORD ExceptionRecord,
IN ULONG EstablisherFrame,
IN OUT PCONTEXT ContextRecord,
IN OUT PDISPATCHER_CONTEXT DispatcherContext,
IN PEXCEPTION_ROUTINE ExceptionRoutine,
IN OUT PCALLSTACK pcstk,
IN ULONG ExceptionMode);
EXCEPTION_DISPOSITION RtlpExecuteHandlerForUnwind(
IN PEXCEPTION_RECORD ExceptionRecord,
IN ULONG EstablisherFrame,
IN OUT PCONTEXT ContextRecord,
IN OUT PDISPATCHER_CONTEXT DispatcherContext,
IN PEXCEPTION_ROUTINE ExceptionRoutine,
IN OUT PCALLSTACK pcstk);
BOOLEAN NKUnwind(
IN PTHREAD pth,
IN PCALLSTACK TargetCStk OPTIONAL,
IN ULONG TargetFrame OPTIONAL,
IN ULONG TargetIp OPTIONAL,
IN PEXCEPTION_RECORD ExceptionRecord,
IN ULONG ReturnValue,
IN PCONTEXT ContextRecord,
IN PCALLSTACK NewStkTop);
PRUNTIME_FUNCTION NKLookupFunctionEntry(
IN PPROCESS pProc,
IN ULONG ControlPc,
PRUNTIME_FUNCTION prf);
void UpdateASID(IN PTHREAD pth, IN PPROCESS pProc, IN ACCESSKEY aky);
extern EXCEPTION_ROUTINE KPSLExceptionRoutine;
#if defined(COMPRESSED_PDATA) || defined(COMBINED_PDATA)
typedef struct PDATA {
ULONG pFuncStart;
ULONG PrologLen : 8; // low order bits
ULONG FuncLen : 22; // high order bits
ULONG ThirtyTwoBits : 1; // 0/1 == 16/32 bit instructions
ULONG ExceptionFlag : 1; // highest bit
} PDATA, *PPDATA;
#endif
typedef struct PDATA_EH {
PEXCEPTION_ROUTINE pHandler;
PVOID pHandlerData;
} PDATA_EH, *PPDATA_EH;
#if defined(COMBINED_PDATA)
typedef struct COMBINED_HEADER {
DWORD zero1; // must be zero if header present
DWORD zero2; // must be zero if header present
DWORD Uncompressed; // count of uncompressed entries
DWORD Compressed; // count of compressed entries
} COMBINED_HEADER, *PCOMBINED_HEADER;
#endif
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOLEAN
NKDispatchException(
IN PTHREAD pth,
IN PEXCEPTION_RECORD ExceptionRecord,
IN PCONTEXT ContextRecord
)
/*++
Routine Description:
This function attempts to dispatch an exception to a frame based
handler by searching backwards through the stack based call frames.
The search begins with the frame specified in the context record and
continues backward until either a handler is found that handles the
exception, the stack is found to be invalid (i.e., out of limits or
unaligned), or the end of the call hierarchy is reached.
As each frame is encounter, the PC where control left the corresponding
function is determined and used to lookup exception handler information
in the runtime function table built by the linker. If the respective
routine has an exception handler, then the handler is called. If the
handler does not handle the exception, then the prologue of the routine
is executed backwards to "unwind" the effect of the prologue and then
the next frame is examined.
Arguments:
pth - Supplies a pointer to thread structure
ExceptionRecord - Supplies a pointer to an exception record.
ContextRecord - Supplies a pointer to a context record.
Return Value:
If the exception is handled by one of the frame based handlers, then
a value of TRUE is returned. Otherwise a value of FALSE is returned.
--*/
{
CONTEXT ContextRecord1;
CONTEXT LocalContext;
PCONTEXT OriginalContext;
ULONG ControlPc;
DISPATCHER_CONTEXT DispatcherContext;
EXCEPTION_DISPOSITION Disposition;
ULONG EstablisherFrame;
ULONG ExceptionFlags;
PRUNTIME_FUNCTION FunctionEntry;
BOOLEAN InFunction;
BOOLEAN Handled;
ULONG HighLimit;
ULONG LowLimit;
ULONG NestedFrame;
ULONG NextPc;
ULONG PrevSp;
PCALLSTACK pcstk, pcstkForHandler;
PCALLSTACK TargetCStk;
PPROCESS pprcSave;
ACCESSKEY akySave;
RUNTIME_FUNCTION TempFunctionEntry;
LPDWORD tlsSave;
// Get current stack limits, copy the context record, get the initial
// PC value, capture the exception flags, and set the nested exception
// frame pointer.
NKGetStackLimits(pth, &LowLimit, &HighLimit);
//
// Redirect ContextRecord to a local copy of the incoming context. The
// exception dispatch process modifies the PC of this context. Unwinding
// of nested exceptions will fail when unwinding through CaptureContext
// with a modified PC.
//
OriginalContext = ContextRecord;
ContextRecord = &LocalContext;
memcpy(ContextRecord, OriginalContext, sizeof(CONTEXT));
memcpy(&ContextRecord1, ContextRecord, sizeof(CONTEXT));
ControlPc = CONTEXT_TO_PROGRAM_COUNTER(&ContextRecord1);
ExceptionFlags = ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE;
NestedFrame = 0;
pcstk = pth->pcstkTop;
akySave = pth->aky;
pprcSave = pCurProc;
tlsSave = pth->tlsPtr;
// Start with the frame specified by the context record and search
// backwards through the call frame hierarchy attempting to find an
// exception handler that will handle the exception.
do {
// Lookup the function table entry using the point at which control
// left the procedure.
DEBUGMSG(ZONE_SEH, (TEXT("NKDispatchException(%08x): Proc=%8.8lx ControlPc=%8.8lx SP=%8.8lx, PSR = %8.8lx\r\n"),
ContextRecord, pCurProc, ControlPc, ContextRecord1.IntSp, ContextRecord1.Psr));
PrevSp = (ULONG) ContextRecord1.IntSp;
TargetCStk = 0;
ControlPc = ZeroPtr(ControlPc);
FunctionEntry = NKLookupFunctionEntry(pCurProc, ControlPc, &TempFunctionEntry);
// If there is a function table entry for the routine, then virtually
// unwind to the caller of the current routine to obtain the virtual
// frame pointer of the establisher and check if there is an exception
// handler for the frame.
if (FunctionEntry != NULL) {
NextPc = RtlVirtualUnwind(ControlPc,
FunctionEntry,
&ContextRecord1,
&InFunction,
&EstablisherFrame,
pCurProc);
// If the virtual frame pointer is not within the specified stack
// limits or the virtual frame pointer is unaligned, then set the
// stack invalid flag in the exception record and return exception
// not handled. Otherwise, check if the current routine has an
// exception handler.
if ((EstablisherFrame < LowLimit)
|| (EstablisherFrame > HighLimit)
|| ((EstablisherFrame & STK_ALIGN) != 0)) {
DEBUGMSG(ZONE_SEH, (TEXT("NKDispatchException: Bad stack frame=%8.8lx Low=%8.8lx High=%8.8lx\r\n"),
EstablisherFrame, LowLimit, HighLimit));
ExceptionFlags |= EXCEPTION_STACK_INVALID;
break;
} else if ((FunctionEntry->ExceptionHandler != NULL) && InFunction) {
// The frame has an exception handler. The handler must be
// executed by calling another routine that is written in
// assembler. This is required because up level addressing
// of the handler information is required when a nested
// exception is encountered.
invokeHandler:
DispatcherContext.ControlPc = ControlPc;
DispatcherContext.FunctionEntry = FunctionEntry;
DispatcherContext.EstablisherFrame = EstablisherFrame;
DispatcherContext.ContextRecord = ContextRecord;
ExceptionRecord->ExceptionFlags = ExceptionFlags;
DEBUGMSG(ZONE_SEH, (TEXT("Calling exception handler @%8.8lx(%8.8lx) Frame=%8.8lx\r\n"),
FunctionEntry->ExceptionHandler, FunctionEntry->HandlerData,
EstablisherFrame));
pcstkForHandler = 0;
if (KERNEL_MODE != GetContextMode (&ContextRecord1)) {
if (!(pcstkForHandler = (PCALLSTACK) AllocMem (HEAP_CALLSTACK))) {
// we're completely out of memory, can't do much about it
ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
break;
}
SetupCSTK (pcstkForHandler);
}
Disposition = RtlpExecuteHandlerForException(ExceptionRecord,
EstablisherFrame, ContextRecord, &DispatcherContext,
FunctionEntry->ExceptionHandler, pcstkForHandler, ContextRecord1.Psr);
// don't need to free pcstkForHandler since it'll be freed at callback return
ExceptionFlags |=
(ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE);
DEBUGMSG(ZONE_SEH, (TEXT("exception dispostion = %d\r\n"), Disposition));
// If the current scan is within a nested context and the frame
// just examined is the end of the nested region, then clear
// the nested context frame and the nested exception flag in
// the exception flags.
if (NestedFrame == EstablisherFrame) {
ExceptionFlags &= (~EXCEPTION_NESTED_CALL);
NestedFrame = 0;
}
// Case on the handler disposition.
switch (Disposition) {
// The disposition is to execute a frame based handler. The
// target handler address is in DispatcherContext.ControlPc.
// Reset to the original context and switch to unwind mode.
case ExceptionExecuteHandler:
DEBUGMSG(ZONE_SEH, (TEXT("Unwinding to %8.8lx Frame=%8.8lx\r\n"),
DispatcherContext.ControlPc, EstablisherFrame));
KPlpvTls = pth->tlsPtr = tlsSave;
UpdateASID(pth, pprcSave, akySave);
Handled = NKUnwind(pth, TargetCStk, EstablisherFrame,
DispatcherContext.ControlPc, ExceptionRecord,
ExceptionRecord->ExceptionCode, ContextRecord, pcstk);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -