274 lines
6.4 KiB
C
274 lines
6.4 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
raisests.c
|
||
|
||
Abstract:
|
||
|
||
This module implements routines to raise a general exception from kernel
|
||
mode or a noncontinuable exception from kernel mode.
|
||
|
||
Author:
|
||
|
||
David N. Cutler (davec) 18-Oct-1990
|
||
|
||
Environment:
|
||
|
||
Any mode.
|
||
|
||
Revision History:
|
||
|
||
Thomas Van Baak (tvb) 5-May-1992
|
||
|
||
Adapted for Alpha AXP.
|
||
|
||
--*/
|
||
|
||
#include "exp.h"
|
||
|
||
//
|
||
// Define private function prototypes.
|
||
//
|
||
|
||
VOID
|
||
ExpRaiseException (
|
||
IN PEXCEPTION_RECORD ExceptionRecord
|
||
);
|
||
|
||
VOID
|
||
ExpRaiseStatus (
|
||
IN NTSTATUS ExceptionCode
|
||
);
|
||
|
||
VOID
|
||
ExRaiseException (
|
||
IN PEXCEPTION_RECORD ExceptionRecord
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function raises a software exception by building a context record
|
||
and calling the exception dispatcher directly.
|
||
|
||
N.B. This routine is a shell routine that simply calls another routine
|
||
to do the real work. The reason this is done is to avoid a problem
|
||
in try/finally scopes where the last statement in the scope is a
|
||
call to raise an exception.
|
||
|
||
Arguments:
|
||
|
||
ExceptionRecord - Supplies a pointer to an exception record.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
#ifdef DBGtvb
|
||
DbgPrint("ExRaiseException(ExceptionRecord = %lx) Status = %lx\n",
|
||
ExceptionRecord, ExceptionRecord->ExceptionCode);
|
||
);
|
||
#endif
|
||
ExpRaiseException(ExceptionRecord);
|
||
return;
|
||
}
|
||
|
||
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_PTR ControlPc;
|
||
CONTEXT ContextRecord;
|
||
FRAME_POINTERS EstablisherFrame;
|
||
PRUNTIME_FUNCTION FunctionEntry;
|
||
BOOLEAN InFunction;
|
||
ULONG_PTR 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 = (ULONG_PTR)ContextRecord.IntRa - 4;
|
||
FunctionEntry = RtlLookupFunctionEntry(ControlPc);
|
||
NextPc = RtlVirtualUnwind(ControlPc,
|
||
FunctionEntry,
|
||
&ContextRecord,
|
||
&InFunction,
|
||
&EstablisherFrame,
|
||
NULL);
|
||
|
||
ContextRecord.Fir = (ULONGLONG)(LONG_PTR)NextPc + 4;
|
||
ExceptionRecord->ExceptionAddress = (PVOID)ContextRecord.Fir;
|
||
|
||
//
|
||
// 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
|
||
ExRaiseStatus (
|
||
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.
|
||
|
||
N.B. This routine is a shell routine that simply calls another routine
|
||
to do the real work. The reason this is done is to avoid a problem
|
||
in try/finally scopes where the last statement in the scope is a
|
||
call to raise an exception.
|
||
|
||
Arguments:
|
||
|
||
ExceptionCode - Supplies the status value to be used as the exception
|
||
code for the exception that is to be raised.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
#ifdef DBGxx
|
||
DbgPrint("ExRaiseStatus(ExceptionCode = %lx)\n", ExceptionCode);
|
||
#endif
|
||
ExpRaiseStatus(ExceptionCode);
|
||
return;
|
||
}
|
||
|
||
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_PTR ControlPc;
|
||
CONTEXT ContextRecord;
|
||
FRAME_POINTERS EstablisherFrame;
|
||
EXCEPTION_RECORD ExceptionRecord;
|
||
PRUNTIME_FUNCTION FunctionEntry;
|
||
BOOLEAN InFunction;
|
||
ULONG_PTR 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 = (ULONG_PTR)ContextRecord.IntRa - 4;
|
||
FunctionEntry = RtlLookupFunctionEntry(ControlPc);
|
||
NextPc = RtlVirtualUnwind(ControlPc,
|
||
FunctionEntry,
|
||
&ContextRecord,
|
||
&InFunction,
|
||
&EstablisherFrame,
|
||
NULL);
|
||
|
||
ContextRecord.Fir = (ULONGLONG)(LONG_PTR)NextPc + 4;
|
||
ExceptionRecord.ExceptionAddress = (PVOID)ContextRecord.Fir;
|
||
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);
|
||
}
|