/*
- * ReactOS kernel
- * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * FILE: ntoskrnl/ke/i386/exp.c
+ * PURPOSE: Handling exceptions
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/*
- * PROJECT: ReactOS kernel
- * FILE: ntoskrnl/ke/i386/exp.c
- * PURPOSE: Handling exceptions
- * PROGRAMMERS: David Welch (welch@cwcom.net)
- * Skywing (skywing@valhallalegends.com)
- * REVISION HISTORY:
- * ??/??/??: Created
- * 09/12/03: KeRaiseUserException added (Skywing).
+ * PROGRAMMERS: David Welch (welch@cwcom.net)
+ * Skywing (skywing@valhallalegends.com)
*/
/* INCLUDES *****************************************************************/
-#include <roscfg.h>
-#include <ddk/ntddk.h>
-#include <internal/ntoskrnl.h>
-#include <internal/ke.h>
-#include <internal/i386/segment.h>
-#include <internal/i386/mm.h>
-#include <internal/module.h>
-#include <internal/mm.h>
-#include <internal/ps.h>
-#include <internal/trap.h>
-#include <ntdll/ldr.h>
-#include <internal/safe.h>
-#include <internal/kd.h>
-#include <internal/ldr.h>
+#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
+/*
+ * FIXMES:
+ * - Put back VEH.
+ * - Clean up file.
+ * - Sanitize some context fields.
+ * - Add PSEH handler when an exception occurs in an exception (KiCopyExceptionRecord).
+ * - Implement official stack trace functions (exported) and remove stuff here.
+ * - Forward exceptions to user-mode debugger.
+ */
+
+VOID
+NTAPI
+Ki386AdjustEsp0(IN PKTRAP_FRAME TrapFrame);
+
/* GLOBALS *****************************************************************/
#define FLAG_IF (1<<9)
#define _STR(x) #x
#define STR(x) _STR(x)
-extern void interrupt_handler2e(void);
-extern void interrupt_handler2d(void);
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
+#endif
+
+extern void KiSystemService(void);
+extern void KiDebugService(void);
extern VOID KiTrap0(VOID);
extern VOID KiTrap1(VOID);
extern VOID KiTrap14(VOID);
extern VOID KiTrap15(VOID);
extern VOID KiTrap16(VOID);
+extern VOID KiTrap17(VOID);
+extern VOID KiTrap18(VOID);
+extern VOID KiTrap19(VOID);
extern VOID KiTrapUnknown(VOID);
extern ULONG init_stack;
extern ULONG init_stack_top;
+extern BOOLEAN Ke386NoExecute;
+
static char *ExceptionTypeStrings[] =
{
"Divide Error",
"Stack Segment Fault",
"General Protection",
"Page Fault",
+ "Reserved(15)",
"Math Fault",
"Alignment Check",
- "Machine Check"
+ "Machine Check",
+ "SIMD Fault"
};
-static NTSTATUS ExceptionToNtStatus[] =
+NTSTATUS ExceptionToNtStatus[] =
{
STATUS_INTEGER_DIVIDE_BY_ZERO,
STATUS_SINGLE_STEP,
STATUS_INTEGER_OVERFLOW,
STATUS_ARRAY_BOUNDS_EXCEEDED,
STATUS_ILLEGAL_INSTRUCTION,
- STATUS_ACCESS_VIOLATION, /* STATUS_FLT_INVALID_OPERATION */
+ STATUS_FLOAT_INVALID_OPERATION,
STATUS_ACCESS_VIOLATION,
STATUS_ACCESS_VIOLATION,
STATUS_ACCESS_VIOLATION,
STATUS_STACK_OVERFLOW,
STATUS_ACCESS_VIOLATION,
STATUS_ACCESS_VIOLATION,
- STATUS_ACCESS_VIOLATION, /* STATUS_FLT_INVALID_OPERATION */
+ STATUS_ACCESS_VIOLATION, /* RESERVED */
+ STATUS_FLOAT_INVALID_OPERATION, /* Should not be used, the FPU can give more specific info */
STATUS_DATATYPE_MISALIGNMENT,
- STATUS_ACCESS_VIOLATION
+ STATUS_ACCESS_VIOLATION,
+ STATUS_FLOAT_MULTIPLE_TRAPS,
};
/* FUNCTIONS ****************************************************************/
-#ifdef KDBG
-BOOLEAN STDCALL
-KeRosPrintAddress(PVOID address)
-{
- KdbPrintAddress(address);
- return TRUE;
-}
-#else /* KDBG */
BOOLEAN STDCALL
-KeRosPrintAddress(PVOID address)
+KiRosPrintAddress(PVOID address)
{
PLIST_ENTRY current_entry;
- MODULE_TEXT_SECTION* current;
- extern LIST_ENTRY ModuleTextListHead;
+ PLDR_DATA_TABLE_ENTRY current;
+ extern LIST_ENTRY ModuleListHead;
ULONG_PTR RelativeAddress;
+ ULONG i = 0;
+
+ do
+ {
+ current_entry = ModuleListHead.Flink;
+
+ while (current_entry != &ModuleListHead)
+ {
+ current =
+ CONTAINING_RECORD(current_entry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
+
+ if (address >= (PVOID)current->DllBase &&
+ address < (PVOID)((ULONG_PTR)current->DllBase + current->SizeOfImage))
+ {
+ RelativeAddress = (ULONG_PTR) address - (ULONG_PTR) current->DllBase;
+ DbgPrint("<%wZ: %x>", ¤t->FullDllName, RelativeAddress);
+ return(TRUE);
+ }
+ current_entry = current_entry->Flink;
+ }
+
+ address = (PVOID)((ULONG_PTR)address & ~(ULONG_PTR)MmSystemRangeStart);
+ } while(++i <= 1);
- current_entry = ModuleTextListHead.Flink;
-
- while (current_entry != &ModuleTextListHead &&
- current_entry != NULL)
- {
- current =
- CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
-
- if (address >= (PVOID)current->Base &&
- address < (PVOID)(current->Base + current->Length))
- {
- RelativeAddress = (ULONG_PTR) address - current->Base;
- DbgPrint("<%ws: %x>", current->Name, RelativeAddress);
- return(TRUE);
- }
- current_entry = current_entry->Flink;
- }
return(FALSE);
}
-#endif /* KDBG */
ULONG
KiKernelTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2)
}
else
{
- if (ExceptionNr < 16)
+ if (ExceptionNr < ARRAY_SIZE(ExceptionToNtStatus))
{
Er.ExceptionCode = ExceptionToNtStatus[ExceptionNr];
}
Er.NumberParameters = 0;
}
- Er.ExceptionFlags = ((NTSTATUS) STATUS_SINGLE_STEP == (NTSTATUS) Er.ExceptionCode
- || (NTSTATUS) STATUS_BREAKPOINT == (NTSTATUS) Er.ExceptionCode) ?
- EXCEPTION_NONCONTINUABLE : 0;
+ /* FIXME: Which exceptions are noncontinuable? */
+ Er.ExceptionFlags = 0;
- KiDispatchException(&Er, 0, Tf, KernelMode, TRUE);
+ KiDispatchException(&Er, NULL, Tf, KernelMode, TRUE);
return(0);
}
-ULONG
+VOID
KiDoubleFaultHandler(VOID)
{
- unsigned int cr2_;
+ unsigned int cr2;
ULONG StackLimit;
ULONG StackBase;
ULONG Esp0;
Esp0 = OldTss->Esp;
/* Get CR2 */
-#if defined(__GNUC__)
- __asm__("movl %%cr2,%0\n\t" : "=d" (cr2_));
-#elif defined(_MSC_VER)
- __asm mov eax, cr2;
- __asm mov cr2_, eax;
-#else
-#error Unknown compiler for inline assembler
-#endif
-
+ cr2 = Ke386GetCr2();
if (PsGetCurrentThread() != NULL &&
PsGetCurrentThread()->ThreadsProcess != NULL)
{
/*
* Print out the CPU registers
*/
- if (ExceptionNr < 19)
+ if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
{
DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
ExceptionNr, 0);
DbgPrint("CS:EIP %x:%x ", OldTss->Cs, OldTss->Eip);
KeRosPrintAddress((PVOID)OldTss->Eip);
DbgPrint("\n");
- DbgPrint("cr2 %x cr3 %x ", cr2_, OldCr3);
+ DbgPrint("cr2 %x cr3 %x ", cr2, OldCr3);
DbgPrint("Proc: %x ",PsGetCurrentProcess());
if (PsGetCurrentProcess() != NULL)
{
DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
- DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
+ DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName);
}
if (PsGetCurrentThread() != NULL)
{
OldTss->Fs, OldTss->Gs);
DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss->Eax, OldTss->Ebx,
OldTss->Ecx);
- DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n ESP: %.8x", OldTss->Edx,
+ DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\nESP: %.8x ", OldTss->Edx,
OldTss->Ebp, OldTss->Esi, Esp0);
DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss->Edi, OldTss->Eflags);
if (OldTss->Cs == KERNEL_CS)
}
else
{
- StackLimit = (ULONG)&init_stack_top;
- StackBase = (ULONG)&init_stack;
+ StackLimit = (ULONG)init_stack_top;
+ StackBase = (ULONG)init_stack;
}
/*
{
KeRosPrintAddress((PVOID)Frame[1]);
Frame = (PULONG)Frame[0];
- DbgPrint(" ");
+ DbgPrint("\n");
}
#else
DbgPrint("Frames: ");
DbgPrint("\n");
for(;;);
- return 0;
}
VOID
+NTAPI
KiDumpTrapFrame(PKTRAP_FRAME Tf, ULONG Parameter1, ULONG Parameter2)
{
ULONG cr3_;
- ULONG i;
ULONG StackLimit;
- PULONG Frame;
ULONG Esp0;
ULONG ExceptionNr = (ULONG)Tf->DebugArgMark;
ULONG cr2 = (ULONG)Tf->DebugPointer;
/*
* Print out the CPU registers
*/
- if (ExceptionNr < 19)
+ if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
{
DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
ExceptionNr, Tf->ErrorCode&0xffff);
if (PsGetCurrentProcess() != NULL)
{
DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
- DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
+ DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName);
}
if (PsGetCurrentThread() != NULL)
{
}
else
{
- StackLimit = (ULONG)&init_stack_top;
+ StackLimit = (ULONG)init_stack_top;
}
/*
* Dump the stack frames
*/
- DbgPrint("Frames: ");
- /* Change to an #if 0 if no frames are printed because of fpo. */
-#if 1
- i = 1;
- Frame = (PULONG)Tf->Ebp;
- while (Frame != NULL)
- {
- NTSTATUS Status;
- PVOID Eip;
- Status = MmSafeCopyFromUser(&Eip, Frame + 1, sizeof(Eip));
- if (!NT_SUCCESS(Status))
- {
- DbgPrint("<INVALID>");
- break;
- }
- if (!KeRosPrintAddress(Eip))
- {
- DbgPrint("<%X>", Eip);
- break;
- }
- Status = MmSafeCopyFromUser(&Frame, Frame, sizeof(Frame));
- if (!NT_SUCCESS(Status))
- {
- break;
- }
- i++;
- DbgPrint(" ");
- }
-#else
- i = 1;
- Frame = (PULONG)((ULONG_PTR)Esp0 + KTRAP_FRAME_EFLAGS);
- while (Frame < (PULONG)PsGetCurrentThread()->Tcb.StackBase && i < 50)
- {
- ULONG Address = *Frame;
- if (KeRosPrintAddress((PVOID)Address))
- {
- i++;
- }
- Frame++;
- }
-#endif
+ KeDumpStackFrames((PULONG)Tf->Ebp);
}
ULONG
* Complete CPU context
*/
{
- unsigned int cr2_;
+ ULONG_PTR cr2;
NTSTATUS Status;
ULONG Esp0;
+ ASSERT(ExceptionNr != 14);
+
/* Store the exception number in an unused field in the trap frame. */
- Tf->DebugArgMark = (PVOID)ExceptionNr;
+ Tf->DebugArgMark = ExceptionNr;
/* Use the address of the trap frame as approximation to the ring0 esp */
Esp0 = (ULONG)&Tf->Eip;
/* Get CR2 */
-#if defined(__GNUC__)
- __asm__("movl %%cr2,%0\n\t" : "=d" (cr2_));
-#elif defined(_MSC_VER)
- __asm mov eax, cr2;
- __asm mov cr2_, eax;
-#else
-#error Unknown compiler for inline assembler
-#endif
- Tf->DebugPointer = (PVOID)cr2_;
+ cr2 = Ke386GetCr2();
+ Tf->DebugPointer = cr2;
/*
* If this was a V86 mode exception then handle it specially
*/
if (Tf->Eflags & (1 << 17))
{
- return(KeV86Exception(ExceptionNr, Tf, cr2_));
+ DPRINT("Tf->Eflags, %x, Tf->Eip %x, ExceptionNr: %d\n", Tf->Eflags, Tf->Eip, ExceptionNr);
+ return(KeV86Exception(ExceptionNr, Tf, cr2));
}
/*
if (PsGetCurrentThread() != NULL &&
Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
{
- DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
- Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
+ DPRINT1("Stack underflow (tf->esp %x Limit %x Eip %x)\n",
+ Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit, Tf->Eip);
ExceptionNr = 12;
}
- /*
- * Maybe handle the page fault and return
- */
- if (ExceptionNr == 14)
+ if (ExceptionNr == 15)
{
- if (Tf->Eflags & FLAG_IF)
- {
- Ke386EnableInterrupts();
- }
- Status = MmPageFault(Tf->Cs&0xffff,
- &Tf->Eip,
- &Tf->Eax,
- cr2_,
- Tf->ErrorCode);
- if (NT_SUCCESS(Status))
- {
- return(0);
- }
+ /*
+ * FIXME:
+ * This exception should never occur. The P6 has a bug, which does sometimes deliver
+ * the apic spurious interrupt as exception 15. On an athlon64, I get one exception
+ * in the early boot phase in apic mode (using the smp build). I've looked to the linux
+ * sources. Linux does ignore this exception.
+ *
+ * Hartmut Birr
+ */
+ DPRINT1("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
+ return(0);
}
/*
return(0);
}
+ /*
+ * Try to handle device-not-present, math-fault and xmm-fault exceptions.
+ */
+ if (ExceptionNr == 7 || ExceptionNr == 16 || ExceptionNr == 19)
+ {
+ Status = KiHandleFpuFault(Tf, ExceptionNr);
+ if (NT_SUCCESS(Status))
+ {
+ return(0);
+ }
+ }
+
/*
* Handle user exceptions differently
*/
if ((Tf->Cs & 0xFFFF) == USER_CS)
{
- return(KiUserTrapHandler(Tf, ExceptionNr, (PVOID)cr2_));
+ return(KiUserTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
}
else
{
- return(KiKernelTrapHandler(Tf, ExceptionNr, (PVOID)cr2_));
+ return(KiKernelTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
+ }
+}
+
+ULONG
+NTAPI
+KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
+{
+ /* Check if this is user-mode or V86 */
+ if ((TrapFrame->Cs & 1) || (TrapFrame->Eflags & X86_EFLAGS_VM))
+ {
+ /* Return it directly */
+ return TrapFrame->Esp;
+ }
+ else
+ {
+ /* Edited frame */
+ if (!(TrapFrame->Cs & FRAME_EDITED))
+ {
+ /* Return edited value */
+ return TrapFrame->TempEsp;
+ }
+ else
+ {
+ /* Virgin frame, calculate */
+ return (ULONG)&TrapFrame->Esp;
+ }
+ }
+}
+
+VOID
+NTAPI
+KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame,
+ IN ULONG Esp)
+{
+ ULONG Previous = KiEspFromTrapFrame(TrapFrame);
+
+ /* Check if this is user-mode or V86 */
+ if ((TrapFrame->Cs & 1) || (TrapFrame->Eflags & X86_EFLAGS_VM))
+ {
+ /* Write it directly */
+ TrapFrame->Esp = Esp;
+ }
+ else
+ {
+ /* Don't allow ESP to be lowered, this is illegal */
+ if (Esp < Previous)
+ {
+ KeBugCheck(SET_OF_INVALID_CONTEXT);
+ }
+
+ /* Create an edit frame, check if it was alrady */
+ if (!(TrapFrame->Cs & FRAME_EDITED))
+ {
+ /* Update the value */
+ TrapFrame->TempEsp = Esp;
+ }
+ else
+ {
+ /* Check if ESP changed */
+ if (Previous != Esp)
+ {
+ /* Save CS */
+ TrapFrame->TempCs = TrapFrame->Cs;
+ TrapFrame->Cs &= ~FRAME_EDITED;
+
+ /* Save ESP */
+ TrapFrame->TempEsp = Esp;
+ }
+ }
+ }
+}
+
+ULONG
+NTAPI
+KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
+{
+ /* If this was V86 Mode */
+ if (TrapFrame->Eflags & X86_EFLAGS_VM)
+ {
+ /* Just return it */
+ return TrapFrame->Ss;
+ }
+ else if (TrapFrame->Cs & 1)
+ {
+ /* Usermode, return the User SS */
+ return TrapFrame->Ss | 3;
+ }
+ else
+ {
+ /* Kernel mode */
+ return KERNEL_DS;
+ }
+}
+
+VOID
+NTAPI
+KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame,
+ IN ULONG Ss)
+{
+ /* Remove the high-bits */
+ Ss &= 0xFFFF;
+
+ /* If this was V86 Mode */
+ if (TrapFrame->Eflags & X86_EFLAGS_VM)
+ {
+ /* Just write it */
+ TrapFrame->Ss = Ss;
+ }
+ else if (TrapFrame->Cs & 1)
+ {
+ /* Usermode, save the User SS */
+ TrapFrame->Ss = Ss | 3;
+ }
+}
+
+BOOLEAN
+NTAPI
+KeContextToTrapFrame(IN PCONTEXT Context,
+ IN OUT PKEXCEPTION_FRAME ExceptionFrame,
+ IN OUT PKTRAP_FRAME TrapFrame,
+ IN KPROCESSOR_MODE PreviousMode)
+{
+ BOOLEAN V86Switch = FALSE;
+
+ /* Start with the basic Registers */
+ if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
+ {
+ /* Check if we went through a V86 switch */
+ if ((Context->EFlags & X86_EFLAGS_VM) !=
+ (TrapFrame->Eflags & X86_EFLAGS_VM))
+ {
+ /* We did, remember this for later */
+ V86Switch = TRUE;
+ }
+
+ /* Copy EFLAGS. FIXME: Needs to be sanitized */
+ TrapFrame->Eflags = Context->EFlags;
+
+ /* Copy EBP and EIP */
+ TrapFrame->Ebp = Context->Ebp;
+ TrapFrame->Eip = Context->Eip;
+
+ /* Check if we were in V86 Mode */
+ if (TrapFrame->Eflags & X86_EFLAGS_VM)
+ {
+ /* Simply copy the CS value */
+ TrapFrame->Cs = Context->SegCs;
+ }
+ else
+ {
+ /* We weren't in V86, so sanitize the CS (FIXME!) */
+ TrapFrame->Cs = Context->SegCs;
+
+ /* Don't let it under 8, that's invalid */
+ if ((PreviousMode !=KernelMode) && (TrapFrame->Cs < 8))
+ {
+ /* Force it to User CS */
+ TrapFrame->Cs = USER_CS;
+ }
+ }
+
+ /* Handle SS Specially for validation */
+ KiSsToTrapFrame(TrapFrame, Context->SegSs);
+
+ /* Write ESP back; take into account Edited Trap Frames */
+ KiEspToTrapFrame(TrapFrame, Context->Esp);
+
+ /* Handle our V86 Bias if we went through a switch */
+ if (V86Switch) Ki386AdjustEsp0(TrapFrame);
+ }
+
+ /* Process the Integer Registers */
+ if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
+ {
+ TrapFrame->Eax = Context->Eax;
+ TrapFrame->Ebx = Context->Ebx;
+ TrapFrame->Ecx = Context->Ecx;
+ TrapFrame->Edx = Context->Edx;
+ TrapFrame->Esi = Context->Esi;
+ TrapFrame->Edi = Context->Edi;
+ }
+
+ /* Process the Context Segments */
+ if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
+ {
+ /* Check if we were in V86 Mode */
+ if (TrapFrame->Eflags & X86_EFLAGS_VM)
+ {
+ /* Copy the V86 Segments directlry */
+ TrapFrame->V86_Ds = Context->SegDs;
+ TrapFrame->V86_Es = Context->SegEs;
+ TrapFrame->V86_Fs = Context->SegFs;
+ TrapFrame->V86_Gs = Context->SegGs;
+ }
+ else if (!(TrapFrame->Cs & 1))
+ {
+ /* For user mode, write the values directly */
+ TrapFrame->Ds = USER_DS;
+ TrapFrame->Es = USER_DS;
+ TrapFrame->Fs = Context->SegFs;
+ TrapFrame->Gs = 0;
+ }
+ else
+ {
+ /* For kernel-mode, return the values */
+ TrapFrame->Ds = Context->SegDs;
+ TrapFrame->Es = Context->SegEs;
+ TrapFrame->Fs = Context->SegFs;
+
+ /* Handle GS specially */
+ if (TrapFrame->Cs == USER_CS)
+ {
+ /* Don't use it, if user */
+ TrapFrame->Gs = 0;
+ }
+ else
+ {
+ /* Copy it if kernel */
+ TrapFrame->Gs = Context->SegGs;
+ }
+ }
+ }
+
+ /* Handle the Debug Registers */
+ if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
+ {
+ /* FIXME: All these should be sanitized */
+ TrapFrame->Dr0 = Context->Dr0;
+ TrapFrame->Dr1 = Context->Dr1;
+ TrapFrame->Dr2 = Context->Dr2;
+ TrapFrame->Dr3 = Context->Dr3;
+ TrapFrame->Dr6 = Context->Dr6;
+ TrapFrame->Dr7 = Context->Dr7;
+
+ /* Check if usermode */
+ if (PreviousMode != KernelMode)
+ {
+ /* Set the Debug Flag */
+ KeGetCurrentThread()->DispatcherHeader.DebugActive = (Context->Dr7 & DR7_ACTIVE);
+ }
+ }
+
+ /* Handle FPU and Extended Registers */
+ return KiContextToFxSaveArea((PFX_SAVE_AREA)(TrapFrame + 1), Context);
+}
+
+VOID
+NTAPI
+KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
+ IN PKEXCEPTION_FRAME ExceptionFrame,
+ IN OUT PCONTEXT Context)
+{
+ PFX_SAVE_AREA FxSaveArea = NULL;
+
+ /* Start with the Control flags */
+ if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
+ {
+ /* EBP, EIP and EFLAGS */
+ Context->Ebp = TrapFrame->Ebp;
+ Context->Eip = TrapFrame->Eip;
+ Context->EFlags = TrapFrame->Eflags;
+
+ /* Return the correct CS */
+ if (!(TrapFrame->Cs & FRAME_EDITED) &&
+ !(TrapFrame->Eflags & X86_EFLAGS_VM))
+ {
+ /* Get it from the Temp location */
+ Context->SegCs = TrapFrame->TempCs & 0xFFFF;
+ }
+ else
+ {
+ /* Return it directly */
+ Context->SegCs = TrapFrame->Cs & 0xFFFF;
+ }
+
+ /* Get the Ss and ESP */
+ Context->SegSs = KiSsFromTrapFrame(TrapFrame);
+ Context->Esp = KiEspFromTrapFrame(TrapFrame);
+ }
+
+ /* Handle the Segments */
+ if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
+ {
+ /* Do V86 Mode first */
+ if (TrapFrame->Eflags & X86_EFLAGS_VM)
+ {
+ /* Return from the V86 location */
+ Context->SegGs = TrapFrame->V86_Gs & 0xFFFF;
+ Context->SegFs = TrapFrame->V86_Fs & 0xFFFF;
+ Context->SegEs = TrapFrame->V86_Es & 0xFFFF;
+ Context->SegDs = TrapFrame->V86_Ds & 0xFFFF;
+ }
+ else
+ {
+ /* Check if this was a Kernel Trap */
+ if (TrapFrame->Cs == KERNEL_CS)
+ {
+ /* Set valid selectors */
+ TrapFrame->Gs = 0;
+ TrapFrame->Fs = PCR_SELECTOR;
+ TrapFrame->Es = USER_DS;
+ TrapFrame->Ds = USER_DS;
+ }
+
+ /* Return the segments */
+ Context->SegGs = TrapFrame->Gs & 0xFFFF;
+ Context->SegFs = TrapFrame->Fs & 0xFFFF;
+ Context->SegEs = TrapFrame->Es & 0xFFFF;
+ Context->SegDs = TrapFrame->Ds & 0xFFFF;
+ }
+ }
+
+ /* Handle the simple registers */
+ if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
+ {
+ /* Return them directly */
+ Context->Eax = TrapFrame->Eax;
+ Context->Ebx = TrapFrame->Ebx;
+ Context->Ecx = TrapFrame->Ecx;
+ Context->Edx = TrapFrame->Edx;
+ Context->Esi = TrapFrame->Esi;
+ Context->Edi = TrapFrame->Edi;
+ }
+
+ if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
+ {
+ /*
+ * FIXME: Implement this case
+ */
+ Context->ContextFlags &= (~CONTEXT_DEBUG_REGISTERS) | CONTEXT_i386;
+ }
+ if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
+ {
+ FxSaveArea = KiGetFpuState(KeGetCurrentThread());
+ if (FxSaveArea != NULL)
+ {
+ KiFxSaveAreaToFloatingSaveArea(&Context->FloatSave, FxSaveArea);
+ }
+ else
+ {
+ Context->ContextFlags &= (~CONTEXT_FLOATING_POINT) | CONTEXT_i386;
+ }
+ }
+ if ((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS)
+ {
+ if (FxSaveArea == NULL)
+ FxSaveArea = KiGetFpuState(KeGetCurrentThread());
+ if (FxSaveArea != NULL)
+ {
+ memcpy(Context->ExtendedRegisters, &FxSaveArea->U.FxArea,
+ min(sizeof (Context->ExtendedRegisters), sizeof (FxSaveArea->U.FxArea)) );
+ }
+ else
+ {
+ Context->ContextFlags &= (~CONTEXT_EXTENDED_REGISTERS) | CONTEXT_i386;
+ }
}
}
VOID
+NTAPI
KeDumpStackFrames(PULONG Frame)
{
- DbgPrint("Frames: ");
- while ( MmIsAddressValid(Frame) )
+ PULONG StackBase, StackEnd;
+ MEMORY_BASIC_INFORMATION mbi;
+ ULONG ResultLength = sizeof(mbi);
+ NTSTATUS Status;
+
+ DbgPrint("Frames:\n");
+ _SEH_TRY
{
- if (!KeRosPrintAddress((PVOID)Frame[1]))
+ Status = MiQueryVirtualMemory (
+ (HANDLE)-1,
+ Frame,
+ MemoryBasicInformation,
+ &mbi,
+ sizeof(mbi),
+ &ResultLength );
+ if ( !NT_SUCCESS(Status) )
{
- DbgPrint("<%X>", (PVOID)Frame[1]);
+ DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
+ return;
+ }
+
+ StackBase = Frame;
+ StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
+
+ while ( Frame >= StackBase && Frame < StackEnd )
+ {
+ ULONG Addr = Frame[1];
+ if (!KeRosPrintAddress((PVOID)Addr))
+ DbgPrint("<%X>", Addr);
+ if ( Addr == 0 || Addr == 0xDEADBEEF )
+ break;
+ StackBase = Frame;
+ Frame = (PULONG)Frame[0];
+ DbgPrint("\n");
}
- Frame = (PULONG)Frame[0];
- DbgPrint(" ");
}
+ _SEH_HANDLE
+ {
+ }
+ _SEH_END;
DbgPrint("\n");
}
KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount )
{
ULONG i=0;
+ PULONG StackBase, StackEnd;
+ MEMORY_BASIC_INFORMATION mbi;
+ ULONG ResultLength = sizeof(mbi);
+ NTSTATUS Status;
DbgPrint("Frames: ");
- if ( !Frame )
+ _SEH_TRY
+ {
+ if ( !Frame )
+ {
+#if defined __GNUC__
+ __asm__("mov %%ebp, %0" : "=r" (Frame) : );
+#elif defined(_MSC_VER)
+ __asm mov [Frame], ebp
+#endif
+ //Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
+ }
+
+ Status = MiQueryVirtualMemory (
+ (HANDLE)-1,
+ Frame,
+ MemoryBasicInformation,
+ &mbi,
+ sizeof(mbi),
+ &ResultLength );
+ if ( !NT_SUCCESS(Status) )
+ {
+ DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
+ return;
+ }
+
+ StackBase = Frame;
+ StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
+
+ while ( Frame >= StackBase && Frame < StackEnd && i++ < FrameCount )
+ {
+ ULONG Addr = Frame[1];
+ if (!KeRosPrintAddress((PVOID)Addr))
+ DbgPrint("<%X>", Addr);
+ if ( Addr == 0 || Addr == 0xDEADBEEF )
+ break;
+ StackBase = Frame;
+ Frame = (PULONG)Frame[0];
+ DbgPrint(" ");
+ }
+ }
+ _SEH_HANDLE
{
- __asm__("mov %%ebp, %%ebx" : "=b" (Frame) : );
- Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
}
- while ( MmIsAddressValid(Frame) && i++ < FrameCount )
+ _SEH_END;
+ DbgPrint("\n");
+}
+
+ULONG STDCALL
+KeRosGetStackFrames ( PULONG Frames, ULONG FrameCount )
+{
+ ULONG Count = 0;
+ PULONG StackBase, StackEnd, Frame;
+ MEMORY_BASIC_INFORMATION mbi;
+ ULONG ResultLength = sizeof(mbi);
+ NTSTATUS Status;
+
+ _SEH_TRY
{
- if (!KeRosPrintAddress((PVOID)Frame[1]))
+#if defined __GNUC__
+ __asm__("mov %%ebp, %0" : "=r" (Frame) : );
+#elif defined(_MSC_VER)
+ __asm mov [Frame], ebp
+#endif
+
+ Status = MiQueryVirtualMemory (
+ (HANDLE)-1,
+ Frame,
+ MemoryBasicInformation,
+ &mbi,
+ sizeof(mbi),
+ &ResultLength );
+ if ( !NT_SUCCESS(Status) )
{
- DbgPrint("<%X>", (PVOID)Frame[1]);
+ DPRINT1("Can't get stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
+ return 0;
}
- if (Frame[1] == 0xdeadbeef)
+
+ StackBase = Frame;
+ StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
+
+ while ( Count < FrameCount && Frame >= StackBase && Frame < StackEnd )
{
- break;
+ Frames[Count++] = Frame[1];
+ StackBase = Frame;
+ Frame = (PULONG)Frame[0];
}
- Frame = (PULONG)Frame[0];
- DbgPrint(" ");
}
- DbgPrint("\n");
+ _SEH_HANDLE
+ {
+ }
+ _SEH_END;
+ return Count;
}
-static void set_system_call_gate(unsigned int sel, unsigned int func)
+static void
+set_system_call_gate(unsigned int sel, unsigned int func)
{
DPRINT("sel %x %d\n",sel,sel);
KiIdt[sel].a = (((int)func)&0xffff) +
static void set_trap_gate(unsigned int sel, unsigned int func, unsigned int dpl)
{
DPRINT("set_trap_gate(sel %d, func %x, dpl %d)\n",sel, func, dpl);
- assert(dpl <= 3);
+ ASSERT(dpl <= 3);
KiIdt[sel].a = (((int)func)&0xffff) +
(KERNEL_CS << 16);
KiIdt[sel].b = 0x8f00 + (dpl << 13) + (((int)func)&0xffff0000);
KiIdt[sel].b = 0x8500;
}
-VOID INIT_FUNCTION
+VOID
+INIT_FUNCTION
+NTAPI
KeInitExceptions(VOID)
/*
* FUNCTION: Initalize CPU exception handling
set_interrupt_gate(14, (ULONG)KiTrap14);
set_trap_gate(15, (ULONG)KiTrap15, 0);
set_trap_gate(16, (ULONG)KiTrap16, 0);
+ set_trap_gate(17, (ULONG)KiTrap17, 0);
+ set_trap_gate(18, (ULONG)KiTrap18, 0);
+ set_trap_gate(19, (ULONG)KiTrap19, 0);
+
+ for (i = 20; i < 256; i++)
+ {
+ set_trap_gate(i,(int)KiTrapUnknown, 0);
+ }
+
+ set_system_call_gate(0x2d,(int)KiDebugService);
+ set_system_call_gate(0x2e,(int)KiSystemService);
+}
- for (i=17;i<256;i++)
+VOID
+NTAPI
+KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
+ PKEXCEPTION_FRAME ExceptionFrame,
+ PKTRAP_FRAME TrapFrame,
+ KPROCESSOR_MODE PreviousMode,
+ BOOLEAN FirstChance)
+{
+ CONTEXT Context;
+ KD_CONTINUE_TYPE Action;
+ ULONG_PTR Stack, NewStack;
+ ULONG Size;
+ BOOLEAN UserDispatch = FALSE;
+ DPRINT("KiDispatchException() called\n");
+
+ /* Increase number of Exception Dispatches */
+ KeGetCurrentPrcb()->KeExceptionDispatchCount++;
+
+ /* Set the context flags */
+ Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
+
+ /* Check if User Mode */
+ if (PreviousMode == UserMode)
+ {
+ extern ULONG FxsrSupport;
+ /* Add the FPU Flag */
+ Context.ContextFlags |= CONTEXT_FLOATING_POINT;
+ if (FxsrSupport)
+ Context.ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
+ }
+
+ /* Get a Context */
+ KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
+
+ /* Handle kernel-mode first, it's simpler */
+ if (PreviousMode == KernelMode)
+ {
+ /* Check if this is a first-chance exception */
+ if (FirstChance == TRUE)
{
- set_trap_gate(i,(int)KiTrapUnknown, 0);
+ /* Break into the debugger for the first time */
+ Action = KdpEnterDebuggerException(ExceptionRecord,
+ PreviousMode,
+ &Context,
+ TrapFrame,
+ TRUE,
+ TRUE);
+
+ /* If the debugger said continue, then continue */
+ if (Action == kdContinue) goto Handled;
+
+ /* If the Debugger couldn't handle it, dispatch the exception */
+ if (RtlDispatchException(ExceptionRecord, &Context))
+ {
+ /* It was handled by an exception handler, continue */
+ goto Handled;
+ }
}
- set_system_call_gate(0x2d,(int)interrupt_handler2d);
- set_system_call_gate(0x2e,(int)interrupt_handler2e);
-}
+ /* This is a second-chance exception, only for the debugger */
+ Action = KdpEnterDebuggerException(ExceptionRecord,
+ PreviousMode,
+ &Context,
+ TrapFrame,
+ FALSE,
+ FALSE);
+
+ /* If the debugger said continue, then continue */
+ if (Action == kdContinue) goto Handled;
+
+ /* Third strike; you're out */
+ KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED,
+ ExceptionRecord->ExceptionCode,
+ (ULONG_PTR)ExceptionRecord->ExceptionAddress,
+ ExceptionRecord->ExceptionInformation[0],
+ ExceptionRecord->ExceptionInformation[1],
+ TrapFrame);
+ }
+ else
+ {
+ /* User mode exception, was it first-chance? */
+ if (FirstChance)
+ {
+ /* Enter Debugger if available */
+ Action = KdpEnterDebuggerException(ExceptionRecord,
+ PreviousMode,
+ &Context,
+ TrapFrame,
+ TRUE,
+ TRUE);
+
+ /* Exit if we're continuing */
+ if (Action == kdContinue) goto Handled;
+
+ /* FIXME: Forward exception to user mode debugger */
+
+ /* Set up the user-stack */
+ _SEH_TRY
+ {
+ /* Align context size and get stack pointer */
+ Size = (sizeof(CONTEXT) + 3) & ~3;
+ Stack = (Context.Esp & ~3) - Size;
+ DPRINT("Stack: %lx\n", Stack);
+
+ /* Probe stack and copy Context */
+ ProbeForWrite((PVOID)Stack, Size, sizeof(ULONG));
+ RtlCopyMemory((PVOID)Stack, &Context, sizeof(CONTEXT));
+
+ /* Align exception record size and get stack pointer */
+ Size = (sizeof(EXCEPTION_RECORD) -
+ (EXCEPTION_MAXIMUM_PARAMETERS - ExceptionRecord->NumberParameters) *
+ sizeof(ULONG) + 3) & ~3;
+ NewStack = Stack - Size;
+ DPRINT("NewStack: %lx\n", NewStack);
+
+ /* Probe stack and copy exception record. Don't forget to add the two params */
+ ProbeForWrite((PVOID)(NewStack - 2 * sizeof(ULONG_PTR)),
+ Size + 2 * sizeof(ULONG_PTR),
+ sizeof(ULONG));
+ RtlCopyMemory((PVOID)NewStack, ExceptionRecord, Size);
+
+ /* Now write the two params for the user-mode dispatcher */
+ *(PULONG_PTR)(NewStack - 1 * sizeof(ULONG_PTR)) = Stack;
+ *(PULONG_PTR)(NewStack - 2 * sizeof(ULONG_PTR)) = NewStack;
+
+ /* Set new Stack Pointer */
+ KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR));
+
+ /* Set EIP to the User-mode Dispathcer */
+ TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher;
+ UserDispatch = TRUE;
+ _SEH_LEAVE;
+ }
+ _SEH_HANDLE
+ {
+ /* Do second-chance */
+ }
+ _SEH_END;
+ }
-/*
- * @implemented
- */
+ /* If we dispatch to user, return now */
+ if (UserDispatch) return;
-NTSTATUS STDCALL
-KeRaiseUserException(IN NTSTATUS ExceptionCode)
-{
- /* FIXME: This needs SEH */
- ULONG OldEip;
- PKTHREAD Thread = KeGetCurrentThread();
-
- ProbeForWrite(&Thread->Teb->ExceptionCode, sizeof(NTSTATUS), sizeof(NTSTATUS)); /* NT doesn't check this -- bad? */
- OldEip = Thread->TrapFrame->Eip;
- Thread->TrapFrame->Eip = (ULONG_PTR)LdrpGetSystemDllRaiseExceptionDispatcher();
- Thread->Teb->ExceptionCode = ExceptionCode;
- return((NTSTATUS)OldEip);
-}
+ /* FIXME: Forward the exception to the debugger for 2nd chance */
-VOID
-FASTCALL
-KeRosTrapReturn ( PKTRAP_FRAME TrapFrame, PKTRAP_FRAME PrevTrapFrame );
+ /* 3rd strike, kill the thread */
+ DPRINT1("Unhandled UserMode exception, terminating thread\n");
+ ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
+ KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED,
+ ExceptionRecord->ExceptionCode,
+ (ULONG_PTR)ExceptionRecord->ExceptionAddress,
+ ExceptionRecord->ExceptionInformation[0],
+ ExceptionRecord->ExceptionInformation[1],
+ TrapFrame);
+ }
+
+Handled:
+ /* Convert the context back into Trap/Exception Frames */
+ KeContextToTrapFrame(&Context, NULL, TrapFrame, PreviousMode);
+ return;
+}
/*
* @implemented
*/
NTSTATUS STDCALL
-NtRaiseException (
- IN PEXCEPTION_RECORD ExceptionRecord,
- IN PCONTEXT Context,
- IN BOOLEAN SearchFrames)
+KeRaiseUserException(IN NTSTATUS ExceptionCode)
{
- PKTRAP_FRAME TrapFrame = KeGetCurrentThread()->TrapFrame;
- PKTRAP_FRAME PrevTrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
-
- KeGetCurrentKPCR()->Tib.ExceptionList = TrapFrame->ExceptionList;
-
- KiDispatchException(ExceptionRecord,
- Context,
- PsGetCurrentThread()->Tcb.TrapFrame,
- (KPROCESSOR_MODE)ExGetPreviousMode(),
- SearchFrames);
-
- KeRosTrapReturn ( TrapFrame, PrevTrapFrame );
- return(STATUS_SUCCESS);
+ ULONG OldEip;
+ PKTHREAD Thread = KeGetCurrentThread();
+
+ _SEH_TRY {
+ Thread->Teb->ExceptionCode = ExceptionCode;
+ } _SEH_HANDLE {
+ return(ExceptionCode);
+ } _SEH_END;
+
+ OldEip = Thread->TrapFrame->Eip;
+ Thread->TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher;
+ return((NTSTATUS)OldEip);
}
+