Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1068 lines
33 KiB

/*++
Module Name:
exceptn.c
Abstract:
This module implement the code necessary to dispatch expections to the
proper mode and invoke the exception dispatcher.
Author:
William K. Cheung (wcheung) 10-Nov-1995
Environment:
Kernel mode only.
Revision History:
--*/
#include "ki.h"
#include "ntfpia64.h"
#include "floatem.h"
BOOLEAN
KiSingleStep (
IN PKTRAP_FRAME TrapFrame
);
LONG
fp_emulate (
ULONG trap_type,
PVOID pbundle,
ULONGLONG *pipsr,
ULONGLONG *pfpsr,
ULONGLONG *pisr,
ULONGLONG *ppreds,
ULONGLONG *pifs,
PVOID fp_state
);
BOOLEAN
KiEmulateFloat (
IN PEXCEPTION_RECORD ExceptionRecord,
IN PKEXCEPTION_FRAME ExceptionFrame,
IN PKTRAP_FRAME TrapFrame,
IN KPROCESSOR_MODE PreviousMode
)
{
FLOATING_POINT_STATE FpState;
USHORT ISRCode;
ULONG TrapType;
PVOID ExceptionAddress;
BUNDLE KeBundle;
BOOLEAN ReturnStatus = FALSE;
KIRQL OldIrql = PASSIVE_LEVEL;
LOGICAL RestoreIrql = FALSE;
LONG Status = -1;
//
// If we are executing x86 instructions, then bail out now.
//
if ((TrapFrame->StIPSR & (0x1i64 << PSR_IS)) != 0) {
goto ErrorReturn;
}
FpState.ExceptionFrame = (PVOID)ExceptionFrame;
FpState.TrapFrame = (PVOID)TrapFrame;
if (ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_FAULTS) {
TrapType = 1;
ExceptionAddress = (PVOID)TrapFrame->StIIP;
} else {
TrapType = 0;
ExceptionAddress = (PVOID)TrapFrame->StIIPA;
}
//
// Block APC's so that a set context does not
// change the trap frame during emulation.
//
if (KeGetCurrentIrql() < APC_LEVEL) {
RestoreIrql = TRUE;
KeRaiseIrql (APC_LEVEL, &OldIrql);
}
//
// If the trap frame has been modifed since the exception and
// this is a trap rather than fault, just
// reexecute the instruction again.
//
if ((TrapFrame->EOFMarker & MODIFIED_FRAME) && (TrapType == 1)) {
ReturnStatus = TRUE;
goto ErrorReturn;
}
try {
if (PreviousMode != KernelMode) {
ProbeForReadSmallStructure(ExceptionAddress, sizeof(KeBundle), TYPE_ALIGNMENT(BUNDLE));
}
KeBundle.BundleLow =(ULONGLONG)(*(PULONGLONG)ExceptionAddress);
KeBundle.BundleHigh =(ULONGLONG)(*((PULONGLONG)ExceptionAddress + 1));
} except (EXCEPTION_EXECUTE_HANDLER) {
//
// if an exception (memory fault) occurs, then let hardware handle it
//
ReturnStatus = TRUE;
goto ErrorReturn;
}
if ((Status = fp_emulate(TrapType, &KeBundle,
&TrapFrame->StIPSR, &TrapFrame->StFPSR, &TrapFrame->StISR,
&TrapFrame->Preds, &TrapFrame->StIFS, (PVOID)&FpState)) == 0) {
//
// Exception was handled and state modified.
// Therefore the context frame does not need to
// be transfered to the trap and exception frames.
//
// Since it was fault, PC should be advanced
//
if (TrapType == 1) {
KiAdvanceInstPointer(TrapFrame);
}
if (TrapFrame->StIPSR & (1 << PSR_MFH)) {
//
// high fp set is modified; set the dfh and clear the mfh
// to force a reload on the first access to the high fp set
//
TrapFrame->StIPSR &= ~(1i64 << PSR_MFH);
TrapFrame->StIPSR |= (1i64 << PSR_DFH);
}
ReturnStatus = TRUE;
goto ErrorReturn;
}
if (Status == -1) {
goto ErrorReturn;
}
ISRCode = (USHORT)TrapFrame->StISR;
if (Status & 0x1) {
ExceptionRecord->ExceptionInformation[4] = TrapFrame->StISR;
if (!(Status & 0x4)) {
if (TrapType == 1) {
//
// FP Fault
//
if (ISRCode & 0x11) {
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
} else if (ISRCode & 0x22) {
ExceptionRecord->ExceptionCode = STATUS_FLOAT_DENORMAL_OPERAND;
} else if (ISRCode & 0x44) {
ExceptionRecord->ExceptionCode = STATUS_FLOAT_DIVIDE_BY_ZERO;
}
} else {
//
// FP Trap
//
ISRCode = ISRCode >> 7;
if (ISRCode & 0x11) {
ExceptionRecord->ExceptionCode = STATUS_FLOAT_OVERFLOW;
} else if (ISRCode & 0x22) {
ExceptionRecord->ExceptionCode = STATUS_FLOAT_UNDERFLOW;
} else if (ISRCode & 0x44) {
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
}
}
}
if (Status & 0x2) {
//
// FP Fault To Trap
//
KiAdvanceInstPointer(TrapFrame);
if (!(Status & 0x4)) {
ISRCode = ISRCode >> 7;
if (ISRCode & 0x11) {
ExceptionRecord->ExceptionCode = STATUS_FLOAT_OVERFLOW;
} else if (ISRCode & 0x22) {
ExceptionRecord->ExceptionCode = STATUS_FLOAT_UNDERFLOW;
} else if (ISRCode & 0x44) {
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
}
} else {
ExceptionRecord->ExceptionCode = STATUS_FLOAT_MULTIPLE_TRAPS;
}
}
}
ErrorReturn:
if (RestoreIrql) {
KeLowerIrql (OldIrql);
}
return ReturnStatus;
}
typedef struct _BRL_INST {
union {
struct {
ULONGLONG qp: 6;
ULONGLONG b1: 3;
ULONGLONG rsv0: 3;
ULONGLONG p: 1;
ULONGLONG imm20: 20;
ULONGLONG wh: 2;
ULONGLONG d: 1;
ULONGLONG i: 1;
ULONGLONG Op: 4;
ULONGLONG rsv1: 23;
} i;
ULONGLONG Ulong64;
} u;
} BRL_INST;
typedef struct _BRL2_INST {
union {
struct {
ULONGLONG rsv0: 2;
ULONGLONG imm39: 39;
ULONGLONG rsv1: 23;
} i;
ULONGLONG Ulong64;
} u;
} BRL0_INST;
typedef struct _FRAME_MARKER {
union {
struct {
ULONGLONG sof : 7;
ULONGLONG sol : 7;
ULONGLONG sor : 4;
ULONGLONG rrbgr : 7;
ULONGLONG rrbfr : 7;
ULONGLONG rrbpr : 6;
} f;
ULONGLONG Ulong64;
} u;
} FRAME_MARKER;
BOOLEAN
KiEmulateBranchLongFault(
IN PEXCEPTION_RECORD ExceptionRecord,
IN OUT PKEXCEPTION_FRAME ExceptionFrame,
IN OUT PKTRAP_FRAME TrapFrame,
IN KPROCESSOR_MODE PreviousMode
)
/*++
Routine Description:
This function is called to emulate a brl instruction.
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.
Return Value:
A value of TRUE is return if the brl is successfully emulated.
Otherwise, a value of FALSE is returned.
--*/
{
PULONGLONG BundleAddress;
PVOID ExceptionAddress;
ULONGLONG BundleLow;
ULONGLONG BundleHigh;
ULONGLONG Template;
BRL_INST BrlInst;
BRL0_INST BrlInst0;
ULONGLONG NewIP;
ULONGLONG Taken;
FRAME_MARKER Cfm;
BOOLEAN ReturnStatus = FALSE;
KIRQL OldIrql = PASSIVE_LEVEL;
LOGICAL RestoreIrql = FALSE;
//
// Block APC's so that a set context does not
// change the trap frame during emulation.
//
if (KeGetCurrentIrql() < APC_LEVEL) {
RestoreIrql = TRUE;
KeRaiseIrql (APC_LEVEL, &OldIrql);
}
//
// Verified that the Exception address has not changed. If it has
// then someone did a set context after the exception and the
// trap information is no longer valid.
//
if ((TrapFrame->EOFMarker & MODIFIED_FRAME) != 0) {
//
// The IIP has changed just restart the execution.
//
ReturnStatus = TRUE;
goto ErrorExit;
}
BundleAddress = (PULONGLONG)TrapFrame->StIIP;
ExceptionAddress = (PVOID) TrapFrame->StIIP;
try {
if (PreviousMode != KernelMode) {
ProbeForReadSmallStructure(ExceptionAddress, sizeof(ULONGLONG) * 2, TYPE_ALIGNMENT(ULONGLONG));
}
//
// get the instruction bundle
//
BundleLow = *BundleAddress;
BundleHigh = *(BundleAddress+1);
} except ((KiCopyInformation(ExceptionRecord,
(GetExceptionInformation())->ExceptionRecord))) {
//
// Preserve the original exception address.
//
ExceptionRecord->ExceptionAddress = ExceptionAddress;
goto ErrorExit;
}
BrlInst0.u.Ulong64 = (BundleLow >> 46) | (BundleHigh << 18);
BrlInst.u.Ulong64 = (BundleHigh >> 23);
Template = BundleLow & 0x1f;
if (!((Template == 4)||(Template == 5))) {
//
// if template does not indicate MLX, return FALSE
//
goto ErrorExit;
}
switch (BrlInst.u.i.Op) {
case 0xc: // brl.cond
Taken = TrapFrame->Preds & (1i64 << BrlInst.u.i.qp);
break;
case 0xd: // brl.call
Taken = TrapFrame->Preds & (1i64 << BrlInst.u.i.qp);
if (Taken) {
switch (BrlInst.u.i.b1) {
case 0: TrapFrame->BrRp = TrapFrame->StIIP + 16; break;
case 1: ExceptionFrame->BrS0 = TrapFrame->StIIP + 16; break;
case 2: ExceptionFrame->BrS1 = TrapFrame->StIIP + 16; break;
case 3: ExceptionFrame->BrS2 = TrapFrame->StIIP + 16; break;
case 4: ExceptionFrame->BrS3 = TrapFrame->StIIP + 16; break;
case 5: ExceptionFrame->BrS4 = TrapFrame->StIIP + 16; break;
case 6: TrapFrame->BrT0 = TrapFrame->StIIP + 16; break;
case 7: TrapFrame->BrT1 = TrapFrame->StIIP + 16; break;
}
TrapFrame->RsPFS = TrapFrame->StIFS & 0x3FFFFFFFFFi64;
TrapFrame->RsPFS |= (ExceptionFrame->ApEC & (0x3fi64 << PFS_EC_SHIFT));
TrapFrame->RsPFS |= (((TrapFrame->StIPSR >> PSR_CPL) & 0x3) << PFS_PPL);
Cfm.u.Ulong64 = TrapFrame->StIFS;
Cfm.u.f.sof -= Cfm.u.f.sol;
Cfm.u.f.sol = 0;
Cfm.u.f.sor = 0;
Cfm.u.f.rrbgr = 0;
Cfm.u.f.rrbfr = 0;
Cfm.u.f.rrbpr = 0;
TrapFrame->StIFS = Cfm.u.Ulong64;
TrapFrame->StIFS |= 0x8000000000000000;
}
break;
default:
goto ErrorExit;
}
if (Taken) {
NewIP = TrapFrame->StIIP +
(((BrlInst.u.i.i<<59)|(BrlInst0.u.i.imm39<<20)|(BrlInst.u.i.imm20)) << 4);
TrapFrame->StIIP = NewIP;
} else {
TrapFrame->StIIP += 16;
}
TrapFrame->StIPSR &= ~(3i64 << PSR_RI);
ReturnStatus = TRUE;
ErrorExit:
if (RestoreIrql) {
KeLowerIrql(OldIrql);
}
return ReturnStatus;
}
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, 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.
If the exception is a floating exception (N.B. the pseudo status
STATUS_FLOAT_STACK_CHECK is used to signify this and is converted to the
proper code by examiningg the main status field of the floating point
status register).
If the exception is neither a data misalignment nor a floating point
exception and the 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
commense 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;
PPLABEL_DESCRIPTOR Plabel;
BOOLEAN UserApcPending;
BOOLEAN AlignmentFaultHandled;
BOOLEAN ExceptionWasForwarded = FALSE;
ISR Isr;
PSR Psr;
//
// If the exception is a illegal instruction, check to see if it was
// trying to executing a brl instruction. If so, emulate the brl
// instruction.
//
if (ExceptionRecord->ExceptionCode == STATUS_ILLEGAL_INSTRUCTION) {
Isr.ull = TrapFrame->StISR;
Psr.ull = TrapFrame->StIPSR;
if ((Isr.sb.isr_code == ISR_ILLEGAL_OP) && (Isr.sb.isr_ei == 1)) {
if (KiEmulateBranchLongFault(ExceptionRecord,
ExceptionFrame,
TrapFrame,
PreviousMode) == TRUE) {
//
// emulation was successful;
//
return;
}
}
}
//
// If the exception is a data misalignment, the previous mode was user,
// this is the first chance for handling the exception, and the current
// thread has enabled automatic alignment fixup, then attempt to emulate
// the unaligned reference.
//
if (ExceptionRecord->ExceptionCode == STATUS_DATATYPE_MISALIGNMENT) {
AlignmentFaultHandled = KiHandleAlignmentFault( ExceptionRecord,
ExceptionFrame,
TrapFrame,
PreviousMode,
FirstChance,
&ExceptionWasForwarded );
if (AlignmentFaultHandled != FALSE) {
if (TrapFrame->StIPSR & MASK_IA64(PSR_SS, 1i64)) {
//
// if psr.ss is set when the unaligned fault is taken,
// transform this exception into a single step trap exception
//
KiSingleStep(TrapFrame);
} else {
goto Handled2;
}
}
}
//
// N.B. BREAKIN_BREAKPOINT check is in KdpTrap()
//
//
// If the exception is a floating point exception, then the
// ExceptionCode was set to STATUS_FLOAT_MULTIPLE_TRAPS or
// STATUS_FLOAT_MULTIPLE_FAULTS.
//
if ((ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_FAULTS) ||
(ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS)) {
if (KiEmulateFloat(ExceptionRecord, ExceptionFrame, TrapFrame, PreviousMode)) {
//
// Emulation is successful; continue execution
//
return;
}
}
//
// Move machine state from trap and exception frames to a context frame,
// and increment the number of exceptions dispatched.
//
ContextFrame.ContextFlags = CONTEXT_FULL;
KeContextFromKframes(TrapFrame, ExceptionFrame, &ContextFrame);
KeGetCurrentPrcb()->KeExceptionDispatchCount += 1;
//
// Select the method of handling the exception based on the previous mode.
//
if (PreviousMode == KernelMode) {
//
// Previous mode was kernel.
//
// If this is the first chance, the kernel debugger is active, and
// the exception is a kernel breakpoint, then give the kernel debugger
// a chance to handle the exception.
//
// If this is the first chance and the kernel debugger is not active
// or does not handle the exception, then attempt to find a frame
// handler to handle the exception.
//
// 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 does
// not handle the exception, then bug check.
//
if (FirstChance != FALSE) {
//
// This is the first chance to handle the exception.
//
// Note: RtlpCaptureRnats() flushes the RSE and captures the
// Nat bits of stacked registers in the RSE frame at
// which exception happens.
//
RtlpCaptureRnats(&ContextFrame);
TrapFrame->RsRNAT = ContextFrame.RsRNAT;
//
// If the kernel debugger is active, the exception is a breakpoint,
// and the breakpoint is handled by the kernel debugger, then give
// the kernel debugger a chance to handle the exception.
//
if ((KiDebugRoutine != NULL) &&
(KdIsThisAKdTrap(ExceptionRecord,
&ContextFrame,
KernelMode) != FALSE)) {
if (((KiDebugRoutine) (TrapFrame,
ExceptionFrame,
ExceptionRecord,
&ContextFrame,
KernelMode,
FALSE)) != FALSE) {
goto Handled1;
}
}
if (RtlDispatchException(ExceptionRecord, &ContextFrame) != FALSE) {
goto Handled1;
}
}
//
// This is the second chance to handle the exception.
//
if (KiDebugRoutine != NULL) {
if (((KiDebugRoutine) (TrapFrame,
ExceptionFrame,
ExceptionRecord,
&ContextFrame,
PreviousMode,
TRUE)) != FALSE) {
goto Handled1;
}
}
KeBugCheckEx(KERNEL_MODE_EXCEPTION_NOT_HANDLED,
ExceptionRecord->ExceptionCode,
(ULONG_PTR)ExceptionRecord->ExceptionAddress,
(ULONG_PTR)TrapFrame,
0);
} else {
//
// Previous mode was user.
//
// If this is the first chance, the kernel debugger is active, the
// exception is a kernel breakpoint, and the current process is not
// being debugged, or the current process is being debugged, but the
// the breakpoint is not a kernel breakpoint instruction, then give
// the kernel debugger a chance to handle the exception.
//
// 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. Else
// 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. Else
// 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. Else terminate the thread.
//
if (FirstChance != FALSE) {
//
// If the kernel debugger is active, the exception is a kernel
// breakpoint, and the current process is not being debugged,
// or the current process is being debugged, but the breakpoint
// is not a kernel breakpoint instruction, then give the kernel
// debugger a chance to handle the exception.
//
if ((KiDebugRoutine != NULL) &&
(KdIsThisAKdTrap(ExceptionRecord,
&ContextFrame,
UserMode) != FALSE) &&
((PsGetCurrentProcess()->DebugPort == NULL &&
!KdIgnoreUmExceptions) ||
((PsGetCurrentProcess()->DebugPort != NULL) &&
(((ExceptionRecord->ExceptionInformation[0] !=
BREAKPOINT_STOP) &&
(ExceptionRecord->ExceptionCode != STATUS_WX86_BREAKPOINT)) &&
(ExceptionRecord->ExceptionCode != STATUS_SINGLE_STEP))))) {
if (((KiDebugRoutine) (TrapFrame,
ExceptionFrame,
ExceptionRecord,
&ContextFrame,
UserMode,
FALSE)) != FALSE) {
goto Handled1;
}
}
//
// This is the first chance to handle the exception.
//
if (ExceptionWasForwarded == 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.
//
//
// We are running on the kernel stack now. On the user stack, we
// build a stack frame containing the following:
//
// | |
// |-----------------------------------|
// | |
// | User's stack frame |
// | |
// |-----------------------------------|
// | |
// | Context record |
// | |
// | |
// |- - - - - - - - - - - - - - - - - -|
// | |
// | Exception record |
// | |
// |- - - - - - - - - - - - - - - - - -|
// | Stack Scratch Area |
// |-----------------------------------|
// | |
//
// This stack frame is for KiUserExceptionDispatcher, the assembly
// langauge routine that effects transfer in user mode to
// RtlDispatchException. KiUserExceptionDispatcher is passed
// pointers to the Exception Record and Context Record as
// parameters.
//
ExceptionRecord1.ExceptionCode = STATUS_SUCCESS;
repeat:
try {
//
// Compute length of exception record and new aligned stack
// address.
//
ULONG Length = (STACK_SCRATCH_AREA + 15 +
sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)) & ~(15);
ULONGLONG UserStack = (ContextFrame.IntSp & (~15)) - Length;
ULONGLONG ContextSlot = UserStack + STACK_SCRATCH_AREA;
ULONGLONG ExceptSlot = ContextSlot + sizeof(CONTEXT);
//
// When the exception gets dispatched to the user the
// user BSP state will be loaded. Clear the preload
// count in the RSE so it is not reloaded after if the
// context is reused.
//
ContextFrame.RsRSC = ZERO_PRELOAD_SIZE(ContextFrame.RsRSC);
//
// Probe user stack area for writeability and then transfer the
// exception record and conext record to the user stack area.
//
ProbeForWrite((PCHAR)UserStack, Length, sizeof(QUAD));
RtlCopyMemory((PVOID)ContextSlot, &ContextFrame,
sizeof(CONTEXT));
RtlCopyMemory((PVOID)ExceptSlot, ExceptionRecord,
sizeof(EXCEPTION_RECORD));
//
// Set address of exception record and context record in
// the exception frame and the new stack pointer in the
// current trap frame. Also set the initial frame size
// to be zero.
//
// N.B. User exception dispatcher flushes the RSE
// and updates the BSPStore field upon entry.
//
TrapFrame->RsPFS = SANITIZE_PFS(TrapFrame->StIFS, UserMode);
TrapFrame->StIFS &= 0xffffffc000000000i64;
TrapFrame->StIPSR &= ~((0x3i64 << PSR_RI) | (0x1i64 << PSR_IS));
if (ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP) {
//
// If this is a Single step event the clear the those flags, so
// the handler does not get called with them turned on.
//
((struct _PSR *) &TrapFrame->StIPSR)->psr_ss = 0;
((struct _PSR *) &TrapFrame->StIPSR)->psr_db = 0;
((struct _PSR *) &TrapFrame->StIPSR)->psr_tb = 0;
}
TrapFrame->IntSp = UserStack;
TrapFrame->IntNats = 0;
//
// reset the user FPSR so that a recursive exception will not occur.
//
// TrapFrame->StFPSR = USER_FPSR_INITIAL;
ExceptionFrame->IntS0 = ExceptSlot;
ExceptionFrame->IntS1 = ContextSlot;
ExceptionFrame->IntNats = 0;
//
// Set the address and the gp 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.
//
Plabel = (PPLABEL_DESCRIPTOR)KeUserExceptionDispatcher;
TrapFrame->StIIP = Plabel->EntryPoint;
TrapFrame->IntGp = Plabel->GlobalPointer;
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;
RtlCopyMemory((PVOID)ExceptionRecord,
&ExceptionRecord1, sizeof(EXCEPTION_RECORD));
goto repeat;
}
}
}
//
// This is the second chance to handle the exception.
//
UserApcPending = KeGetCurrentThread()->ApcState.UserApcPending;
if (DbgkForwardException(ExceptionRecord, TRUE, TRUE)) {
goto Handled2;
} else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE)) {
goto Handled2;
} else {
ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode);
KeBugCheckEx(KERNEL_MODE_EXCEPTION_NOT_HANDLED,
ExceptionRecord->ExceptionCode,
(ULONG_PTR)ExceptionRecord->ExceptionAddress,
(ULONG_PTR)TrapFrame,
0);
}
}
//
// 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 transfered 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.
//
RtlCopyMemory((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.
--*/
{
PKTHREAD Thread;
PKTRAP_FRAME TrapFrame;
IA64_PFS Ifs;
PTEB Teb;
Thread = KeGetCurrentThread();
TrapFrame = Thread->TrapFrame;
if (TrapFrame == NULL || TrapFrame->PreviousMode != UserMode) {
return ExceptionCode;
}
Teb = (PTEB)Thread->Teb;
try {
PULONGLONG IntSp;
Teb->ExceptionCode = ExceptionCode;
IntSp = (PULONGLONG) TrapFrame->IntSp;
ProbeForWriteSmallStructure (IntSp, sizeof (*IntSp)*2, sizeof(QUAD));
*IntSp++ = TrapFrame->BrRp;
*IntSp = TrapFrame->RsPFS;
TrapFrame->StIIP = ((PPLABEL_DESCRIPTOR)KeRaiseUserExceptionDispatcher)->EntryPoint;
} except (EXCEPTION_EXECUTE_HANDLER) {
return (ExceptionCode);
}
//
// Set IFS the size after the the system call.
//
Ifs.ull = TrapFrame->StIFS;
Ifs.sb.pfs_sof = Ifs.sb.pfs_sof - Ifs.sb.pfs_sol;
Ifs.sb.pfs_sol = 0;
TrapFrame->StIFS = Ifs.ull;
return(ExceptionCode);
}