mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1212 lines
37 KiB
1212 lines
37 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
Copyright (c) 1993, 1994 Digital Equipment Corporation
|
|
|
|
Module Name:
|
|
|
|
exceptn.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the code necessary to dispatch exceptions to the
|
|
proper mode and invoke the exception dispatcher.
|
|
|
|
Author:
|
|
|
|
David N. Cutler (davec) 3-Apr-1990
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
Thomas Van Baak (tvb) 12-May-1992
|
|
|
|
Adapted for Alpha AXP.
|
|
|
|
--*/
|
|
|
|
#include "ki.h"
|
|
|
|
BOOLEAN
|
|
KiHandleAlignmentFault(
|
|
IN PEXCEPTION_RECORD ExceptionRecord,
|
|
IN PKEXCEPTION_FRAME ExceptionFrame,
|
|
IN PKTRAP_FRAME TrapFrame,
|
|
IN KPROCESSOR_MODE PreviousMode,
|
|
IN BOOLEAN FirstChance,
|
|
OUT BOOLEAN *ExceptionForwarded
|
|
);
|
|
|
|
|
|
VOID
|
|
KiMachineCheck (
|
|
IN PEXCEPTION_RECORD ExceptionRecord,
|
|
IN PKEXCEPTION_FRAME ExceptionFrame,
|
|
IN PKTRAP_FRAME TrapFrame
|
|
);
|
|
|
|
|
|
VOID
|
|
KeContextFromKframes (
|
|
IN PKTRAP_FRAME TrapFrame,
|
|
IN PKEXCEPTION_FRAME ExceptionFrame,
|
|
IN OUT PCONTEXT ContextFrame
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine moves the selected contents of the specified trap and exception
|
|
frames into the specified context frame according to the specified context
|
|
flags.
|
|
|
|
Arguments:
|
|
|
|
TrapFrame - Supplies a pointer to a trap frame from which volatile context
|
|
should be copied into the context record.
|
|
|
|
ExceptionFrame - Supplies a pointer to an exception frame from which context
|
|
should be copied into the context record.
|
|
|
|
ContextFrame - Supplies a pointer to the context frame that receives the
|
|
context copied from the trap and exception frames.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Set control information if specified.
|
|
//
|
|
|
|
if ((ContextFrame->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) {
|
|
|
|
//
|
|
// Set integer register gp, ra, sp, FIR, and PSR from trap frame.
|
|
//
|
|
|
|
ContextFrame->IntGp = TrapFrame->IntGp;
|
|
ContextFrame->IntSp = TrapFrame->IntSp;
|
|
ContextFrame->IntRa = TrapFrame->IntRa;
|
|
ContextFrame->Fir = TrapFrame->Fir;
|
|
ContextFrame->Psr = TrapFrame->Psr;
|
|
}
|
|
|
|
//
|
|
// Set integer register contents if specified.
|
|
//
|
|
|
|
if ((ContextFrame->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) {
|
|
|
|
//
|
|
// Set volatile integer registers v0 and t0 - t7 from trap frame.
|
|
//
|
|
|
|
ContextFrame->IntV0 = TrapFrame->IntV0;
|
|
ContextFrame->IntT0 = TrapFrame->IntT0;
|
|
ContextFrame->IntT1 = TrapFrame->IntT1;
|
|
ContextFrame->IntT2 = TrapFrame->IntT2;
|
|
ContextFrame->IntT3 = TrapFrame->IntT3;
|
|
ContextFrame->IntT4 = TrapFrame->IntT4;
|
|
ContextFrame->IntT5 = TrapFrame->IntT5;
|
|
ContextFrame->IntT6 = TrapFrame->IntT6;
|
|
ContextFrame->IntT7 = TrapFrame->IntT7;
|
|
|
|
//
|
|
// Set nonvolatile integer registers s0 - s5 from exception frame.
|
|
//
|
|
|
|
ContextFrame->IntS0 = ExceptionFrame->IntS0;
|
|
ContextFrame->IntS1 = ExceptionFrame->IntS1;
|
|
ContextFrame->IntS2 = ExceptionFrame->IntS2;
|
|
ContextFrame->IntS3 = ExceptionFrame->IntS3;
|
|
ContextFrame->IntS4 = ExceptionFrame->IntS4;
|
|
ContextFrame->IntS5 = ExceptionFrame->IntS5;
|
|
|
|
//
|
|
// Set volatile integer registers a0 - a5, and t8 - t11 from trap
|
|
// frame.
|
|
//
|
|
|
|
ContextFrame->IntA0 = TrapFrame->IntA0;
|
|
ContextFrame->IntA1 = TrapFrame->IntA1;
|
|
ContextFrame->IntA2 = TrapFrame->IntA2;
|
|
ContextFrame->IntA3 = TrapFrame->IntA3;
|
|
ContextFrame->IntA4 = TrapFrame->IntA4;
|
|
ContextFrame->IntA5 = TrapFrame->IntA5;
|
|
|
|
ContextFrame->IntT8 = TrapFrame->IntT8;
|
|
ContextFrame->IntT9 = TrapFrame->IntT9;
|
|
ContextFrame->IntT10 = TrapFrame->IntT10;
|
|
ContextFrame->IntT11 = TrapFrame->IntT11;
|
|
|
|
//
|
|
// Set volatile integer registers fp, t12 and at from trap frame.
|
|
// Set integer register zero.
|
|
//
|
|
|
|
ContextFrame->IntFp = TrapFrame->IntFp;
|
|
ContextFrame->IntT12 = TrapFrame->IntT12;
|
|
ContextFrame->IntAt = TrapFrame->IntAt;
|
|
ContextFrame->IntZero = 0;
|
|
}
|
|
|
|
//
|
|
// Set floating register contents if specified.
|
|
//
|
|
|
|
if ((ContextFrame->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) {
|
|
|
|
//
|
|
// Set volatile floating registers f0 - f1 from trap frame.
|
|
// Set volatile floating registers f10 - f30 from trap frame.
|
|
// Set floating zero register f31 to 0.
|
|
//
|
|
|
|
ContextFrame->FltF0 = TrapFrame->FltF0;
|
|
ContextFrame->FltF1 = TrapFrame->FltF1;
|
|
RtlMoveMemory(&ContextFrame->FltF10, &TrapFrame->FltF10,
|
|
sizeof(ULONGLONG) * 21);
|
|
ContextFrame->FltF31 = 0;
|
|
|
|
//
|
|
// Set nonvolatile floating registers f2 - f9 from exception frame.
|
|
//
|
|
|
|
ContextFrame->FltF2 = ExceptionFrame->FltF2;
|
|
ContextFrame->FltF3 = ExceptionFrame->FltF3;
|
|
ContextFrame->FltF4 = ExceptionFrame->FltF4;
|
|
ContextFrame->FltF5 = ExceptionFrame->FltF5;
|
|
ContextFrame->FltF6 = ExceptionFrame->FltF6;
|
|
ContextFrame->FltF7 = ExceptionFrame->FltF7;
|
|
ContextFrame->FltF8 = ExceptionFrame->FltF8;
|
|
ContextFrame->FltF9 = ExceptionFrame->FltF9;
|
|
|
|
//
|
|
// Set floating point control register from trap frame.
|
|
// Clear software floating point control register in context frame
|
|
// (if necessary, it can be set to the proper value by the caller).
|
|
//
|
|
|
|
ContextFrame->Fpcr = TrapFrame->Fpcr;
|
|
ContextFrame->SoftFpcr = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
KeContextToKframes (
|
|
IN OUT PKTRAP_FRAME TrapFrame,
|
|
IN OUT PKEXCEPTION_FRAME ExceptionFrame,
|
|
IN PCONTEXT ContextFrame,
|
|
IN ULONG ContextFlags,
|
|
IN KPROCESSOR_MODE PreviousMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine moves the selected contents of the specified context frame into
|
|
the specified trap and exception frames according to the specified context
|
|
flags.
|
|
|
|
Arguments:
|
|
|
|
TrapFrame - Supplies a pointer to a trap frame that receives the volatile
|
|
context from the context record.
|
|
|
|
ExceptionFrame - Supplies a pointer to an exception frame that receives
|
|
the nonvolatile context from the context record.
|
|
|
|
ContextFrame - Supplies a pointer to a context frame that contains the
|
|
context that is to be copied into the trap and exception frames.
|
|
|
|
ContextFlags - Supplies the set of flags that specify which parts of the
|
|
context frame are to be copied into the trap and exception frames.
|
|
|
|
PreviousMode - Supplies the processor mode for which the trap and exception
|
|
frames are being built.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Set control information if specified.
|
|
//
|
|
|
|
if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) {
|
|
|
|
//
|
|
// Set integer register gp, sp, ra, FIR, and PSR in trap frame.
|
|
//
|
|
|
|
TrapFrame->IntGp = ContextFrame->IntGp;
|
|
TrapFrame->IntSp = ContextFrame->IntSp;
|
|
TrapFrame->IntRa = ContextFrame->IntRa;
|
|
TrapFrame->Fir = ContextFrame->Fir;
|
|
TrapFrame->Psr = SANITIZE_PSR(ContextFrame->Psr, PreviousMode);
|
|
}
|
|
|
|
//
|
|
// Set integer register contents if specified.
|
|
//
|
|
|
|
if ((ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) {
|
|
|
|
//
|
|
// Set volatile integer registers v0 and t0 - t7 in trap frame.
|
|
//
|
|
|
|
TrapFrame->IntV0 = ContextFrame->IntV0;
|
|
TrapFrame->IntT0 = ContextFrame->IntT0;
|
|
TrapFrame->IntT1 = ContextFrame->IntT1;
|
|
TrapFrame->IntT2 = ContextFrame->IntT2;
|
|
TrapFrame->IntT3 = ContextFrame->IntT3;
|
|
TrapFrame->IntT4 = ContextFrame->IntT4;
|
|
TrapFrame->IntT5 = ContextFrame->IntT5;
|
|
TrapFrame->IntT6 = ContextFrame->IntT6;
|
|
TrapFrame->IntT7 = ContextFrame->IntT7;
|
|
|
|
//
|
|
// Set nonvolatile integer registers s0 - s5 in exception frame.
|
|
//
|
|
|
|
ExceptionFrame->IntS0 = ContextFrame->IntS0;
|
|
ExceptionFrame->IntS1 = ContextFrame->IntS1;
|
|
ExceptionFrame->IntS2 = ContextFrame->IntS2;
|
|
ExceptionFrame->IntS3 = ContextFrame->IntS3;
|
|
ExceptionFrame->IntS4 = ContextFrame->IntS4;
|
|
ExceptionFrame->IntS5 = ContextFrame->IntS5;
|
|
|
|
//
|
|
// Set volatile integer registers a0 - a5, and t8 - t11 in trap frame.
|
|
//
|
|
|
|
TrapFrame->IntA0 = ContextFrame->IntA0;
|
|
TrapFrame->IntA1 = ContextFrame->IntA1;
|
|
TrapFrame->IntA2 = ContextFrame->IntA2;
|
|
TrapFrame->IntA3 = ContextFrame->IntA3;
|
|
TrapFrame->IntA4 = ContextFrame->IntA4;
|
|
TrapFrame->IntA5 = ContextFrame->IntA5;
|
|
|
|
TrapFrame->IntT8 = ContextFrame->IntT8;
|
|
TrapFrame->IntT9 = ContextFrame->IntT9;
|
|
TrapFrame->IntT10 = ContextFrame->IntT10;
|
|
TrapFrame->IntT11 = ContextFrame->IntT11;
|
|
|
|
//
|
|
// Set volatile integer registers fp, t12 and at in trap frame.
|
|
//
|
|
|
|
TrapFrame->IntFp = ContextFrame->IntFp;
|
|
TrapFrame->IntT12 = ContextFrame->IntT12;
|
|
TrapFrame->IntAt = ContextFrame->IntAt;
|
|
}
|
|
|
|
//
|
|
// Set floating register contents if specified.
|
|
//
|
|
|
|
if ((ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) {
|
|
|
|
//
|
|
// Set volatile floating registers f0 - f1 in trap frame.
|
|
// Set volatile floating registers f10 - f30 in trap frame.
|
|
//
|
|
|
|
TrapFrame->FltF0 = ContextFrame->FltF0;
|
|
TrapFrame->FltF1 = ContextFrame->FltF1;
|
|
RtlMoveMemory(&TrapFrame->FltF10, &ContextFrame->FltF10,
|
|
sizeof(ULONGLONG) * 21);
|
|
|
|
//
|
|
// Set nonvolatile floating registers f2 - f9 in exception frame.
|
|
//
|
|
|
|
ExceptionFrame->FltF2 = ContextFrame->FltF2;
|
|
ExceptionFrame->FltF3 = ContextFrame->FltF3;
|
|
ExceptionFrame->FltF4 = ContextFrame->FltF4;
|
|
ExceptionFrame->FltF5 = ContextFrame->FltF5;
|
|
ExceptionFrame->FltF6 = ContextFrame->FltF6;
|
|
ExceptionFrame->FltF7 = ContextFrame->FltF7;
|
|
ExceptionFrame->FltF8 = ContextFrame->FltF8;
|
|
ExceptionFrame->FltF9 = ContextFrame->FltF9;
|
|
|
|
//
|
|
// Set floating point control register in trap frame.
|
|
//
|
|
|
|
TrapFrame->Fpcr = ContextFrame->Fpcr;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
KiDispatchException (
|
|
IN PEXCEPTION_RECORD ExceptionRecord,
|
|
IN PKEXCEPTION_FRAME ExceptionFrame,
|
|
IN PKTRAP_FRAME TrapFrame,
|
|
IN KPROCESSOR_MODE PreviousMode,
|
|
IN BOOLEAN FirstChance
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to dispatch an exception to the proper mode and
|
|
to cause the exception dispatcher to be called.
|
|
|
|
If the exception is a data misalignment, the previous mode is user, this
|
|
is the first chance for handling the exception, and the current thread
|
|
has enabled automatic alignment fixup, then an attempt is made to emulate
|
|
the unaligned reference. Data misalignment exceptions are never emulated
|
|
for kernel mode.
|
|
|
|
If the exception is a floating not implemented exception, then an attempt
|
|
is made to emulate the floating operation. If the exception is an
|
|
arithmetic exception, then an attempt is made to convert the imprecise
|
|
exception into a precise exception, and then emulate the floating
|
|
operation in order to obtain the proper IEEE results and exceptions.
|
|
Floating exceptions are never emulated for kernel mode.
|
|
|
|
If the exception is neither a data misalignment nor a floating point
|
|
exception and the previous mode is kernel, then the exception
|
|
dispatcher is called directly to process the exception. Otherwise the
|
|
exception record, exception frame, and trap frame contents are copied
|
|
to the user mode stack. The contents of the exception frame and trap
|
|
are then modified such that when control is returned, execution will
|
|
commence in user mode in a routine which will call the exception
|
|
dispatcher.
|
|
|
|
Arguments:
|
|
|
|
ExceptionRecord - Supplies a pointer to an exception record.
|
|
|
|
ExceptionFrame - Supplies a pointer to an exception frame.
|
|
|
|
TrapFrame - Supplies a pointer to a trap frame.
|
|
|
|
PreviousMode - Supplies the previous processor mode.
|
|
|
|
FirstChance - Supplies a boolean variable that specifies whether this
|
|
is the first (TRUE) or second (FALSE) time that this exception has
|
|
been processed.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
CONTEXT ContextFrame;
|
|
EXCEPTION_RECORD ExceptionRecord1;
|
|
PEXC_SUM ExceptionSummary;
|
|
LONG Length;
|
|
ULONG SoftFpcr;
|
|
ULONGLONG UserStack1;
|
|
ULONGLONG UserStack2;
|
|
BOOLEAN AlignmentFaultHandled;
|
|
BOOLEAN ExceptionForwarded;
|
|
|
|
//
|
|
// If the exception is an illegal instruction exception, then check for
|
|
// a byte/word instruction that should be emulated.
|
|
//
|
|
// N.B. The exception code STATUS_ILLEGAL_INSTRUCTION may be converted
|
|
// into STATUS_DATATYPE_MISALIGNMENT in the case of unaligned word
|
|
// access.
|
|
//
|
|
|
|
if (ExceptionRecord->ExceptionCode == STATUS_ILLEGAL_INSTRUCTION) {
|
|
if (KiEmulateByteWord(ExceptionRecord,
|
|
ExceptionFrame,
|
|
TrapFrame) != FALSE) {
|
|
KeGetCurrentPrcb()->KeByteWordEmulationCount += 1;
|
|
goto Handled2;
|
|
}
|
|
}
|
|
|
|
ExceptionForwarded = FALSE;
|
|
if (ExceptionRecord->ExceptionCode == STATUS_DATATYPE_MISALIGNMENT) {
|
|
|
|
AlignmentFaultHandled = KiHandleAlignmentFault( ExceptionRecord,
|
|
ExceptionFrame,
|
|
TrapFrame,
|
|
PreviousMode,
|
|
FirstChance,
|
|
&ExceptionForwarded );
|
|
if (AlignmentFaultHandled != FALSE) {
|
|
goto Handled2;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the exception is a data bus error then a machine check has
|
|
// been trapped by the PALcode. The error will be forwarded to the
|
|
// HAL eventually for logging or handling. If the handler returns
|
|
// it is assumed that the HAL successfully handled the error and
|
|
// execution may resume.
|
|
//
|
|
// N.B. A special exception code is used to signal a data bus error.
|
|
// This code is equivalent to the bug check code merged with a
|
|
// reserved facility code and the reserved bit set.
|
|
//
|
|
|
|
if (ExceptionRecord->ExceptionCode == (DATA_BUS_ERROR | 0xdfff0000)) {
|
|
KiMachineCheck(ExceptionRecord, ExceptionFrame, TrapFrame);
|
|
goto Handled2;
|
|
}
|
|
|
|
//
|
|
// Initialize the copy of the software FPCR. The proper value is set
|
|
// if a floating emulation operation is performed. Case on arithmetic
|
|
// exception codes that require special handling by the kernel.
|
|
//
|
|
|
|
SoftFpcr = 0;
|
|
switch (ExceptionRecord->ExceptionCode) {
|
|
|
|
//
|
|
// If the exception is a gentrap, then attempt to translate the
|
|
// Alpha specific gentrap value to a status code value. This
|
|
// exception is a precise trap.
|
|
//
|
|
// N.B. STATUS_ALPHA_GENTRAP is a pseudo status code generated by
|
|
// PALcode when a callpal gentrap is executed. The status is
|
|
// visible in user mode only when the gentrap code value is
|
|
// unrecognized.
|
|
//
|
|
|
|
case STATUS_ALPHA_GENTRAP :
|
|
switch (ExceptionRecord->ExceptionInformation[0]) {
|
|
case GENTRAP_INTEGER_OVERFLOW :
|
|
ExceptionRecord->ExceptionCode = STATUS_INTEGER_OVERFLOW;
|
|
break;
|
|
|
|
case GENTRAP_INTEGER_DIVIDE_BY_ZERO :
|
|
ExceptionRecord->ExceptionCode = STATUS_INTEGER_DIVIDE_BY_ZERO;
|
|
break;
|
|
|
|
case GENTRAP_FLOATING_OVERFLOW :
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_OVERFLOW;
|
|
break;
|
|
|
|
case GENTRAP_FLOATING_DIVIDE_BY_ZERO :
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_DIVIDE_BY_ZERO;
|
|
break;
|
|
|
|
case GENTRAP_FLOATING_UNDERFLOW :
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_UNDERFLOW;
|
|
break;
|
|
|
|
case GENTRAP_FLOATING_INVALID_OPERAND :
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
|
|
break;
|
|
|
|
case GENTRAP_FLOATING_INEXACT_RESULT :
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// If the exception is an unimplemented floating operation, then
|
|
// PALcode has detected a subsetted floating point operation. These
|
|
// include attempts to use round to plus or minus infinity rounding
|
|
// modes on EV4. This exception is a fault.
|
|
//
|
|
// If the previous mode was user, an attempt is made to emulate the
|
|
// operation. If the emulation is successful, the continuation
|
|
// address is incremented to the next instruction.
|
|
//
|
|
// N.B. STATUS_ALPHA_FLOATING_NOT_IMPLEMENTED is a pseudo status code
|
|
// generated by PALcode. The status is never visible outside of
|
|
// this handler because the floating emulation routine converts
|
|
// the status code to the proper floating status value.
|
|
//
|
|
|
|
case STATUS_ALPHA_FLOATING_NOT_IMPLEMENTED :
|
|
if (PreviousMode != KernelMode) {
|
|
if (KiFloatingException(ExceptionRecord,
|
|
ExceptionFrame,
|
|
TrapFrame,
|
|
FALSE,
|
|
&SoftFpcr) != FALSE) {
|
|
TrapFrame->Fir += 4;
|
|
goto Handled2;
|
|
}
|
|
|
|
} else {
|
|
ExceptionRecord->ExceptionCode = STATUS_ILLEGAL_INSTRUCTION;
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// If the exception is an arithmetic exception, then one or more
|
|
// integer overflow or floating point traps has occurred. This
|
|
// exception is an imprecise (asynchronous) trap. Attempt to locate
|
|
// the original trapping instruction and emulate the instruction.
|
|
//
|
|
// N.B. STATUS_ALPHA_ARITHMETIC_EXCEPTION is a pseudo status code
|
|
// generated by PALcode. The status is never visible outside of
|
|
// this handler because the floating emulation routine converts
|
|
// the status code to the proper floating status value.
|
|
//
|
|
|
|
case STATUS_ALPHA_ARITHMETIC_EXCEPTION :
|
|
if (KiFloatingException(ExceptionRecord,
|
|
ExceptionFrame,
|
|
TrapFrame,
|
|
TRUE,
|
|
&SoftFpcr) != FALSE) {
|
|
goto Handled2;
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Move machine state from trap and exception frames to a context frame,
|
|
// and increment the number of exceptions dispatched.
|
|
//
|
|
// Explicitly set the value of the software FPCR in the context frame
|
|
// (because it is not a hardware register and thus not present in the
|
|
// trap or exception frames).
|
|
//
|
|
|
|
ContextFrame.ContextFlags = CONTEXT_FULL;
|
|
KeContextFromKframes(TrapFrame, ExceptionFrame, &ContextFrame);
|
|
KeGetCurrentPrcb()->KeExceptionDispatchCount += 1;
|
|
ContextFrame.SoftFpcr = (ULONGLONG)SoftFpcr;
|
|
|
|
//
|
|
// Select the method of handling the exception based on the previous mode.
|
|
//
|
|
|
|
if (PreviousMode == KernelMode) {
|
|
|
|
//
|
|
// If the kernel debugger is active, the exception is a breakpoint,
|
|
// the breakpoint is handled by the kernel debugger, and this is the
|
|
// first chance, then give the kernel debugger a chance to handle
|
|
// the exception.
|
|
//
|
|
|
|
if ((FirstChance != FALSE) && (KiDebugRoutine != NULL) &&
|
|
(ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
|
|
(KdIsThisAKdTrap(ExceptionRecord,
|
|
&ContextFrame,
|
|
KernelMode) != FALSE) &&
|
|
|
|
(((KiDebugRoutine) (TrapFrame,
|
|
ExceptionFrame,
|
|
ExceptionRecord,
|
|
&ContextFrame,
|
|
KernelMode,
|
|
FALSE)) != FALSE)) {
|
|
|
|
goto Handled1;
|
|
}
|
|
|
|
|
|
//
|
|
// Previous mode was kernel.
|
|
//
|
|
// If this is the first chance, then attempt to dispatch the exception
|
|
// to a frame based handler. If the exception is handled, then continue
|
|
// execution.
|
|
//
|
|
// If this is the second chance or the exception is not handled,
|
|
// then if the kernel debugger is active, then give the kernel
|
|
// debugger a second chance to handle the exception. If the kernel
|
|
// debugger handles the exception, then continue execution. Otherwise
|
|
// bug check.
|
|
//
|
|
|
|
if (FirstChance != FALSE) {
|
|
|
|
//
|
|
// This is the first chance to handle the exception.
|
|
//
|
|
|
|
if (RtlDispatchException(ExceptionRecord, &ContextFrame) != FALSE) {
|
|
goto Handled1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// This is the second chance to handle the exception.
|
|
//
|
|
|
|
if ((KiDebugRoutine != NULL) &&
|
|
(((KiDebugRoutine) (TrapFrame,
|
|
ExceptionFrame,
|
|
ExceptionRecord,
|
|
&ContextFrame,
|
|
PreviousMode,
|
|
TRUE)) != FALSE)) {
|
|
|
|
goto Handled1;
|
|
}
|
|
|
|
KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
|
|
ExceptionRecord->ExceptionCode,
|
|
(ULONG_PTR)ExceptionRecord->ExceptionAddress,
|
|
ExceptionRecord->ExceptionInformation[0],
|
|
ExceptionRecord->ExceptionInformation[1]);
|
|
|
|
} else {
|
|
|
|
//
|
|
// If the kernel debugger is active, the exception is a breakpoint,
|
|
// the breakpoint is handled by the kernel debugger, and this is the
|
|
// first chance, then give the kernel debugger a chance to handle
|
|
// the exception.
|
|
//
|
|
|
|
if ((FirstChance != FALSE) &&
|
|
(KiDebugRoutine != NULL) &&
|
|
(ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
|
|
(KdIsThisAKdTrap(ExceptionRecord,
|
|
&ContextFrame,
|
|
UserMode) != FALSE) &&
|
|
|
|
((PsGetCurrentProcess()->DebugPort == NULL) ||
|
|
((PsGetCurrentProcess()->DebugPort != NULL) &&
|
|
(ExceptionRecord->ExceptionInformation[0] !=
|
|
DEBUG_STOP_BREAKPOINT)))) {
|
|
|
|
if (((KiDebugRoutine) (TrapFrame,
|
|
ExceptionFrame,
|
|
ExceptionRecord,
|
|
&ContextFrame,
|
|
UserMode,
|
|
FALSE)) != FALSE) {
|
|
|
|
goto Handled1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Previous mode was user.
|
|
//
|
|
// If this is the first chance and the current process has a debugger
|
|
// port, then send a message to the debugger port and wait for a reply.
|
|
// If the debugger handles the exception, then continue execution. Otherwise
|
|
// transfer the exception information to the user stack, transition to
|
|
// user mode, and attempt to dispatch the exception to a frame based
|
|
// handler. If a frame based handler handles the exception, then continue
|
|
// execution. Otherwise, execute the raise exception system service
|
|
// which will call this routine a second time to process the exception.
|
|
//
|
|
// If this is the second chance and the current process has a debugger
|
|
// port, then send a message to the debugger port and wait for a reply.
|
|
// If the debugger handles the exception, then continue execution. Otherwise
|
|
// if the current process has a subsystem port, then send a message to
|
|
// the subsystem port and wait for a reply. If the subsystem handles the
|
|
// exception, then continue execution. Otherwise terminate the thread.
|
|
//
|
|
|
|
if (FirstChance != FALSE) {
|
|
|
|
//
|
|
// This is the first chance to handle the exception.
|
|
//
|
|
|
|
if (ExceptionForwarded == FALSE &&
|
|
DbgkForwardException(ExceptionRecord, TRUE, FALSE)) {
|
|
goto Handled2;
|
|
}
|
|
|
|
//
|
|
// Transfer exception information to the user stack, transition
|
|
// to user mode, and attempt to dispatch the exception to a frame
|
|
// based handler.
|
|
//
|
|
|
|
repeat:
|
|
try {
|
|
|
|
//
|
|
// Compute length of exception record and new aligned stack
|
|
// address.
|
|
//
|
|
|
|
Length = (sizeof(EXCEPTION_RECORD) + 15) & (~15);
|
|
UserStack1 = (ContextFrame.IntSp & ~((ULONG_PTR)15)) - Length;
|
|
|
|
//
|
|
// Probe user stack area for writability and then transfer the
|
|
// exception record to the user stack area.
|
|
//
|
|
|
|
ProbeForWrite((PCHAR)UserStack1, Length, sizeof(QUAD));
|
|
RtlMoveMemory((PVOID)UserStack1, ExceptionRecord, Length);
|
|
|
|
//
|
|
// Compute length of context record and new aligned user stack
|
|
// pointer.
|
|
//
|
|
|
|
Length = (sizeof(CONTEXT) + 15) & (~15);
|
|
UserStack2 = UserStack1 - Length;
|
|
|
|
//
|
|
// Probe user stack area for writability and then transfer the
|
|
// context record to the user stack.
|
|
//
|
|
|
|
ProbeForWrite((PCHAR)UserStack2, Length, sizeof(QUAD));
|
|
RtlMoveMemory((PVOID)UserStack2, &ContextFrame, sizeof(CONTEXT));
|
|
|
|
//
|
|
// Set address of exception record, context record, and the
|
|
// and the new stack pointer in the current trap frame.
|
|
//
|
|
|
|
TrapFrame->IntSp = UserStack2;
|
|
TrapFrame->IntFp = UserStack2;
|
|
ExceptionFrame->IntS0 = UserStack1;
|
|
ExceptionFrame->IntS1 = UserStack2;
|
|
|
|
//
|
|
// Set the address of the exception routine that will call the
|
|
// exception dispatcher and then return to the trap handler.
|
|
// The trap handler will restore the exception and trap frame
|
|
// context and continue execution in the routine that will
|
|
// call the exception dispatcher.
|
|
//
|
|
|
|
TrapFrame->Fir = (ULONGLONG)(LONG_PTR)KeUserExceptionDispatcher;
|
|
return;
|
|
|
|
//
|
|
// If an exception occurs, then copy the new exception information
|
|
// to an exception record and handle the exception.
|
|
//
|
|
|
|
} except (KiCopyInformation(&ExceptionRecord1,
|
|
(GetExceptionInformation())->ExceptionRecord)) {
|
|
|
|
//
|
|
// If the exception is a stack overflow, then attempt
|
|
// to raise the stack overflow exception. Otherwise,
|
|
// the user's stack is not accessible, or is misaligned,
|
|
// and second chance processing is performed.
|
|
//
|
|
|
|
if (ExceptionRecord1.ExceptionCode == STATUS_STACK_OVERFLOW) {
|
|
ExceptionRecord1.ExceptionAddress = ExceptionRecord->ExceptionAddress;
|
|
RtlMoveMemory((PVOID)ExceptionRecord,
|
|
&ExceptionRecord1, sizeof(EXCEPTION_RECORD));
|
|
goto repeat;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// This is the second chance to handle the exception.
|
|
//
|
|
|
|
if (DbgkForwardException(ExceptionRecord, TRUE, TRUE)) {
|
|
goto Handled2;
|
|
|
|
} else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE)) {
|
|
goto Handled2;
|
|
|
|
} else {
|
|
ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode);
|
|
KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
|
|
ExceptionRecord->ExceptionCode,
|
|
(ULONG_PTR)ExceptionRecord->ExceptionAddress,
|
|
ExceptionRecord->ExceptionInformation[0],
|
|
ExceptionRecord->ExceptionInformation[1]);
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Move machine state from context frame to trap and exception frames and
|
|
// then return to continue execution with the restored state.
|
|
//
|
|
|
|
Handled1:
|
|
KeContextToKframes(TrapFrame, ExceptionFrame, &ContextFrame,
|
|
ContextFrame.ContextFlags, PreviousMode);
|
|
|
|
//
|
|
// Exception was handled by the debugger or the associated subsystem
|
|
// and state was modified, if necessary, using the get state and set
|
|
// state capabilities. Therefore the context frame does not need to
|
|
// be transferred to the trap and exception frames.
|
|
//
|
|
|
|
Handled2:
|
|
return;
|
|
}
|
|
|
|
ULONG
|
|
KiCopyInformation (
|
|
IN OUT PEXCEPTION_RECORD ExceptionRecord1,
|
|
IN PEXCEPTION_RECORD ExceptionRecord2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called from an exception filter to copy the exception
|
|
information from one exception record to another when an exception occurs.
|
|
|
|
Arguments:
|
|
|
|
ExceptionRecord1 - Supplies a pointer to the destination exception record.
|
|
|
|
ExceptionRecord2 - Supplies a pointer to the source exception record.
|
|
|
|
Return Value:
|
|
|
|
A value of EXCEPTION_EXECUTE_HANDLER is returned as the function value.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Copy one exception record to another and return value that causes
|
|
// an exception handler to be executed.
|
|
//
|
|
|
|
RtlMoveMemory((PVOID)ExceptionRecord1,
|
|
(PVOID)ExceptionRecord2,
|
|
sizeof(EXCEPTION_RECORD));
|
|
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
KeRaiseUserException(
|
|
IN NTSTATUS ExceptionCode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function causes an exception to be raised in the calling thread's user-mode
|
|
context. It does this by editing the trap frame the kernel was entered with to
|
|
point to trampoline code that raises the requested exception.
|
|
|
|
Arguments:
|
|
|
|
ExceptionCode - Supplies the status value to be used as the exception
|
|
code for the exception that is to be raised.
|
|
|
|
Return Value:
|
|
|
|
The status value that should be returned by the caller.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PKTRAP_FRAME TrapFrame;
|
|
|
|
ASSERT(KeGetPreviousMode() == UserMode);
|
|
|
|
TrapFrame = KeGetCurrentThread()->TrapFrame;
|
|
|
|
TrapFrame->Fir = (ULONGLONG)(LONG_PTR)KeRaiseUserExceptionDispatcher;
|
|
return(ExceptionCode);
|
|
}
|
|
|
|
|
|
#if 0
|
|
|
|
LOGICAL
|
|
BdReportExceptionStateChange (
|
|
IN PEXCEPTION_RECORD ExceptionRecord,
|
|
IN OUT PCONTEXT ContextRecord
|
|
);
|
|
|
|
LOGICAL
|
|
BdReportLoadSymbolsStateChange (
|
|
IN PSTRING PathName,
|
|
IN PKD_SYMBOLS_INFO SymbolInfo,
|
|
IN LOGICAL UnloadSymbols,
|
|
IN OUT PCONTEXT ContextRecord
|
|
);
|
|
|
|
LOGICAL
|
|
BdPrintString (
|
|
IN PSTRING Output
|
|
);
|
|
|
|
LOGICAL
|
|
BdPromptString (
|
|
IN PSTRING Output,
|
|
IN OUT PSTRING Input
|
|
);
|
|
|
|
LOGICAL
|
|
BdTrap (
|
|
IN PEXCEPTION_RECORD ExceptionRecord,
|
|
IN PKEXCEPTION_FRAME ExceptionFrame,
|
|
IN PKTRAP_FRAME TrapFrame,
|
|
IN KPROCESSOR_MODE PreviousMode,
|
|
IN BOOLEAN FirstChance
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called whenever a exception is dispatched and the kernel
|
|
debugger is active.
|
|
|
|
Arguments:
|
|
|
|
FirmwareFrame - Supplies a pointer to a firmware frame that describes the
|
|
trap.
|
|
|
|
Return Value:
|
|
|
|
A value of TRUE is returned if the exception is handled. Otherwise a
|
|
value of FALSE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
CONTEXT ContextFrame;
|
|
LOGICAL Completion;
|
|
PCONTEXT ContextRecord;
|
|
STRING Input;
|
|
ULONGLONG OldFir;
|
|
STRING Output;
|
|
PKD_SYMBOLS_INFO SymbolInfo;
|
|
LOGICAL UnloadSymbols;
|
|
|
|
//
|
|
// Set address of context record and set context flags.
|
|
//
|
|
|
|
ContextRecord = &ContextFrame;
|
|
ContextRecord->ContextFlags = CONTEXT_FULL;
|
|
|
|
//
|
|
// Print, prompt, load symbols, and unload symbols are all special cases
|
|
// of breakpoint.
|
|
//
|
|
|
|
// BlPrint("bd: debug code entered with type %lx, p1 %lx\r\n",
|
|
// (ULONG)FirmwareFrame->Type,
|
|
// (ULONG)FirmwareFrame->Param1);
|
|
|
|
if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
|
|
(ExceptionRecord->ExceptionInformation[0] >= DEBUG_PRINT_BREAKPOINT)) {
|
|
|
|
//
|
|
// Switch on the breakpoint code.
|
|
//
|
|
|
|
UnloadSymbols = FALSE;
|
|
switch (ExceptionRecord->ExceptionInformation[0]) {
|
|
|
|
//
|
|
// Print:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// a0 - Supplies a pointer to an output string buffer.
|
|
// a1 - Supplies the length of the output string buffer.
|
|
//
|
|
|
|
case DEBUG_PRINT_BREAKPOINT:
|
|
// BlPrint("bd/debug: print\r\n");
|
|
Output.Buffer = (PCHAR)TrapFrame->IntA0;
|
|
Output.Length = (USHORT)TrapFrame->IntA1;
|
|
if (BdPrintString(&Output)) {
|
|
TrapFrame->IntV0 = STATUS_BREAKPOINT;
|
|
|
|
} else {
|
|
TrapFrame->IntV0 = STATUS_SUCCESS;
|
|
}
|
|
|
|
TrapFrame->Fir += 4;
|
|
// BlPrint("bd/debug: exit - print\r\n");
|
|
KeSweepCurrentIcache();
|
|
return TRUE;
|
|
|
|
//
|
|
// Stop in debugger:
|
|
//
|
|
// As this is not a normal breakpoint we must increment the
|
|
// context past the breakpoint instruction.
|
|
//
|
|
|
|
case BREAKIN_BREAKPOINT:
|
|
TrapFrame->Fir += 4;
|
|
break;
|
|
|
|
//
|
|
// Prompt:
|
|
//
|
|
// a0 - Supplies a pointer to an output string buffer.
|
|
// a1 - Supplies the length of the output string buffer..
|
|
// a2 - supplies a pointer to an input string buffer.
|
|
// a3 - Supplies the length of the input string bufffer.
|
|
//
|
|
|
|
case DEBUG_PROMPT_BREAKPOINT:
|
|
// BlPrint("bd/debug: prompt\r\n");
|
|
Output.Buffer = (PCHAR)TrapFrame->IntA0;
|
|
Output.Length = (USHORT)TrapFrame->IntA1;
|
|
Input.Buffer = (PCHAR)TrapFrame->IntA2;
|
|
Input.MaximumLength = (USHORT)TrapFrame->IntA3;
|
|
|
|
//
|
|
// Prompt and keep prompting until no breakin seen.
|
|
//
|
|
|
|
do {
|
|
} while(BdPromptString(&Output, &Input) != FALSE);
|
|
|
|
TrapFrame->IntV0 = Input.Length;
|
|
TrapFrame->Fir += 4;
|
|
// BlPrint("bd/debug: exit - prompt\r\n");
|
|
KeSweepCurrentIcache();
|
|
return TRUE;
|
|
|
|
//
|
|
// Unload Symbols:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// a0 - Supplies a pointer to the image path string descriptor.
|
|
// a1 - Supplies a pointer to he symbol information.
|
|
//
|
|
|
|
case DEBUG_UNLOAD_SYMBOLS_BREAKPOINT:
|
|
// BlPrint("bd/debug: unload\r\n");
|
|
UnloadSymbols = TRUE;
|
|
|
|
//
|
|
// Fall through to load symbol case.
|
|
//
|
|
|
|
case DEBUG_LOAD_SYMBOLS_BREAKPOINT:
|
|
// BlPrint("bd/debug: load\r\n");
|
|
KeContextFromKframes(TrapFrame, ExceptionFrame, ContextRecord);
|
|
OldFir = ContextRecord->Fir;
|
|
SymbolInfo = (PKD_SYMBOLS_INFO)ContextRecord->IntA1;
|
|
BdReportLoadSymbolsStateChange((PSTRING)ContextRecord->IntA0,
|
|
SymbolInfo,
|
|
UnloadSymbols,
|
|
ContextRecord);
|
|
|
|
|
|
//
|
|
// If the kernel debugger did not update the FIR, then increment
|
|
// past the breakpoint instruction.
|
|
//
|
|
|
|
if (ContextRecord->Fir == OldFir) {
|
|
ContextRecord->Fir += 4;
|
|
}
|
|
|
|
KeContextToKframes(TrapFrame,
|
|
ExceptionFrame,
|
|
ContextRecord,
|
|
ContextRecord->ContextFlags,
|
|
PreviousMode);
|
|
|
|
// BlPrint("bd/debug: exit - load/unload\r\n");
|
|
KeSweepCurrentIcache();
|
|
return TRUE;
|
|
|
|
//
|
|
// Unknown internal command.
|
|
//
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Report state change to kernel debugger on host machine.
|
|
//
|
|
|
|
// BlPrint("bd/debug: report\r\n");
|
|
KeContextFromKframes(TrapFrame, ExceptionFrame, ContextRecord);
|
|
Completion = BdReportExceptionStateChange(ExceptionRecord,
|
|
ContextRecord);
|
|
|
|
KeContextToKframes(TrapFrame,
|
|
ExceptionFrame,
|
|
ContextRecord,
|
|
ContextRecord->ContextFlags,
|
|
PreviousMode);
|
|
|
|
// BlPrint("bd/debug: exit - report\r\n");
|
|
KeSweepCurrentIcache();
|
|
return TRUE;
|
|
}
|
|
|
|
LOGICAL
|
|
BdStub (
|
|
IN PEXCEPTION_RECORD ExceptionRecord,
|
|
IN PKEXCEPTION_FRAME ExceptionFrame,
|
|
IN PKTRAP_FRAME TrapFrame,
|
|
IN KPROCESSOR_MODE PreviousMode,
|
|
IN BOOLEAN FirstChance
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine provides a kernel debugger stub routine that catchs debug
|
|
prints in checked systems when the kernel debugger is not active.
|
|
|
|
Arguments:
|
|
|
|
FirmwareFrame - Supplies a pointer to a firmware frame that describes
|
|
the trap.
|
|
|
|
Return Value:
|
|
|
|
A value of TRUE is returned if the exception is handled. Otherwise a
|
|
value of FALSE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#endif
|
|
|
|
|