/* * @implemented */ VOID NTAPI RtlRaiseException(IN PEXCEPTION_RECORD ExceptionRecord) { CONTEXT Context; NTSTATUS Status; /* Capture the context */ RtlCaptureContext(&Context); /* Save the exception address */ ExceptionRecord->ExceptionAddress = _ReturnAddress(); /* Write the context flag */ Context.ContextFlags = CONTEXT_FULL; /* Check if user mode debugger is active */ if (RtlpCheckForActiveDebugger()) { /* Raise an exception immediately */ Status = ZwRaiseException(ExceptionRecord, &Context, TRUE); } else { /* Dispatch the exception and check if we should continue */ if (!RtlDispatchException(ExceptionRecord, &Context)) { /* Raise the exception */ Status = ZwRaiseException(ExceptionRecord, &Context, FALSE); } else { /* Continue, go back to previous context */ Status = ZwContinue(&Context, FALSE); } } /* If we returned, raise a status */ RtlRaiseStatus(Status); }
/* * @implemented */ VOID NTAPI RtlRaiseStatus(IN NTSTATUS Status) { EXCEPTION_RECORD ExceptionRecord; CONTEXT Context; /* Capture the context */ RtlCaptureContext(&Context); /* Create an exception record */ ExceptionRecord.ExceptionAddress = _ReturnAddress(); ExceptionRecord.ExceptionCode = Status; ExceptionRecord.ExceptionRecord = NULL; ExceptionRecord.NumberParameters = 0; ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE; /* Write the context flag */ Context.ContextFlags = CONTEXT_FULL; /* Check if user mode debugger is active */ if (RtlpCheckForActiveDebugger()) { /* Raise an exception immediately */ ZwRaiseException(&ExceptionRecord, &Context, TRUE); } else { /* Dispatch the exception */ RtlDispatchException(&ExceptionRecord, &Context); /* Raise exception if we got here */ Status = ZwRaiseException(&ExceptionRecord, &Context, FALSE); } /* If we returned, raise a status */ RtlRaiseStatus(Status); }
/* * @implemented */ VOID NTAPI RtlUnwind(IN PVOID TargetFrame OPTIONAL, IN PVOID TargetIp OPTIONAL, IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL, IN PVOID ReturnValue) { PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, OldFrame; DISPATCHER_CONTEXT DispatcherContext; EXCEPTION_RECORD ExceptionRecord2, ExceptionRecord3; EXCEPTION_DISPOSITION Disposition; ULONG_PTR StackLow, StackHigh; ULONG_PTR RegistrationFrameEnd; CONTEXT LocalContext; PCONTEXT Context; /* Get the current stack limits */ RtlpGetStackLimits(&StackLow, &StackHigh); /* Check if we don't have an exception record */ if (!ExceptionRecord) { /* Overwrite the argument */ ExceptionRecord = &ExceptionRecord3; /* Setup a local one */ ExceptionRecord3.ExceptionFlags = 0; ExceptionRecord3.ExceptionCode = STATUS_UNWIND; ExceptionRecord3.ExceptionRecord = NULL; ExceptionRecord3.ExceptionAddress = _ReturnAddress(); ExceptionRecord3.NumberParameters = 0; } /* Check if we have a frame */ if (TargetFrame) { /* Set it as unwinding */ ExceptionRecord->ExceptionFlags |= EXCEPTION_UNWINDING; } else { /* Set the Exit Unwind flag as well */ ExceptionRecord->ExceptionFlags |= (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND); } /* Now capture the context */ Context = &LocalContext; LocalContext.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS; RtlpCaptureContext(Context); /* Pop the current arguments off */ Context->Esp += sizeof(TargetFrame) + sizeof(TargetIp) + sizeof(ExceptionRecord) + sizeof(ReturnValue); /* Set the new value for EAX */ Context->Eax = (ULONG)ReturnValue; /* Get the current frame */ RegistrationFrame = RtlpGetExceptionList(); /* Now loop every frame */ while (RegistrationFrame != EXCEPTION_CHAIN_END) { /* Registration chain entries are never NULL */ ASSERT(RegistrationFrame != NULL); /* If this is the target */ if (RegistrationFrame == TargetFrame) ZwContinue(Context, FALSE); /* Check if the frame is too low */ if ((TargetFrame) && ((ULONG_PTR)TargetFrame < (ULONG_PTR)RegistrationFrame)) { /* Create an invalid unwind exception */ ExceptionRecord2.ExceptionCode = STATUS_INVALID_UNWIND_TARGET; ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; ExceptionRecord2.ExceptionRecord = ExceptionRecord; ExceptionRecord2.NumberParameters = 0; /* Raise the exception */ RtlRaiseException(&ExceptionRecord2); } /* Find out where it ends */ RegistrationFrameEnd = (ULONG_PTR)RegistrationFrame + sizeof(EXCEPTION_REGISTRATION_RECORD); /* Make sure the registration frame is located within the stack */ if ((RegistrationFrameEnd > StackHigh) || ((ULONG_PTR)RegistrationFrame < StackLow) || ((ULONG_PTR)RegistrationFrame & 0x3)) { /* Check if this happened in the DPC Stack */ if (RtlpHandleDpcStackException(RegistrationFrame, RegistrationFrameEnd, &StackLow, &StackHigh)) { /* Use DPC Stack Limits and restart */ continue; } /* Create an invalid stack exception */ ExceptionRecord2.ExceptionCode = STATUS_BAD_STACK; ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; ExceptionRecord2.ExceptionRecord = ExceptionRecord; ExceptionRecord2.NumberParameters = 0; /* Raise the exception */ RtlRaiseException(&ExceptionRecord2); } else { /* Call the handler */ Disposition = RtlpExecuteHandlerForUnwind(ExceptionRecord, RegistrationFrame, Context, &DispatcherContext, RegistrationFrame->Handler); switch(Disposition) { /* Continue searching */ case ExceptionContinueSearch: break; /* Collission */ case ExceptionCollidedUnwind : /* Get the original frame */ RegistrationFrame = DispatcherContext.RegistrationPointer; break; /* Anything else */ default: /* Set up the exception record */ ExceptionRecord2.ExceptionRecord = ExceptionRecord; ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION; ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; ExceptionRecord2.NumberParameters = 0; /* Raise the exception */ RtlRaiseException(&ExceptionRecord2); break; } /* Go to the next frame */ OldFrame = RegistrationFrame; RegistrationFrame = RegistrationFrame->Next; /* Remove this handler */ RtlpSetExceptionList(OldFrame); } } /* Check if we reached the end */ if (TargetFrame == EXCEPTION_CHAIN_END) { /* Unwind completed, so we don't exit */ ZwContinue(Context, FALSE); } else { /* This is an exit_unwind or the frame wasn't present in the list */ ZwRaiseException(ExceptionRecord, Context, FALSE); } }
VOID ExpRaiseException ( IN PEXCEPTION_RECORD ExceptionRecord ) /*++ Routine Description: This function raises a software exception by building a context record and calling the exception dispatcher directly. Arguments: ExceptionRecord - Supplies a pointer to an exception record. Return Value: None. --*/ { ULONG ControlPc; CONTEXT ContextRecord; ULONG EstablisherFrame; PRUNTIME_FUNCTION FunctionEntry; BOOLEAN InFunction; ULONG NextPc; NTSTATUS Status; // // Capture the current context, virtually unwind to the caller of this // routine, set the fault instruction address to that of the caller, and // call the exception dispatcher. // RtlCaptureContext(&ContextRecord); ControlPc = ContextRecord.Lr - 4; FunctionEntry = RtlLookupFunctionEntry(ControlPc); NextPc = RtlVirtualUnwind(ControlPc, FunctionEntry, &ContextRecord, &InFunction, &EstablisherFrame, NULL, 0, 0xffffffff); ContextRecord.Iar = NextPc + 4; ExceptionRecord->ExceptionAddress = (PVOID)ContextRecord.Iar; // // If the exception is successfully dispatched, then continue execution. // Otherwise, give the kernel debugger a chance to handle the exception. // if (RtlDispatchException(ExceptionRecord, &ContextRecord)) { Status = ZwContinue(&ContextRecord, FALSE); } else { Status = ZwRaiseException(ExceptionRecord, &ContextRecord, FALSE); } // // Either the attempt to continue execution or the attempt to give // the kernel debugger a chance to handle the exception failed. Raise // a noncontinuable exception. // ExRaiseStatus(Status); }
VOID ExpRaiseStatus ( IN NTSTATUS ExceptionCode ) /*++ Routine Description: This function raises an exception with the specified status value by building an exception record, building a context record, and calling the exception dispatcher directly. The exception is marked as noncontinuable with no parameters. There is no return from this function. Arguments: ExceptionCode - Supplies the status value to be used as the exception code for the exception that is to be raised. Return Value: None. --*/ { ULONG ControlPc; CONTEXT ContextRecord; ULONG EstablisherFrame; EXCEPTION_RECORD ExceptionRecord; PRUNTIME_FUNCTION FunctionEntry; BOOLEAN InFunction; ULONG NextPc; NTSTATUS Status; // // Construct an exception record. // ExceptionRecord.ExceptionCode = ExceptionCode; ExceptionRecord.ExceptionRecord = (PEXCEPTION_RECORD)NULL; ExceptionRecord.NumberParameters = 0; ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE; // // Capture the current context, virtually unwind to the caller of this // routine, set the fault instruction address to that of the caller, and // call the exception dispatcher. // RtlCaptureContext(&ContextRecord); ControlPc = ContextRecord.Lr - 4; FunctionEntry = RtlLookupFunctionEntry(ControlPc); NextPc = RtlVirtualUnwind(ControlPc, FunctionEntry, &ContextRecord, &InFunction, &EstablisherFrame, NULL, 0, 0xffffffff); ContextRecord.Iar = NextPc + 4; ExceptionRecord.ExceptionAddress = (PVOID)ContextRecord.Iar; RtlDispatchException(&ExceptionRecord, &ContextRecord); // // An unwind was not initiated during the dispatching of a noncontinuable // exception. Give the kernel debugger a chance to handle the exception. // Status = ZwRaiseException(&ExceptionRecord, &ContextRecord, FALSE); // // The attempt to give the kernel debugger a chance to handle the exception // failed. Raise another noncontinuable exception. // ExRaiseStatus(Status); }