* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/i386/exp.c
* PURPOSE: Handling exceptions
- * PROGRAMMER: David Welch (welch@cwcom.net)
+ * PROGRAMMERS: David Welch (welch@cwcom.net)
+ * Skywing (skywing@valhallalegends.com)
* REVISION HISTORY:
* ??/??/??: Created
+ * 09/12/03: KeRaiseUserException added (Skywing).
*/
/* 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 <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
#define _STR(x) #x
#define STR(x) _STR(x)
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
+#endif
+
extern void interrupt_handler2e(void);
extern void interrupt_handler2d(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;
-static char *ExceptionTypeStrings[] =
+extern BOOLEAN Ke386NoExecute;
+
+static char *ExceptionTypeStrings[] =
{
"Divide Error",
"Debug Trap",
"Stack Segment Fault",
"General Protection",
"Page Fault",
+ "Reserved(15)",
"Math Fault",
"Alignment Check",
- "Machine Check"
+ "Machine Check",
+ "SIMD Fault"
};
-static NTSTATUS ExceptionToNtStatus[] =
+static NTSTATUS ExceptionToNtStatus[] =
{
STATUS_INTEGER_DIVIDE_BY_ZERO,
STATUS_SINGLE_STEP,
STATUS_STACK_OVERFLOW,
STATUS_ACCESS_VIOLATION,
STATUS_ACCESS_VIOLATION,
+ STATUS_ACCESS_VIOLATION, /* RESERVED */
STATUS_ACCESS_VIOLATION, /* STATUS_FLT_INVALID_OPERATION */
STATUS_DATATYPE_MISALIGNMENT,
- STATUS_ACCESS_VIOLATION
+ STATUS_ACCESS_VIOLATION,
+ STATUS_ACCESS_VIOLATION /* STATUS_FLT_MULTIPLE_TRAPS? */
};
-extern unsigned int _text_start__, _text_end__;
-
/* FUNCTIONS ****************************************************************/
-STATIC BOOLEAN
-print_address(PVOID address)
+#if defined(DBG) || defined(KDBG)
+BOOLEAN STDCALL
+KeRosPrintAddress(PVOID address)
+{
+ return KdbSymPrintAddress(address);
+}
+#else /* KDBG */
+BOOLEAN STDCALL
+KeRosPrintAddress(PVOID address)
{
PLIST_ENTRY current_entry;
MODULE_TEXT_SECTION* current;
ULONG_PTR RelativeAddress;
current_entry = ModuleTextListHead.Flink;
-
+
while (current_entry != &ModuleTextListHead &&
current_entry != NULL)
{
- current =
+ current =
CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
if (address >= (PVOID)current->Base &&
}
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];
}
ULONG TraceLength;
BOOLEAN FoundRepeat;
#endif
-
+
OldTss = KeGetCurrentKPCR()->TSS;
Esp0 = OldTss->Esp;
/* Get CR2 */
- __asm__("movl %%cr2,%0\n\t" : "=d" (cr2));
-
+ cr2 = Ke386GetCr2();
if (PsGetCurrentThread() != NULL &&
PsGetCurrentThread()->ThreadsProcess != NULL)
{
- OldCr3 =
+ OldCr3 = (ULONG)
PsGetCurrentThread()->ThreadsProcess->Pcb.DirectoryTableBase.QuadPart;
}
else
{
OldCr3 = 0xBEADF0AL;
}
-
+
/*
* Check for stack underflow
*/
Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
ExceptionNr = 12;
}
-
+
/*
* Print out the CPU registers
*/
- if (ExceptionNr < 19)
+ if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
{
DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
ExceptionNr, 0);
DbgPrint("Exception: %d(%x)\n", ExceptionNr, 0);
}
DbgPrint("CS:EIP %x:%x ", OldTss->Cs, OldTss->Eip);
- print_address((PVOID)OldTss->Eip);
+ KeRosPrintAddress((PVOID)OldTss->Eip);
DbgPrint("\n");
DbgPrint("cr2 %x cr3 %x ", cr2, OldCr3);
DbgPrint("Proc: %x ",PsGetCurrentProcess());
DbgPrint("\n");
DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss->Ds, OldTss->Es,
OldTss->Fs, OldTss->Gs);
- DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss->Eax, OldTss->Ebx,
+ DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss->Eax, OldTss->Ebx,
OldTss->Ecx);
- DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", OldTss->Edx, OldTss->Ebp,
- OldTss->Esi);
+ DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n ESP: %.8x", OldTss->Edx,
+ OldTss->Ebp, OldTss->Esi, Esp0);
DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss->Edi, OldTss->Eflags);
if (OldTss->Cs == KERNEL_CS)
{
{
DbgPrint("kernel stack base %x\n",
PsGetCurrentThread()->Tcb.StackLimit);
-
+
}
}
else
}
if ((OldTss->Cs & 0xffff) == KERNEL_CS)
{
- DbgPrint("ESP %x\n", Esp0);
if (PsGetCurrentThread() != NULL)
{
StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
StackBase = (ULONG)&init_stack;
}
+ /*
+ Change to an #if 0 to reduce the amount of information printed on
+ a recursive stack trace.
+ */
#if 1
DbgPrint("Frames: ");
Frame = (PULONG)OldTss->Ebp;
while (Frame != NULL && (ULONG)Frame >= StackBase)
{
- print_address((PVOID)Frame[1]);
+ KeRosPrintAddress((PVOID)Frame[1]);
Frame = (PULONG)Frame[0];
DbgPrint(" ");
}
FoundRepeat = FALSE;
while ((j - i) <= (TraceLength - j) && FoundRepeat == FALSE)
{
- if (memcmp(&StackTrace[i], &StackTrace[j],
+ if (memcmp(&StackTrace[i], &StackTrace[j],
(j - i) * sizeof(PVOID)) == 0)
{
StackRepeatCount[i] = 2;
continue;
}
j = j + StackRepeatLength[i];
- while ((TraceLength - j) >= StackRepeatLength[i] &&
+ while ((TraceLength - j) >= StackRepeatLength[i] &&
FoundRepeat == TRUE)
{
- if (memcmp(&StackTrace[i], &StackTrace[j],
+ if (memcmp(&StackTrace[i], &StackTrace[j],
StackRepeatLength[i] * sizeof(PVOID)) == 0)
{
StackRepeatCount[i]++;
{
if (StackRepeatCount[i] == 0)
{
- print_address(StackTrace[i]);
+ KeRosPrintAddress(StackTrace[i]);
i++;
}
else
}
for (j = 0; j < StackRepeatLength[i]; j++)
{
- print_address(StackTrace[i + j]);
+ KeRosPrintAddress(StackTrace[i + j]);
}
DbgPrint("}*%d", StackRepeatCount[i]);
i = i + StackRepeatLength[i] * StackRepeatCount[i];
}
#endif
}
-
+
DbgPrint("\n");
for(;;);
+ return 0;
}
VOID
KiDumpTrapFrame(PKTRAP_FRAME Tf, ULONG Parameter1, ULONG Parameter2)
{
- ULONG cr3;
+ ULONG cr3_;
ULONG i;
ULONG StackLimit;
PULONG Frame;
ULONG cr2 = (ULONG)Tf->DebugPointer;
Esp0 = (ULONG)Tf;
-
+
/*
* 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);
}
DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
Tf->Cs&0xffff, Tf->Eip);
- print_address((PVOID)Tf->Eip);
+ KeRosPrintAddress((PVOID)Tf->Eip);
DbgPrint("\n");
- __asm__("movl %%cr3,%0\n\t" : "=d" (cr3));
- DbgPrint("cr2 %x cr3 %x ", cr2, cr3);
+ Ke386GetPageTableDirectory(cr3_);
+ DbgPrint("cr2 %x cr3 %x ", cr2, cr3_);
DbgPrint("Proc: %x ",PsGetCurrentProcess());
if (PsGetCurrentProcess() != NULL)
{
DbgPrint("DS %x ES %x FS %x GS %x\n", Tf->Ds&0xffff, Tf->Es&0xffff,
Tf->Fs&0xffff, Tf->Gs&0xfff);
DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf->Eax, Tf->Ebx, Tf->Ecx);
- DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", Tf->Edx, Tf->Ebp, Tf->Esi);
+ DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", Tf->Edx,
+ Tf->Ebp, Tf->Esi, Esp0);
DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf->Edi, Tf->Eflags);
if ((Tf->Cs&0xffff) == KERNEL_CS)
{
{
DbgPrint("kernel stack base %x\n",
PsGetCurrentThread()->Tcb.StackLimit);
-
+
}
}
- DbgPrint("ESP %x\n", Esp0);
-
if (PsGetCurrentThread() != NULL)
{
StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
{
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)
{
- print_address((PVOID)Frame[1]);
- Frame = (PULONG)Frame[0];
+ NTSTATUS Status;
+ PVOID Eip;
+ Status = MmSafeCopyFromUser(&Eip, Frame + 1, sizeof(Eip));
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("<INVALID>");
+ break;
+ }
+ if (!KeRosPrintAddress(Eip))
+ {
+ DbgPrint("<%X>", Eip);
+ }
+ 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
}
ULONG
KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr)
/*
- * FUNCTION: Called by the lowlevel execption handlers to print an amusing
+ * FUNCTION: Called by the lowlevel execption handlers to print an amusing
* message and halt the computer
* ARGUMENTS:
* Complete CPU context
/* Use the address of the trap frame as approximation to the ring0 esp */
Esp0 = (ULONG)&Tf->Eip;
-
+
/* Get CR2 */
- __asm__("movl %%cr2,%0\n\t" : "=d" (cr2));
+ cr2 = Ke386GetCr2();
Tf->DebugPointer = (PVOID)cr2;
-
+
+ if (ExceptionNr == 14 && Tf->Eflags & FLAG_IF)
+ {
+ Ke386EnableInterrupts();
+ }
+
/*
* If this was a V86 mode exception then handle it specially
*/
*/
if (ExceptionNr == 14)
{
- if (Tf->Eflags & FLAG_IF)
+ if (Ke386NoExecute && Tf->ErrorCode & 0x10 && cr2 >= KERNEL_BASE)
{
- __asm__("sti\n\t");
+ KEBUGCHECKWITHTF(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY, 0, 0, 0, 0, Tf);
}
Status = MmPageFault(Tf->Cs&0xffff,
&Tf->Eip,
}
}
+ /*
+ * Check for a breakpoint that was only for the attention of the debugger.
+ */
+ if (ExceptionNr == 3 && Tf->Eip == ((ULONG)DbgBreakPointNoBugCheck) + 1)
+ {
+ /*
+ EIP is already adjusted by the processor to point to the instruction
+ after the breakpoint.
+ */
+ 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
*/
}
}
-VOID
+VOID
KeDumpStackFrames(PULONG Frame)
{
- ULONG i;
+ DbgPrint("Frames: ");
+ while ( MmIsAddressValid(Frame) )
+ {
+ ULONG Addr = Frame[1];
+ if (!KeRosPrintAddress((PVOID)Addr))
+ DbgPrint("<%X>", Addr);
+ if ( Addr == 0 || Addr == 0xDEADBEEF )
+ break;
+ Frame = (PULONG)Frame[0];
+ DbgPrint(" ");
+ }
+ DbgPrint("\n");
+}
- DbgPrint("Frames: ");
- i = 1;
- while (Frame != NULL)
- {
- print_address((PVOID)Frame[1]);
- Frame = (PULONG)Frame[0];
- i++;
- DbgPrint(" ");
- }
+VOID STDCALL
+KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount )
+{
+ ULONG i=0;
+
+ DbgPrint("Frames: ");
+ if ( !Frame )
+ {
+#if defined __GNUC__
+ __asm__("mov %%ebp, %%ebx" : "=b" (Frame) : );
+#elif defined(_MSC_VER)
+ __asm mov [Frame], ebp
+#endif
+ Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
+ }
+ while ( MmIsAddressValid(Frame) && i++ < FrameCount )
+ {
+ ULONG Addr = Frame[1];
+ if (!KeRosPrintAddress((PVOID)Addr))
+ DbgPrint("<%X>", Addr);
+ if ( Addr == 0 || Addr == 0xDEADBEEF )
+ break;
+ Frame = (PULONG)Frame[0];
+ DbgPrint(" ");
+ }
+ DbgPrint("\n");
}
static void set_system_call_gate(unsigned int sel, unsigned int func)
DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel,func);
KiIdt[sel].a = (((int)func)&0xffff) +
(KERNEL_CS << 16);
- KiIdt[sel].b = 0x8e00 + (((int)func)&0xffff0000);
+ KiIdt[sel].b = 0x8e00 + (((int)func)&0xffff0000);
}
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 = 0x8f00 + (dpl << 13) + (((int)func)&0xffff0000);
}
static void
KiIdt[sel].b = 0x8500;
}
-VOID
+VOID INIT_FUNCTION
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);
-
- for (i=17;i<256;i++)
- {
- set_trap_gate(i,(int)KiTrapUnknown, 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)interrupt_handler2d);
set_system_call_gate(0x2e,(int)interrupt_handler2e);
}
+
+/*
+ * @implemented
+ */
+
+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);
+}
+
+VOID
+FASTCALL
+KeRosTrapReturn ( PKTRAP_FRAME TrapFrame, PKTRAP_FRAME PrevTrapFrame );
+
+/*
+ * @implemented
+ */
+NTSTATUS STDCALL
+NtRaiseException (
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PCONTEXT Context,
+ IN BOOLEAN SearchFrames)
+{
+ 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);
+}