mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 05:42:59 +00:00
[NTOSKRNL]
- Implement saving / restoring debug registers on traps - Replace the loop in KeContextToTrapFrame with something less ridiculous - fixes a number of ntdd exception winetests svn path=/trunk/; revision=56357
This commit is contained in:
parent
ebccbcb163
commit
038a2fbb39
5 changed files with 191 additions and 120 deletions
|
@ -539,28 +539,6 @@ Ke386SanitizeFlags(IN ULONG Eflags,
|
|||
(EFLAGS_INTERRUPT_MASK | (Eflags & EFLAGS_USER_SANITIZE)));
|
||||
}
|
||||
|
||||
//
|
||||
// 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
|
||||
//
|
||||
|
|
|
@ -95,11 +95,30 @@ KiFillTrapFrameDebug(IN PKTRAP_FRAME TrapFrame)
|
|||
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)
|
||||
{
|
||||
|
@ -142,6 +161,33 @@ KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame,
|
|||
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
|
||||
|
@ -208,6 +254,53 @@ VOID
|
|||
|
||||
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
|
||||
//
|
||||
|
@ -247,9 +340,8 @@ KiExitV86Trap(IN PKTRAP_FRAME TrapFrame)
|
|||
/* 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 */
|
||||
|
@ -270,8 +362,8 @@ KiEnterV86Trap(IN PKTRAP_FRAME TrapFrame)
|
|||
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,12 +378,19 @@ KiEnterInterruptTrap(IN PKTRAP_FRAME TrapFrame)
|
|||
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))
|
||||
|
||||
/* Check if the frame was from user mode or v86 mode */
|
||||
if ((TrapFrame->SegCs & MODE_MASK) ||
|
||||
(TrapFrame->EFlags & EFLAGS_V86_MASK))
|
||||
{
|
||||
DbgPrint("Need Hardware Breakpoint Support!\n");
|
||||
while (TRUE);
|
||||
/* Check for active debugging */
|
||||
if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
|
||||
{
|
||||
/* Handle debug registers */
|
||||
KiHandleDebugRegistersOnTrapEntry(TrapFrame);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set debug header */
|
||||
|
@ -308,12 +407,19 @@ KiEnterTrap(IN PKTRAP_FRAME TrapFrame)
|
|||
/* 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))
|
||||
|
||||
/* Check if the frame was from user mode or v86 mode */
|
||||
if ((TrapFrame->SegCs & MODE_MASK) ||
|
||||
(TrapFrame->EFlags & EFLAGS_V86_MASK))
|
||||
{
|
||||
DbgPrint("Need Hardware Breakpoint Support!\n");
|
||||
while (TRUE);
|
||||
/* Check for active debugging */
|
||||
if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
|
||||
{
|
||||
/* Handle debug registers */
|
||||
KiHandleDebugRegistersOnTrapEntry(TrapFrame);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set debug header */
|
||||
|
|
|
@ -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 @@ KiRecordDr7(OUT PULONG Dr7Ptr,
|
|||
if (Mask != NewMask)
|
||||
{
|
||||
/* Update it */
|
||||
KeGetCurrentThread()->Header.DebugActive =
|
||||
(BOOLEAN)NewMask;
|
||||
KeGetCurrentThread()->Header.DebugActive = (UCHAR)NewMask;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,7 +322,6 @@ KeContextToTrapFrame(IN PCONTEXT Context,
|
|||
BOOLEAN V86Switch = FALSE;
|
||||
KIRQL OldIrql;
|
||||
ULONG DrMask = 0;
|
||||
PVOID SafeDr;
|
||||
|
||||
/* Do this at APC_LEVEL */
|
||||
OldIrql = KeGetCurrentIrql();
|
||||
|
@ -584,26 +553,35 @@ KeContextToTrapFrame(IN PCONTEXT Context,
|
|||
}
|
||||
|
||||
/* Handle the Debug Registers */
|
||||
if (0 && (ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
|
||||
if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
|
||||
{
|
||||
/* Loop DR registers */
|
||||
for (i = 0; i < 4; i++)
|
||||
/* 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)
|
||||
{
|
||||
/* 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);
|
||||
/* 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 save and sanitize DR6 */
|
||||
/* 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 @@ KeContextToTrapFrame(IN PCONTEXT Context,
|
|||
if (PreviousMode != KernelMode)
|
||||
{
|
||||
/* Save the mask */
|
||||
KeGetCurrentThread()->Header.DebugActive = (DrMask != 0);
|
||||
KeGetCurrentThread()->Header.DebugActive = (UCHAR)DrMask;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,9 @@ PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler;
|
|||
PKDBG_PRESERVICEHOOK KeWin32PreServiceHook = NULL;
|
||||
PKDBG_POSTSERVICEHOOK KeWin32PostServiceHook = NULL;
|
||||
#endif
|
||||
#if TRAP_DEBUG
|
||||
BOOLEAN StopChecking = FALSE;
|
||||
#endif
|
||||
|
||||
|
||||
/* TRAP EXIT CODE *************************************************************/
|
||||
|
@ -90,20 +93,23 @@ KiCommonExit(IN PKTRAP_FRAME TrapFrame, BOOLEAN SkipPreviousMode)
|
|||
/* Check for APC delivery */
|
||||
KiCheckForApcDelivery(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);
|
||||
/* 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);
|
||||
}
|
||||
|
||||
DECLSPEC_NORETURN
|
||||
|
@ -1524,12 +1530,18 @@ KiSystemCall(IN PKTRAP_FRAME TrapFrame,
|
|||
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))
|
||||
|
||||
/* Check if the frame was from user mode */
|
||||
if (TrapFrame->SegCs & MODE_MASK)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
while (TRUE);
|
||||
/* Check for active debugging */
|
||||
if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
|
||||
{
|
||||
/* Handle debug registers */
|
||||
KiHandleDebugRegistersOnTrapEntry(TrapFrame);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set thread fields */
|
||||
|
|
|
@ -528,10 +528,7 @@ KiEnterV86Mode(IN PKV8086_STACK_FRAME StackFrame)
|
|||
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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue