windows-nt/Source/XPSP1/NT/base/ntos/ke/raisexcp.c

346 lines
9.4 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
}