|
|
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
raisexcp.c
Abstract:
This module implements the internal kernel code to continue execution and raise a exception.
Author:
David N. Cutler (davec) 8-Aug-1990
Environment:
Kernel mode only.
Revision History:
--*/
#include "ki.h"
VOID KiContinuePreviousModeUser( IN PCONTEXT ContextRecord, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame, IN KPROCESSOR_MODE PreviousMode )
/*++
Routine Description:
This function is called from KiContinue if PreviousMode is not KernelMode. In this case a kernel mode copy of the ContextRecord is made before calling KeContextToKframes. This is done in a seperate routine to save stack space for the common case which is PreviousMode == Kernel.
N.B. This routine is called from within a try/except block that will be used to handle errors like invalid context.
Arguments:
ContextRecord - Supplies a pointer to a context record.
ExceptionFrame - Supplies a pointer to an exception frame.
TrapFrame - Supplies a pointer to a trap frame.
PreviousMode - Not KernelMode.
Return Value:
None.
--*/
{ CONTEXT ContextRecord2;
//
// Copy the context record to kernel mode space.
//
ProbeForReadSmallStructure(ContextRecord, sizeof(CONTEXT), CONTEXT_ALIGN); RtlCopyMemory(&ContextRecord2, ContextRecord, sizeof(CONTEXT)); ContextRecord = &ContextRecord2;
//
// Move information from the context record to the exception
// and trap frames.
//
KeContextToKframes(TrapFrame, ExceptionFrame, &ContextRecord2, ContextRecord2.ContextFlags, PreviousMode); }
NTSTATUS KiContinue ( IN PCONTEXT ContextRecord, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame )
/*++
Routine Description:
This function is called to copy the specified context frame to the specified exception and trap frames for the continue system service.
Arguments:
ContextRecord - Supplies a pointer to a context record.
ExceptionFrame - Supplies a pointer to an exception frame.
TrapFrame - Supplies a pointer to a trap frame.
Return Value:
STATUS_ACCESS_VIOLATION is returned if the context record is not readable from user mode.
STATUS_DATATYPE_MISALIGNMENT is returned if the context record is not properly aligned.
STATUS_SUCCESS is returned if the context frame is copied successfully to the specified exception and trap frames.
--*/
{ KPROCESSOR_MODE PreviousMode; NTSTATUS Status; KIRQL OldIrql; BOOLEAN IrqlChanged = FALSE;
//
// Synchronize with other context operations.
//
Status = STATUS_SUCCESS; if (KeGetCurrentIrql() < APC_LEVEL) {
//
// To support try-except and ExRaiseStatus in device driver code we
// need to check if we are already at raised level.
//
IrqlChanged = TRUE; KeRaiseIrql(APC_LEVEL, &OldIrql); }
//
// Establish an exception handler and probe and capture the specified
// context record if the previous mode is user. If the probe or copy
// fails, then return the exception code as the function value. Else
// copy the context record to the specified exception and trap frames,
// and return success as the function value.
//
try {
//
// Get the previous processor mode. If the previous processor mode is
// user, then probe and copy the specified context record.
//
PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { KiContinuePreviousModeUser(ContextRecord, ExceptionFrame, TrapFrame, PreviousMode); } else {
//
// Move information from the context record to the exception
// and trap frames.
//
KeContextToKframes(TrapFrame, ExceptionFrame, ContextRecord, ContextRecord->ContextFlags, PreviousMode); }
//
// If an exception occurs during the probe or copy of the context
// record, then always handle the exception and return the exception
// code as the status value.
//
} except(EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); }
if (IrqlChanged) { KeLowerIrql (OldIrql); }
return Status; }
NTSTATUS KiRaiseException ( IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame, IN BOOLEAN FirstChance )
/*++
Routine Description:
This function is called to raise an exception. The exception can be raised as a first or second chance exception.
Arguments:
ExceptionRecord - Supplies a pointer to an exception record.
ContextRecord - Supplies a pointer to a context record.
ExceptionFrame - Supplies a pointer to an exception frame.
TrapFrame - Supplies a pointer to a trap frame.
FirstChance - Supplies a boolean value that specifies whether this is the first (TRUE) or second (FALSE) chance for the exception.
Return Value:
STATUS_ACCESS_VIOLATION is returned if either the exception or the context record is not readable from user mode.
STATUS_DATATYPE_MISALIGNMENT is returned if the exception record or the context record are not properly aligned.
STATUS_INVALID_PARAMETER is returned if the number of exception parameters is greater than the maximum allowable number of exception parameters.
STATUS_SUCCESS is returned if the exception is dispatched and handled.
--*/
{
CONTEXT ContextRecord2; EXCEPTION_RECORD ExceptionRecord2; ULONG Length; ULONG Params; KPROCESSOR_MODE PreviousMode;
//
// Establish an exception handler and probe the specified exception and
// context records for read accessibility. If the probe fails, then
// return the exception code as the service status. Else call the exception
// dispatcher to dispatch the exception.
//
try {
//
// Get the previous processor mode. If the previous processor mode
// is user, then probe and copy the specified exception and context
// records.
//
PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { ProbeForReadSmallStructure(ContextRecord, sizeof(CONTEXT), CONTEXT_ALIGN); ProbeForReadSmallStructure(ExceptionRecord, FIELD_OFFSET (EXCEPTION_RECORD, NumberParameters) + sizeof (ExceptionRecord->NumberParameters), sizeof(ULONG)); Params = ExceptionRecord->NumberParameters; if (Params > EXCEPTION_MAXIMUM_PARAMETERS) { return STATUS_INVALID_PARAMETER; }
//
// The exception record structure is defined unlike others with trailing
// information as being its maximum size rather than just a single trailing
// element.
//
Length = (sizeof(EXCEPTION_RECORD) - ((EXCEPTION_MAXIMUM_PARAMETERS - Params) * sizeof(ExceptionRecord->ExceptionInformation[0])));
//
// The structure is currently less that 64k so we don't really need this probe.
//
ProbeForRead(ExceptionRecord, Length, sizeof(ULONG));
//
// Copy the exception and context record to local storage so an
// access violation cannot occur during exception dispatching.
//
RtlCopyMemory(&ContextRecord2, ContextRecord, sizeof(CONTEXT)); RtlCopyMemory(&ExceptionRecord2, ExceptionRecord, Length); ContextRecord = &ContextRecord2; ExceptionRecord = &ExceptionRecord2; //
// The number of parameters might have changed after we validated but before we
// copied the structure. Fix this up as lower levels might not like this.
//
ExceptionRecord->NumberParameters = Params; }
//
// If an exception occurs during the probe of the exception or context
// record, then always handle the exception and return the exception code
// as the status value.
//
} except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); }
//
// Move information from the context record to the exception and
// trap frames.
//
KeContextToKframes(TrapFrame, ExceptionFrame, ContextRecord, ContextRecord->ContextFlags, PreviousMode);
//
// Make sure the reserved bit is clear in the exception code and
// perform exception dispatching.
//
// N.B. The reserved bit is used to differentiate internally gerarated
// codes from codes generated by application programs.
//
ExceptionRecord->ExceptionCode &= 0xefffffff; KiDispatchException(ExceptionRecord, ExceptionFrame, TrapFrame, PreviousMode, FirstChance);
return STATUS_SUCCESS; }
|