📄 exdsptch.c
字号:
IN PEXCEPTION_ROUTINE ExceptionRoutine);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);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;#endiftypedef 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;#endifBOOLEANNKDispatchException( 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; PCALLSTACK TargetCStk; PPROCESS pprcSave; ACCESSKEY akySave; RUNTIME_FUNCTION TempFunctionEntry; // // 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)); // 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); 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; // 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\r\n"),ContextRecord, pCurProc, ControlPc, ContextRecord1.IntSp)); PrevSp = 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); // 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(1, (TEXT("Calling exception handler @%8.8lx(%8.8lx) Frame=%8.8lx\r\n"), FunctionEntry->ExceptionHandler, FunctionEntry->HandlerData, EstablisherFrame)); Disposition = RtlpExecuteHandlerForException(ExceptionRecord, EstablisherFrame, ContextRecord, &DispatcherContext, FunctionEntry->ExceptionHandler, ContextRecord1.Psr); ExceptionFlags |= (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE); 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 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)); UpdateASID(pth, pprcSave, akySave); Handled = NKUnwind(pth, TargetCStk, EstablisherFrame, DispatcherContext.ControlPc, ExceptionRecord, ExceptionRecord->ExceptionCode, ContextRecord); memcpy(OriginalContext, ContextRecord, sizeof(CONTEXT)); return Handled; // The disposition is to continue execution. // If the exception is not continuable, then raise the // exception STATUS_NONCONTINUABLE_EXCEPTION. Otherwise // return exception handled. case ExceptionContinueExecution : DEBUGMSG(ZONE_SEH, (TEXT("Continuing execution ...\r\n"))); if ((ExceptionFlags & EXCEPTION_NONCONTINUABLE) != 0) RAISE_EXCEPTION(STATUS_NONCONTINUABLE_EXCEPTION, ExceptionRecord); UpdateASID(pth, pprcSave, akySave); memcpy(OriginalContext, ContextRecord, sizeof(CONTEXT)); 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 the nested exception flag in the // exception flags. case ExceptionNestedException : DEBUGMSG(ZONE_SEH, (TEXT("Nested exception: frame=%8.8lx\r\n"), DispatcherContext.EstablisherFrame)); ExceptionFlags |= EXCEPTION_NESTED_CALL; if (DispatcherContext.EstablisherFrame > NestedFrame) NestedFrame = DispatcherContext.EstablisherFrame; 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); } } else { if (NextPc != ControlPc) PrevSp = 0; // don't terminate loop because sp didn't change. } } else { // Set point at which control left the previous routine. NextPc = ContextRecord1.IntRa - INST_SIZE; PrevSp = 0; // don't terminate loop because sp didn't change. // If the next control PC is the same as the old control PC, then // the function table is not correctly formed. if (NextPc == ControlPc) break; } // Set point at which control left the previous routine. ControlPc = NextPc; if (pcstk && (ControlPc == SYSCALL_RETURN || ControlPc+INST_SIZE == SYSCALL_RETURN || ControlPc == DIRECT_RETURN || ControlPc+INST_SIZE == DIRECT_RETURN)) { // Server IPC return. If the server process has registered an // exception handler, the call that handler before unwinding // in the calling process. PPROCESS pProc = pcstk->pprcLast; PEXCEPTION_ROUTINE pEH = KPSLExceptionRoutine; if (TargetCStk == 0 && pcstk->akyLast && ((ulong)pProc < 0x10000 || (pEH = pCurProc->pfnEH) != 0)) { TargetCStk = pcstk; FunctionEntry = &TempFunctionEntry; FunctionEntry->ExceptionHandler = pEH; FunctionEntry->BeginAddress = 0; FunctionEntry->EndAddress = 0; FunctionEntry->HandlerData = 0; EstablisherFrame = 0; goto invokeHandler; } // Update the return address and process context // information from the thread's call stack list. ContextRecord1.IntRa = (ULONG)pcstk->retAddr; RESTORE_EXTRA_INFO(&ContextRecord1, 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); } ControlPc = ContextRecord1.IntRa - INST_SIZE; DEBUGMSG(ZONE_SEH, (TEXT("NKDispatchException: PSL ret=%8.8lx\r\n"), ContextRecord1.IntRa)); pcstk = pcstk->pcstkNext; } } while (ContextRecord1.IntSp < HighLimit && ContextRecord1.IntSp > PrevSp); // Set final exception flags and return exception not handled. DEBUGMSG(1, (TEXT("NKDispatchException: returning failure. Flags=%x\r\n"), ExceptionFlags)); UpdateASID(pth, pprcSave, akySave); ExceptionRecord->ExceptionFlags = ExceptionFlags; memcpy(OriginalContext, ContextRecord, sizeof(CONTEXT)); return FALSE;}#if defined(COMPRESSED_PDATA)PRUNTIME_FUNCTION
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -