📄 exdsptch.c
字号:
/*++Copyright (c) 1990-2000 Microsoft Corporation. All rights reserved.Module Name: exdsptch.cAbstract: 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)BOOLEANNKDispatchException( 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;}BOOLEANNKUnwind( 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)/*++Routine Description: This function initiates an unwind of procedure call frames. The machine state at the time of the call to unwind is captured in a context record
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -