Author: tkreuzer
Date: Wed Apr 18 13:39:19 2012
New Revision: 56357
URL:
http://svn.reactos.org/svn/reactos?rev=56357&view=rev
Log:
[NTOSKRNL]
- Implement saving / restoring debug registers on traps
- Replace the loop in KeContextToTrapFrame with something less ridiculous
- fixes a number of ntdd exception winetests
Modified:
trunk/reactos/ntoskrnl/include/internal/i386/ke.h
trunk/reactos/ntoskrnl/include/internal/i386/trap_x.h
trunk/reactos/ntoskrnl/ke/i386/exp.c
trunk/reactos/ntoskrnl/ke/i386/traphdlr.c
trunk/reactos/ntoskrnl/ke/i386/v86vdm.c
Modified: trunk/reactos/ntoskrnl/include/internal/i386/ke.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/i386/ke.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/i386/ke.h [iso-8859-1] Wed Apr 18 13:39:19
2012
@@ -540,28 +540,6 @@
}
//
-// Gets a DR register from a CONTEXT structure
-//
-FORCEINLINE
-PVOID
-KiDrFromContext(IN ULONG Dr,
- IN PCONTEXT Context)
-{
- return *(PVOID*)((ULONG_PTR)Context + KiDebugRegisterContextOffsets[Dr]);
-}
-
-//
-// Gets a DR register from a KTRAP_FRAME structure
-//
-FORCEINLINE
-PVOID*
-KiDrFromTrapFrame(IN ULONG Dr,
- IN PKTRAP_FRAME TrapFrame)
-{
- return (PVOID*)((ULONG_PTR)TrapFrame + KiDebugRegisterTrapOffsets[Dr]);
-}
-
-//
// Sanitizes a Debug Register
//
FORCEINLINE
Modified: trunk/reactos/ntoskrnl/include/internal/i386/trap_x.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/i386/trap_x.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/i386/trap_x.h [iso-8859-1] Wed Apr 18 13:39:19
2012
@@ -95,18 +95,37 @@
TrapFrame->PreviousPreviousMode = -1;
}
+#define DR7_RESERVED_READ_AS_1 0x400
+
+#define CheckDr(DrNumner, ExpectedValue) \
+ { \
+ ULONG DrValue = __readdr(DrNumner); \
+ if (DrValue != (ExpectedValue)) \
+ { \
+ DbgPrint("Dr%ld: expected %.8lx, got %.8lx\n", \
+ DrNumner, ExpectedValue, DrValue); \
+ __debugbreak(); \
+ } \
+ }
+
+extern BOOLEAN StopChecking;
+
VOID
FORCEINLINE
KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame,
IN BOOLEAN SkipPreviousMode)
{
+ /* Don't check recursively */
+ if (StopChecking) return;
+ StopChecking = TRUE;
+
/* Make sure interrupts are disabled */
if (__readeflags() & EFLAGS_INTERRUPT_MASK)
{
DbgPrint("Exiting with interrupts enabled: %lx\n", __readeflags());
__debugbreak();
}
-
+
/* Make sure this is a real trap frame */
if (TrapFrame->DbgArgMark != 0xBADB0D00)
{
@@ -114,34 +133,61 @@
KiDumpTrapFrame(TrapFrame);
__debugbreak();
}
-
+
/* Make sure we're not in user-mode or something */
if (Ke386GetFs() != KGDT_R0_PCR)
{
DbgPrint("Exiting with an invalid FS: %lx\n", Ke386GetFs());
__debugbreak();
}
-
+
/* Make sure we have a valid SEH chain */
if (KeGetPcr()->NtTib.ExceptionList == 0)
{
DbgPrint("Exiting with NULL exception chain: %p\n",
KeGetPcr()->NtTib.ExceptionList);
__debugbreak();
}
-
+
/* Make sure we're restoring a valid SEH chain */
if (TrapFrame->ExceptionList == 0)
{
DbgPrint("Entered a trap with a NULL exception chain: %p\n",
TrapFrame->ExceptionList);
__debugbreak();
}
-
+
/* If we're ignoring previous mode, make sure caller doesn't actually want it
*/
if (SkipPreviousMode && (TrapFrame->PreviousPreviousMode != -1))
{
DbgPrint("Exiting a trap witout restoring previous mode, yet previous mode
seems valid: %lx\n", TrapFrame->PreviousPreviousMode);
__debugbreak();
}
+
+ /* Check DR values */
+ if (TrapFrame->SegCs & MODE_MASK)
+ {
+ /* Check for active debugging */
+ if (KeGetCurrentThread()->Header.DebugActive)
+ {
+ if ((TrapFrame->Dr7 & ~DR7_RESERVED_MASK) == 0) __debugbreak();
+
+ CheckDr(0, TrapFrame->Dr0);
+ CheckDr(1, TrapFrame->Dr1);
+ CheckDr(2, TrapFrame->Dr2);
+ CheckDr(3, TrapFrame->Dr3);
+ CheckDr(7, TrapFrame->Dr7 | DR7_RESERVED_READ_AS_1);
+ }
+ }
+ else
+ {
+ PKPRCB Prcb = KeGetCurrentPrcb();
+ CheckDr(0, Prcb->ProcessorState.SpecialRegisters.KernelDr0);
+ CheckDr(1, Prcb->ProcessorState.SpecialRegisters.KernelDr1);
+ CheckDr(2, Prcb->ProcessorState.SpecialRegisters.KernelDr2);
+ CheckDr(3, Prcb->ProcessorState.SpecialRegisters.KernelDr3);
+ //CheckDr(7, Prcb->ProcessorState.SpecialRegisters.KernelDr7);
+ }
+
+ StopChecking = FALSE;
}
VOID
@@ -150,7 +196,7 @@
IN PKTRAP_FRAME TrapFrame)
{
KIRQL OldIrql;
-
+
/* Check if this was a user call */
if (KiUserTrap(TrapFrame))
{
@@ -161,7 +207,7 @@
/* Forcibly put us in a sane state */
KeGetPcr()->Irql = PASSIVE_LEVEL;
_disable();
-
+
/* Fail */
KeBugCheckEx(IRQL_GT_ZERO_AT_SYSTEM_SERVICE,
SystemCall,
@@ -209,6 +255,53 @@
extern PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler;
//
+// Save user mode debug registers and restore kernel values
+//
+VOID
+FORCEINLINE
+KiHandleDebugRegistersOnTrapEntry(
+ IN PKTRAP_FRAME TrapFrame)
+{
+ PKPRCB Prcb = KeGetCurrentPrcb();
+
+ /* Save all debug registers in the trap frame */
+ TrapFrame->Dr0 = __readdr(0);
+ TrapFrame->Dr1 = __readdr(1);
+ TrapFrame->Dr2 = __readdr(2);
+ TrapFrame->Dr3 = __readdr(3);
+ TrapFrame->Dr6 = __readdr(6);
+ TrapFrame->Dr7 = __readdr(7);
+
+ /* Disable all active debugging */
+ __writedr(7, 0);
+
+ /* Restore kernel values */
+ __writedr(0, Prcb->ProcessorState.SpecialRegisters.KernelDr0);
+ __writedr(1, Prcb->ProcessorState.SpecialRegisters.KernelDr1);
+ __writedr(2, Prcb->ProcessorState.SpecialRegisters.KernelDr2);
+ __writedr(3, Prcb->ProcessorState.SpecialRegisters.KernelDr3);
+ __writedr(6, Prcb->ProcessorState.SpecialRegisters.KernelDr6);
+ __writedr(7, Prcb->ProcessorState.SpecialRegisters.KernelDr7);
+}
+
+VOID
+FORCEINLINE
+KiHandleDebugRegistersOnTrapExit(
+ PKTRAP_FRAME TrapFrame)
+{
+ /* Disable all active debugging */
+ __writedr(7, 0);
+
+ /* Load all debug registers from the trap frame */
+ __writedr(0, TrapFrame->Dr0);
+ __writedr(1, TrapFrame->Dr1);
+ __writedr(2, TrapFrame->Dr2);
+ __writedr(3, TrapFrame->Dr3);
+ __writedr(6, TrapFrame->Dr6);
+ __writedr(7, TrapFrame->Dr7);
+}
+
+//
// Virtual 8086 Mode Optimized Trap Exit
//
VOID
@@ -218,7 +311,7 @@
{
PKTHREAD Thread;
KIRQL OldIrql;
-
+
/* Get the thread */
Thread = KeGetCurrentThread();
while (TRUE)
@@ -243,15 +336,14 @@
KfLowerIrql(OldIrql);
_disable();
}
-
+
/* If we got here, we're still in a valid V8086 context, so quit it */
if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
{
- /* Not handled yet */
- DbgPrint("Need Hardware Breakpoint Support!\n");
- while (TRUE);
- }
-
+ /* Restore debug registers from the trap frame */
+ KiHandleDebugRegistersOnTrapExit(TrapFrame);
+ }
+
/* Return from interrupt */
KiTrapReturnNoSegments(TrapFrame);
}
@@ -270,8 +362,8 @@
TrapFrame->Dr7 = __readdr(7);
if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
{
- DbgPrint("Need Hardware Breakpoint Support!\n");
- while (TRUE);
+ /* Handle debug registers */
+ KiHandleDebugRegistersOnTrapEntry(TrapFrame);
}
}
@@ -286,14 +378,21 @@
TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
- /* Flush DR7 and check for debugging */
+ /* Default to debugging disabled */
TrapFrame->Dr7 = 0;
- if (__builtin_expect(KeGetCurrentThread()->Header.DebugActive & 0xFF, 0))
- {
- DbgPrint("Need Hardware Breakpoint Support!\n");
- while (TRUE);
- }
-
+
+ /* Check if the frame was from user mode or v86 mode */
+ if ((TrapFrame->SegCs & MODE_MASK) ||
+ (TrapFrame->EFlags & EFLAGS_V86_MASK))
+ {
+ /* Check for active debugging */
+ if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
+ {
+ /* Handle debug registers */
+ KiHandleDebugRegistersOnTrapEntry(TrapFrame);
+ }
+ }
+
/* Set debug header */
KiFillTrapFrameDebug(TrapFrame);
}
@@ -307,15 +406,22 @@
{
/* Save exception list */
TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
-
- /* Flush DR7 and check for debugging */
+
+ /* Default to debugging disabled */
TrapFrame->Dr7 = 0;
- if (__builtin_expect(KeGetCurrentThread()->Header.DebugActive & 0xFF, 0))
- {
- DbgPrint("Need Hardware Breakpoint Support!\n");
- while (TRUE);
- }
-
+
+ /* Check if the frame was from user mode or v86 mode */
+ if ((TrapFrame->SegCs & MODE_MASK) ||
+ (TrapFrame->EFlags & EFLAGS_V86_MASK))
+ {
+ /* Check for active debugging */
+ if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
+ {
+ /* Handle debug registers */
+ KiHandleDebugRegistersOnTrapEntry(TrapFrame);
+ }
+ }
+
/* Set debug header */
KiFillTrapFrameDebug(TrapFrame);
}
Modified: trunk/reactos/ntoskrnl/ke/i386/exp.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/exp.c?rev…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/exp.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/i386/exp.c [iso-8859-1] Wed Apr 18 13:39:19 2012
@@ -14,35 +14,6 @@
#define NDEBUG
#include <debug.h>
-/* GLOBALS *******************************************************************/
-
-/* DR Registers in the CONTEXT structure */
-UCHAR KiDebugRegisterContextOffsets[9] =
-{
- FIELD_OFFSET(CONTEXT, Dr0),
- FIELD_OFFSET(CONTEXT, Dr1),
- FIELD_OFFSET(CONTEXT, Dr2),
- FIELD_OFFSET(CONTEXT, Dr3),
- 0,
- 0,
- FIELD_OFFSET(CONTEXT, Dr6),
- FIELD_OFFSET(CONTEXT, Dr7),
- 0,
-};
-
-/* DR Registers in the KTRAP_FRAME structure */
-UCHAR KiDebugRegisterTrapOffsets[9] =
-{
- FIELD_OFFSET(KTRAP_FRAME, Dr0),
- FIELD_OFFSET(KTRAP_FRAME, Dr1),
- FIELD_OFFSET(KTRAP_FRAME, Dr2),
- FIELD_OFFSET(KTRAP_FRAME, Dr3),
- 0,
- 0,
- FIELD_OFFSET(KTRAP_FRAME, Dr6),
- FIELD_OFFSET(KTRAP_FRAME, Dr7),
- 0,
-};
/* FUNCTIONS *****************************************************************/
@@ -153,8 +124,7 @@
if (Mask != NewMask)
{
/* Update it */
- KeGetCurrentThread()->Header.DebugActive =
- (BOOLEAN)NewMask;
+ KeGetCurrentThread()->Header.DebugActive = (UCHAR)NewMask;
}
}
@@ -312,11 +282,11 @@
PKTHREAD Thread;
ULONG_PTR Stack;
ULONG EFlags;
-
+
/* Get the current thread's stack */
Thread = KeGetCurrentThread();
Stack = (ULONG_PTR)Thread->InitialStack;
-
+
/* Check if we are in V8086 mode */
if (!(TrapFrame->EFlags & EFLAGS_V86_MASK))
{
@@ -324,17 +294,17 @@
Stack -= (FIELD_OFFSET(KTRAP_FRAME, V86Gs) -
FIELD_OFFSET(KTRAP_FRAME, HardwareSegSs));
}
-
+
/* Bias the stack for the FPU area */
Stack -= sizeof(FX_SAVE_AREA);
-
+
/* Disable interrupts */
EFlags = __readeflags();
_disable();
-
+
/* Set new ESP0 value in the TSS */
KeGetPcr()->TSS->Esp0 = Stack;
-
+
/* Restore old interrupt state */
__writeeflags(EFlags);
}
@@ -352,7 +322,6 @@
BOOLEAN V86Switch = FALSE;
KIRQL OldIrql;
ULONG DrMask = 0;
- PVOID SafeDr;
/* Do this at APC_LEVEL */
OldIrql = KeGetCurrentIrql();
@@ -584,26 +553,35 @@
}
/* Handle the Debug Registers */
- if (0 && (ContextFlags & CONTEXT_DEBUG_REGISTERS) ==
CONTEXT_DEBUG_REGISTERS)
- {
- /* Loop DR registers */
- for (i = 0; i < 4; i++)
- {
- /* Sanitize the context DR Address */
- SafeDr = Ke386SanitizeDr(KiDrFromContext(i, Context), PreviousMode);
-
- /* Save it in the trap frame */
- *KiDrFromTrapFrame(i, TrapFrame) = SafeDr;
-
- /* Check if this DR address is active and add it in the DR mask */
- if (SafeDr) DrMask |= DR_MASK(i);
- }
-
- /* Now save and sanitize DR6 */
+ if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
+ {
+ /* Copy Dr0 - Dr4 */
+ TrapFrame->Dr0 = Context->Dr0;
+ TrapFrame->Dr1 = Context->Dr1;
+ TrapFrame->Dr2 = Context->Dr2;
+ TrapFrame->Dr3 = Context->Dr3;
+
+ /* If we're in user-mode */
+ if (PreviousMode != KernelMode)
+ {
+ /* Make sure, no Dr address is above user space */
+ if (Context->Dr0 > (ULONG)MmHighestUserAddress) TrapFrame->Dr0 = 0;
+ if (Context->Dr1 > (ULONG)MmHighestUserAddress) TrapFrame->Dr1 = 0;
+ if (Context->Dr2 > (ULONG)MmHighestUserAddress) TrapFrame->Dr2 = 0;
+ if (Context->Dr3 > (ULONG)MmHighestUserAddress) TrapFrame->Dr3 = 0;
+ }
+
+ /* Now sanitize and save DR6 */
TrapFrame->Dr6 = Context->Dr6 & DR6_LEGAL;
+
+ /* Update the Dr active mask */
+ if (TrapFrame->Dr0) DrMask |= DR_MASK(0);
+ if (TrapFrame->Dr1) DrMask |= DR_MASK(1);
+ if (TrapFrame->Dr2) DrMask |= DR_MASK(2);
+ if (TrapFrame->Dr3) DrMask |= DR_MASK(3);
if (TrapFrame->Dr6) DrMask |= DR_MASK(6);
- /* Save and sanitize DR7 */
+ /* Sanitize and save DR7 */
TrapFrame->Dr7 = Context->Dr7 & DR7_LEGAL;
KiRecordDr7(&TrapFrame->Dr7, &DrMask);
@@ -611,7 +589,7 @@
if (PreviousMode != KernelMode)
{
/* Save the mask */
- KeGetCurrentThread()->Header.DebugActive = (DrMask != 0);
+ KeGetCurrentThread()->Header.DebugActive = (UCHAR)DrMask;
}
}
@@ -962,7 +940,7 @@
/* User mode exception, was it first-chance? */
if (FirstChance)
{
- /*
+ /*
* Break into the kernel debugger unless a user mode debugger
* is present or user mode exceptions are ignored, except if this
* is a debug service which we must always pass to KD
@@ -1132,7 +1110,7 @@
ExceptionRecord.ExceptionInformation[1] = Parameter2;
ExceptionRecord.ExceptionInformation[2] = Parameter3;
}
-
+
/* Now go dispatch the exception */
KiDispatchException(&ExceptionRecord,
NULL,
Modified: trunk/reactos/ntoskrnl/ke/i386/traphdlr.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/traphdlr.…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/traphdlr.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/i386/traphdlr.c [iso-8859-1] Wed Apr 18 13:39:19 2012
@@ -50,6 +50,9 @@
PKDBG_PRESERVICEHOOK KeWin32PreServiceHook = NULL;
PKDBG_POSTSERVICEHOOK KeWin32PostServiceHook = NULL;
#endif
+#if TRAP_DEBUG
+BOOLEAN StopChecking = FALSE;
+#endif
/* TRAP EXIT CODE *************************************************************/
@@ -86,24 +89,27 @@
{
/* Disable interrupts until we return */
_disable();
-
+
/* Check for APC delivery */
KiCheckForApcDelivery(TrapFrame);
-
+
+ /* Restore the SEH handler chain */
+ KeGetPcr()->NtTib.ExceptionList = TrapFrame->ExceptionList;
+
+ /* Check if there are active debug registers */
+ if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
+ {
+ /* Check if the frame was from user mode or v86 mode */
+ if ((TrapFrame->SegCs & MODE_MASK) ||
+ (TrapFrame->EFlags & EFLAGS_V86_MASK))
+ {
+ /* Handle debug registers */
+ KiHandleDebugRegistersOnTrapExit(TrapFrame);
+ }
+ }
+
/* Debugging checks */
KiExitTrapDebugChecks(TrapFrame, SkipPreviousMode);
-
- /* Restore the SEH handler chain */
- KeGetPcr()->NtTib.ExceptionList = TrapFrame->ExceptionList;
-
- /* Check if there are active debug registers */
- if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
- {
- /* Not handled yet */
- DbgPrint("Need Hardware Breakpoint Support!\n");
- DbgBreakPoint();
- while (TRUE);
- }
}
DECLSPEC_NORETURN
@@ -841,7 +847,7 @@
/* Check for VDM trap */
ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
-
+
/* Kill the system */
KiSystemFatalException(EXCEPTION_INVALID_TSS, TrapFrame);
}
@@ -1068,7 +1074,7 @@
UNIMPLEMENTED;
while (TRUE);
}
-
+
/*
* NOTE: The ASM trap exit code would restore segment registers by doing
* a POP <SEG>, which could cause an invalid segment if someone had messed
@@ -1524,12 +1530,18 @@
TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
- /* Clear DR7 and check for debugging */
+ /* Default to debugging disabled */
TrapFrame->Dr7 = 0;
- if (__builtin_expect(Thread->Header.DebugActive & 0xFF, 0))
- {
- UNIMPLEMENTED;
- while (TRUE);
+
+ /* Check if the frame was from user mode */
+ if (TrapFrame->SegCs & MODE_MASK)
+ {
+ /* Check for active debugging */
+ if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
+ {
+ /* Handle debug registers */
+ KiHandleDebugRegistersOnTrapEntry(TrapFrame);
+ }
}
/* Set thread fields */
Modified: trunk/reactos/ntoskrnl/ke/i386/v86vdm.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/v86vdm.c?…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/v86vdm.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/i386/v86vdm.c [iso-8859-1] Wed Apr 18 13:39:19 2012
@@ -528,10 +528,7 @@
TrapFrame->Dr7 = 0;
/* Set some debug fields if trap debugging is enabled */
-#if TRAP_DEBUG
- TrapFrame->DbgArgMark = 0xBADB0D00;
- TrapFrame->PreviousPreviousMode = -1;
-#endif
+ KiFillTrapFrameDebug(TrapFrame);
/* Disable interrupts */
_disable();