📄 exdsptch.c
字号:
/*++
Copyright (c) 1990-2000 Microsoft Corporation. All rights reserved.
Module Name:
exdsptch.c
Abstract:
This module implements the dispatching of exception and the unwinding of
procedure call frames.
--*/
#include "kernel.h"
#include "excpt.h"
//
// Define local macros.
//
// Raise noncontinuable exception with associated exception record.
//
#if 0
#define RAISE_EXCEPTION(Status, ExceptionRecordt) { \
EXCEPTION_RECORD ExceptionRecordn; \
\
ExceptionRecordn.ExceptionCode = Status; \
ExceptionRecordn.ExceptionFlags = EXCEPTION_NONCONTINUABLE; \
ExceptionRecordn.ExceptionRecord = ExceptionRecordt; \
ExceptionRecordn.NumberParameters = 0; \
RtlRaiseException(&ExceptionRecordn); \
}
#else
#define RAISE_EXCEPTION(Status, ExceptionRecordt) DEBUGCHK(0)
#endif
// Obtain current stack limits
#define NKGetStackLimits(pth, LL, HL) \
((*(LL) = (pth)->dwStackBase), (*(HL) = (ULONG)(pth)->tlsPtr))
#ifdef x86
#define EXCEPTION_CHAIN_END ((PEXCEPTION_REGISTRATION_RECORD)-1)
//
// Define private function prototypes.
//
EXCEPTION_DISPOSITION RtlpExecuteHandlerForException(
IN PEXCEPTION_RECORD ExceptionRecord,
IN PVOID EstablisherFrame,
IN OUT PCONTEXT ContextRecord,
IN OUT PDISPATCHER_CONTEXT DispatcherContext,
IN PEXCEPTION_ROUTINE ExceptionRoutine,
IN ULONG ExceptionMode);
EXCEPTION_DISPOSITION RtlpExecuteHandlerForUnwind(
IN PEXCEPTION_RECORD ExceptionRecord,
IN PVOID EstablisherFrame,
IN OUT PCONTEXT ContextRecord,
IN OUT PDISPATCHER_CONTEXT DispatcherContext,
IN PEXCEPTION_ROUTINE ExceptionRoutine,
IN ULONG ExceptionMode);
BOOLEAN NKUnwind(
IN PTHREAD pth,
IN PCALLSTACK TargetCStk OPTIONAL,
IN PEXCEPTION_REGISTRATION_RECORD TargetFrame OPTIONAL,
IN ULONG TargetIp OPTIONAL,
IN PEXCEPTION_RECORD ExceptionRecord,
IN ULONG ReturnValue,
IN PCONTEXT ContextRecord);
void UpdateASID(IN PTHREAD pth, IN PPROCESS pProc, IN ACCESSKEY aky);
extern EXCEPTION_ROUTINE KPSLExceptionRoutine;
void __inline StoreRegistrationPointer(void *RegistrationPointer)
{
__asm {
mov eax, [RegistrationPointer]
mov dword ptr fs:[0], eax
}
}
#pragma warning(disable:4035)
PVOID __inline GetRegistrationHead(void)
{
__asm mov eax, dword ptr fs:[0];
}
#pragma warning(default:4035)
BOOLEAN
NKDispatchException(
IN PTHREAD pth,
IN PEXCEPTION_RECORD ExceptionRecord,
IN PCONTEXT ContextRecord)
{
EXCEPTION_DISPOSITION Disposition;
PEXCEPTION_REGISTRATION_RECORD RegistrationPointer;
PEXCEPTION_REGISTRATION_RECORD NestedRegistration;
DISPATCHER_CONTEXT DispatcherContext;
UINT HighAddress;
UINT HighLimit;
UINT LowLimit;
PCALLSTACK pcstk;
PCALLSTACK TargetCStk;
PPROCESS pProc;
PPROCESS pprcSave;
ACCESSKEY akySave;
EXCEPTION_REGISTRATION_RECORD TempRegistration;
CONTEXT ContextRecord1;
// Get current stack limits
NKGetStackLimits(pth, &LowLimit, &HighLimit);
DEBUGMSG(ZONE_SEH, (TEXT("X86 DispatchException(%x %x) pc %x code %x address %x\r\n"),
ExceptionRecord, ContextRecord, ContextRecord->Eip,
ExceptionRecord->ExceptionCode, ExceptionRecord->ExceptionAddress));
pcstk = pth->pcstkTop;
akySave = pth->aky;
pprcSave = pCurProc;
memcpy(&ContextRecord1, ContextRecord, sizeof(CONTEXT));
/*
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 handler the exception.
*/
RegistrationPointer = GetRegistrationHead();
NestedRegistration = 0;
TargetCStk = 0;
while (RegistrationPointer && RegistrationPointer != EXCEPTION_CHAIN_END) {
// Check for PSL call boundary.
DEBUGMSG(ZONE_SEH, (TEXT("NKDispatchException: Proc=%8.8lx RP=%8.8lx\r\n"),
pCurProc, RegistrationPointer));
while (RegistrationPointer == (PEXCEPTION_REGISTRATION_RECORD)-2) {
PEXCEPTION_ROUTINE pEH = KPSLExceptionRoutine;
if (!pcstk) {
RETAILMSG(1, (TEXT("NKDispatchException: no CALLSTACK with RP=%d\r\n"),
RegistrationPointer));
break;
}
// in a PSL call.
pProc = pcstk->pprcLast;
if (!TargetCStk && pcstk->akyLast && ((ulong)pProc < 0x10000
|| (pEH = pCurProc->pfnEH) != 0)) {
TargetCStk = pcstk;
RegistrationPointer = &TempRegistration;
RegistrationPointer->Next = (PEXCEPTION_REGISTRATION_RECORD)-2;
RegistrationPointer->Handler = pEH;
break;
} else {
TargetCStk = 0;
RegistrationPointer = (PEXCEPTION_REGISTRATION_RECORD)pcstk->extra;
if ((ulong)pProc < 0x10000) {
/* This call is returning from kernel mode server. Restore
* the thread's previous operating mode and return.
*/
SetContextMode(&ContextRecord1, (ULONG)pProc);
} else {
/* Returning from a user mode server, restore the previous
* address space information and return.
*/
UpdateASID(pth, pProc, pcstk->akyLast ? pcstk->akyLast : pth->aky);
}
pcstk = pcstk->pcstkNext;
DEBUGMSG(ZONE_SEH, (TEXT("NKDispatchException: PSL return Proc=%8.8lx RP=%8.8lx pcstk=%8.8lx\r\n"),
pProc, RegistrationPointer, pcstk));
}
}
/*
If the call frame is not within the specified stack limits or the
call frame is unaligned, then set the stack invalid flag in the
exception record and return FALSE. Else check to determine if the
frame has an exception handler.
*/
HighAddress = (UINT)RegistrationPointer + sizeof(EXCEPTION_REGISTRATION_RECORD);
if ((UINT)RegistrationPointer < LowLimit || HighAddress > HighLimit
|| ((UINT)RegistrationPointer & 0x3) != 0) { /* Not aligned */
ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
break;
} else {
/* 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.
*/
DispatcherContext.ControlPc = 0;
DispatcherContext.RegistrationPointer = RegistrationPointer;
DEBUGMSG(1, (TEXT("Calling exception handler @%8.8lx RP=%8.8lx\r\n"),
RegistrationPointer->Handler, RegistrationPointer));
Disposition = RtlpExecuteHandlerForException(ExceptionRecord,
RegistrationPointer, ContextRecord, &DispatcherContext,
RegistrationPointer->Handler, GetContextMode(&ContextRecord1));
DEBUGMSG(1, (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 context region, then clear
the nested context frame and the nested exception in the
exception flags.
*/
if (NestedRegistration == RegistrationPointer) {
ExceptionRecord->ExceptionFlags &= (~EXCEPTION_NESTED_CALL);
NestedRegistration = 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 && DispatcherContext.ControlPc,
(TEXT("Unwinding to %8.8lx RegistrationPointer=%8.8lx\r\n"),
DispatcherContext.ControlPc, RegistrationPointer));
DEBUGMSG(ZONE_SEH && !DispatcherContext.ControlPc,
(TEXT("Unwinding to %8.8lx RegistrationPointer=%8.8lx Ebx=%8.8lx Esi=%d\r\n"),
ContextRecord->Eip, RegistrationPointer,
ContextRecord->Ebx, ContextRecord->Esi));
UpdateASID(pth, pprcSave, akySave);
// Repair the CONTEXT for PSL handlers.
if (TargetCStk) {
ContextRecord->Esp = TargetCStk->ExEsp;
ContextRecord->Ebp = TargetCStk->ExEbp;
ContextRecord->Ebx = TargetCStk->ExEbx;
ContextRecord->Esi = TargetCStk->ExEsi;
ContextRecord->Edi = TargetCStk->ExEdi;
}
return NKUnwind(pth, TargetCStk, RegistrationPointer,
DispatcherContext.ControlPc, ExceptionRecord,
ExceptionRecord->ExceptionCode, ContextRecord);
/* The disposition is to continue execution. If the
exception is not continuable, then raise the exception
EXC_NONCONTINUABLE_EXCEPTION. Otherwise return
TRUE. */
case ExceptionContinueExecution :
if ((ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) != 0) {
RAISE_EXCEPTION(STATUS_INVALID_DISPOSITION, ExceptionRecord);
break;
} else {
UpdateASID(pth, pprcSave, akySave);
return TRUE;
}
/*
The disposition is to continue the search. Get next
frame address and continue the search.
*/
case ExceptionContinueSearch :
break;
/*
The disposition is nested exception. Set the nested
context frame to the establisher frame address and set
nested exception in the exception flags.
*/
case ExceptionNestedException :
ExceptionRecord->ExceptionFlags |= EXCEPTION_NESTED_CALL;
if (DispatcherContext.RegistrationPointer > NestedRegistration){
NestedRegistration = DispatcherContext.RegistrationPointer;
}
break;
/*
All other disposition values are invalid. Raise
invalid disposition exception.
*/
default :
RETAILMSG(1, (TEXT("NKDispatchException: invalid dispositon (%d)\r\n"),
Disposition));
RAISE_EXCEPTION(STATUS_INVALID_DISPOSITION, ExceptionRecord);
break;
}
RegistrationPointer = RegistrationPointer->Next;
}
}
DEBUGMSG(ZONE_SEH, (TEXT("NKDispatchException: ran out of exceptions pc=%x code=%x\n"),
ContextRecord1.Eip, ExceptionRecord->ExceptionCode));
RAISE_EXCEPTION(STATUS_INVALID_DISPOSITION, ExceptionRecord);
UpdateASID(pth, pprcSave, akySave);
return FALSE;
}
BOOLEAN
NKUnwind(
IN PTHREAD pth,
IN PCALLSTACK TargetCStk OPTIONAL,
IN PEXCEPTION_REGISTRATION_RECORD TargetFrame OPTIONAL,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -