windows-nt/Source/XPSP1/NT/base/ntos/ke/alpha/exceptn.c
2020-09-26 16:20:57 +08:00

1213 lines
37 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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