Author: hbelusca Date: Fri Aug 28 03:03:26 2015 New Revision: 68841
URL: http://svn.reactos.org/svn/reactos?rev=68841&view=rev Log: [NTOS:KD] - Fix the condition check when setting twice (or more) the same breakpoint. - Implement support for deferred breakpoints. For more information, see: http://www.osronline.com/article.cfm?article=541 (which also exposes an interesting problem about them).
Modified: trunk/reactos/ntoskrnl/include/internal/kd.h trunk/reactos/ntoskrnl/include/internal/kd64.h trunk/reactos/ntoskrnl/kd64/kdbreak.c trunk/reactos/ntoskrnl/kd64/kdinit.c trunk/reactos/ntoskrnl/ke/amd64/cpu.c trunk/reactos/ntoskrnl/ke/amd64/trap.S trunk/reactos/ntoskrnl/ke/i386/traphdlr.c
Modified: trunk/reactos/ntoskrnl/include/internal/kd.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/k... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/kd.h [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/include/internal/kd.h [iso-8859-1] Fri Aug 28 03:03:26 2015 @@ -67,7 +67,7 @@ IN PROSSYM_INFO RosSymInfo, IN ULONG_PTR RelativeAddress, #ifdef __ROS_DWARF__ - IN PROSSYM_LINEINFO RosSymLineInfo + IN PROSSYM_LINEINFO RosSymLineInfo #else OUT PULONG LineNumber OPTIONAL, OUT PCH FileName OPTIONAL,
Modified: trunk/reactos/ntoskrnl/include/internal/kd64.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/k... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/kd64.h [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/include/internal/kd64.h [iso-8859-1] Fri Aug 28 03:03:26 2015 @@ -7,11 +7,6 @@ */
// -// Maximum supported number of breakpoints -// -#define KD_BREAKPOINT_MAX 32 - -// // Default size of the DbgPrint log buffer // #if DBG @@ -21,15 +16,29 @@ #endif
// +// Maximum supported number of breakpoints +// +#define KD_BREAKPOINT_MAX 32 + +// +// Highest limit starting which we consider that breakpoint addresses +// are either in system space, or in user space but inside shared DLLs. +// +// I'm wondering whether this can be computed using MmHighestUserAddress +// or whether there is already some #define somewhere else... +// See http://www.drdobbs.com/windows/faster-dll-load-load/184416918 +// and http://www.drdobbs.com/rebasing-win32-dlls/184416272 +// for a tentative explanation. +// +#define KD_HIGHEST_USER_BREAKPOINT_ADDRESS (PVOID)0x60000000 // MmHighestUserAddress + +// // Breakpoint Status Flags // -typedef enum _KDP_BREAKPOINT_FLAGS -{ - KdpBreakpointActive = 1, - KdpBreakpointPending = 2, - KdpBreakpointSuspended = 4, - KdpBreakpointExpired = 8 -} KDP_BREAKPOINT_FLAGS; +#define KD_BREAKPOINT_ACTIVE 0x01 +#define KD_BREAKPOINT_PENDING 0x02 +#define KD_BREAKPOINT_SUSPENDED 0x04 +#define KD_BREAKPOINT_EXPIRED 0x08
// // Structure for Breakpoints @@ -37,7 +46,7 @@ typedef struct _BREAKPOINT_ENTRY { ULONG Flags; - PKPROCESS Process; + ULONG_PTR DirectoryTableBase; PVOID Address; KD_BREAKPOINT_TYPE Content; } BREAKPOINT_ENTRY, *PBREAKPOINT_ENTRY; @@ -280,6 +289,12 @@ NTAPI KdpAddBreakpoint( IN PVOID Address +); + +VOID +NTAPI +KdSetOwedBreakpoints( + VOID );
BOOLEAN
Modified: trunk/reactos/ntoskrnl/kd64/kdbreak.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/kd64/kdbreak.c?rev... ============================================================================== --- trunk/reactos/ntoskrnl/kd64/kdbreak.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/kd64/kdbreak.c [iso-8859-1] Fri Aug 28 03:03:26 2015 @@ -23,18 +23,18 @@ ULONG i; NTSTATUS Status;
- /* Loop current breakpoints */ + /* Check whether we are not setting a breakpoint twice */ for (i = 0; i < KD_BREAKPOINT_MAX; i++) { /* Check if the breakpoint is valid */ - if ((KdpBreakpointTable[i].Flags & KdpBreakpointActive) && + if ((KdpBreakpointTable[i].Flags & KD_BREAKPOINT_ACTIVE) && (KdpBreakpointTable[i].Address == Address)) { - /* Check if it's pending */ - if ((KdpBreakpointTable[i].Flags & KdpBreakpointPending)) - { - /* It's not pending anymore now */ - KdpBreakpointTable[i].Flags &= ~KdpBreakpointPending; + /* Were we not able to remove it earlier? */ + if (KdpBreakpointTable[i].Flags & KD_BREAKPOINT_EXPIRED) + { + /* Just re-use it! */ + KdpBreakpointTable[i].Flags &= ~KD_BREAKPOINT_EXPIRED; return i + 1; } else @@ -46,33 +46,246 @@ }
/* Find a free entry */ - for (i = 0; i < KD_BREAKPOINT_MAX; i++) if (!(KdpBreakpointTable[i].Flags)) break; + for (i = 0; i < KD_BREAKPOINT_MAX; i++) + { + if (KdpBreakpointTable[i].Flags == 0) + break; + }
/* Fail if no free entry was found */ if (i == KD_BREAKPOINT_MAX) return 0;
- /* Save the old instruction */ + /* Save the breakpoint */ + KdpBreakpointTable[i].Address = Address; + + /* If we are setting the breakpoint in user space, save the active process context */ + if (Address < KD_HIGHEST_USER_BREAKPOINT_ADDRESS) + KdpBreakpointTable[i].DirectoryTableBase = KeGetCurrentThread()->ApcState.Process->DirectoryTableBase[0]; + + /* Try to save the old instruction */ Status = KdpCopyMemoryChunks((ULONG_PTR)Address, &Content, KD_BREAKPOINT_SIZE, 0, MMDBG_COPY_UNSAFE, NULL); - + if (NT_SUCCESS(Status)) + { + /* Memory accessible, set the breakpoint */ + KdpBreakpointTable[i].Content = Content; + KdpBreakpointTable[i].Flags = KD_BREAKPOINT_ACTIVE; + + /* Write the breakpoint */ + Status = KdpCopyMemoryChunks((ULONG_PTR)Address, + &KdpBreakpointInstruction, + KD_BREAKPOINT_SIZE, + 0, + MMDBG_COPY_UNSAFE | MMDBG_COPY_WRITE, + NULL); + if (!NT_SUCCESS(Status)) + { + /* This should never happen */ + KdpDprintf("Unable to write breakpoint to address 0x%p\n", Address); + } + } + else + { + /* Memory is inaccessible now, setting breakpoint is deferred */ + KdpDprintf("Failed to set breakpoint at address 0x%p, adding deferred breakpoint.\n", Address); + KdpBreakpointTable[i].Flags = KD_BREAKPOINT_ACTIVE | KD_BREAKPOINT_PENDING; + KdpOweBreakpoint = TRUE; + } + + /* Return the breakpoint handle */ + return i + 1; +} + +VOID +NTAPI +KdSetOwedBreakpoints(VOID) +{ + BOOLEAN Enable; + KD_BREAKPOINT_TYPE Content; + ULONG i; + NTSTATUS Status; + + /* If we don't owe any breakpoints, just return */ + if (!KdpOweBreakpoint) return; + + /* Enter the debugger */ + Enable = KdEnterDebugger(NULL, NULL); + + /* + * Suppose we succeed in setting all the breakpoints. + * If we fail to do so, the flag will be set again. + */ + KdpOweBreakpoint = FALSE; + + /* Loop through current breakpoints and try to set or delete the pending ones */ + for (i = 0; i < KD_BREAKPOINT_MAX; i++) + { + if (KdpBreakpointTable[i].Flags & (KD_BREAKPOINT_PENDING | KD_BREAKPOINT_EXPIRED)) + { + /* + * Set the breakpoint only if it is in kernel space, or if it is + * in user space and the active process context matches. + */ + if (KdpBreakpointTable[i].Address < KD_HIGHEST_USER_BREAKPOINT_ADDRESS && + KdpBreakpointTable[i].DirectoryTableBase != KeGetCurrentThread()->ApcState.Process->DirectoryTableBase[0]) + { + KdpOweBreakpoint = TRUE; + continue; + } + + /* Try to save the old instruction */ + Status = KdpCopyMemoryChunks((ULONG_PTR)KdpBreakpointTable[i].Address, + &Content, + KD_BREAKPOINT_SIZE, + 0, + MMDBG_COPY_UNSAFE, + NULL); + if (!NT_SUCCESS(Status)) + { + /* Memory is still inaccessible, breakpoint setting will be deferred again */ + // KdpDprintf("Failed to set deferred breakpoint at address 0x%p\n", + // KdpBreakpointTable[i].Address); + KdpOweBreakpoint = TRUE; + continue; + } + + /* Check if we need to write the breakpoint */ + if (KdpBreakpointTable[i].Flags & KD_BREAKPOINT_PENDING) + { + /* Memory accessible, set the breakpoint */ + KdpBreakpointTable[i].Content = Content; + + /* Write the breakpoint */ + Status = KdpCopyMemoryChunks((ULONG_PTR)KdpBreakpointTable[i].Address, + &KdpBreakpointInstruction, + KD_BREAKPOINT_SIZE, + 0, + MMDBG_COPY_UNSAFE | MMDBG_COPY_WRITE, + NULL); + if (!NT_SUCCESS(Status)) + { + /* This should never happen */ + KdpDprintf("Unable to write deferred breakpoint to address 0x%p\n", + KdpBreakpointTable[i].Address); + KdpOweBreakpoint = TRUE; + } + else + { + KdpBreakpointTable[i].Flags = KD_BREAKPOINT_ACTIVE; + } + + continue; + } + + /* Check if we need to restore the original instruction */ + if (KdpBreakpointTable[i].Flags & KD_BREAKPOINT_EXPIRED) + { + /* Write it back */ + Status = KdpCopyMemoryChunks((ULONG_PTR)KdpBreakpointTable[i].Address, + &KdpBreakpointTable[i].Content, + KD_BREAKPOINT_SIZE, + 0, + MMDBG_COPY_UNSAFE | MMDBG_COPY_WRITE, + NULL); + if (!NT_SUCCESS(Status)) + { + /* This should never happen */ + KdpDprintf("Failed to delete deferred breakpoint at address 0x%p\n", + KdpBreakpointTable[i].Address); + KdpOweBreakpoint = TRUE; + } + else + { + /* Check if the breakpoint is suspended */ + if (KdpBreakpointTable[i].Flags & KD_BREAKPOINT_SUSPENDED) + { + KdpBreakpointTable[i].Flags = KD_BREAKPOINT_SUSPENDED | KD_BREAKPOINT_ACTIVE; + } + else + { + /* Invalidate it */ + KdpBreakpointTable[i].Flags = 0; + } + } + + continue; + } + } + } + + /* Exit the debugger */ + KdExitDebugger(Enable); +} + +BOOLEAN +NTAPI +KdpLowWriteContent(IN ULONG BpIndex) +{ + NTSTATUS Status; + + /* Make sure that the breakpoint is actually active */ + if (KdpBreakpointTable[BpIndex].Flags & KD_BREAKPOINT_PENDING) + { + /* So we have a valid breakpoint, but it hasn't been used yet... */ + KdpBreakpointTable[BpIndex].Flags &= ~KD_BREAKPOINT_PENDING; + return TRUE; + } + + /* Is the original instruction a breakpoint anyway? */ + if (KdpBreakpointTable[BpIndex].Content == KdpBreakpointInstruction) + { + /* Then leave it that way... */ + return TRUE; + } + + /* We have an active breakpoint with an instruction to bring back. Do it. */ + Status = KdpCopyMemoryChunks((ULONG_PTR)KdpBreakpointTable[BpIndex].Address, + &KdpBreakpointTable[BpIndex].Content, + KD_BREAKPOINT_SIZE, + 0, + MMDBG_COPY_UNSAFE | MMDBG_COPY_WRITE, + NULL); if (!NT_SUCCESS(Status)) { - /* TODO: Set it as a owed breakpoint */ - KdpDprintf("Failed to set breakpoint at address 0x%p\n", Address); - return 0; - } - - /* Write the entry */ - KdpBreakpointTable[i].Address = Address; - KdpBreakpointTable[i].Content = Content; - KdpBreakpointTable[i].Flags = KdpBreakpointActive; - - /* Write the breakpoint */ - Status = KdpCopyMemoryChunks((ULONG_PTR)Address, + /* Memory is inaccessible now, restoring original instruction is deferred */ + KdpDprintf("Failed to delete breakpoint at address 0x%p\n", + KdpBreakpointTable[BpIndex].Address); + KdpBreakpointTable[BpIndex].Flags |= KD_BREAKPOINT_EXPIRED; + KdpOweBreakpoint = TRUE; + return FALSE; + } + + /* Everything went fine, return */ + return TRUE; +} + +BOOLEAN +NTAPI +KdpLowRestoreBreakpoint(IN ULONG BpIndex) +{ + NTSTATUS Status; + + /* Were we not able to remove it earlier? */ + if (KdpBreakpointTable[BpIndex].Flags & KD_BREAKPOINT_EXPIRED) + { + /* Just re-use it! */ + KdpBreakpointTable[BpIndex].Flags &= ~KD_BREAKPOINT_EXPIRED; + return TRUE; + } + + /* Are we merely writing a breakpoint on top of another breakpoint? */ + if (KdpBreakpointTable[BpIndex].Content == KdpBreakpointInstruction) + { + /* Nothing to do */ + return TRUE; + } + + /* Ok, we actually have to overwrite the instruction now */ + Status = KdpCopyMemoryChunks((ULONG_PTR)KdpBreakpointTable[BpIndex].Address, &KdpBreakpointInstruction, KD_BREAKPOINT_SIZE, 0, @@ -80,94 +293,15 @@ NULL); if (!NT_SUCCESS(Status)) { - /* This should never happen */ - KdpDprintf("Unable to write breakpoint to address 0x%p\n", Address); - } - - /* Return the breakpoint handle */ - return i + 1; -} - -BOOLEAN -NTAPI -KdpLowWriteContent(IN ULONG BpIndex) -{ - NTSTATUS Status; - - /* Make sure that the breakpoint is actually active */ - if (KdpBreakpointTable[BpIndex].Flags & KdpBreakpointPending) - { - /* So we have a valid breakpoint, but it hasn't been used yet... */ - KdpBreakpointTable[BpIndex].Flags &= ~KdpBreakpointPending; - return TRUE; - } - - /* Is the original instruction a breakpoint anyway? */ - if (KdpBreakpointTable[BpIndex].Content == KdpBreakpointInstruction) - { - /* Then leave it that way... */ - return TRUE; - } - - /* We have an active breakpoint with an instruction to bring back. Do it. */ - Status = KdpCopyMemoryChunks((ULONG_PTR)KdpBreakpointTable[BpIndex]. - Address, - &KdpBreakpointTable[BpIndex].Content, - KD_BREAKPOINT_SIZE, - 0, - MMDBG_COPY_UNSAFE | MMDBG_COPY_WRITE, - NULL); - if (!NT_SUCCESS(Status)) - { - /* TODO: Set it as a owed breakpoint */ - KdpDprintf("Failed to delete breakpoint at address 0x%p\n", - KdpBreakpointTable[BpIndex].Address); - return FALSE; - } - - /* Everything went fine, return */ - return TRUE; -} - -BOOLEAN -NTAPI -KdpLowRestoreBreakpoint(IN ULONG BpIndex) -{ - NTSTATUS Status; - - /* Were we not able to remove it earlier? */ - if (KdpBreakpointTable[BpIndex].Flags & KdpBreakpointExpired) - { - /* Well then, we'll just re-use it and return success! */ - KdpBreakpointTable[BpIndex].Flags &= ~KdpBreakpointExpired; - return TRUE; - } - - /* Are we merely writing a breakpoint on top of another breakpoint? */ - if (KdpBreakpointTable[BpIndex].Content == KdpBreakpointInstruction) - { - /* Nothing to do then... */ - return TRUE; - } - - /* Ok, we actually have to overwrite the instruction now */ - Status = KdpCopyMemoryChunks((ULONG_PTR)KdpBreakpointTable[BpIndex]. - Address, - &KdpBreakpointInstruction, - KD_BREAKPOINT_SIZE, - 0, - MMDBG_COPY_UNSAFE | MMDBG_COPY_WRITE, - NULL); - if (!NT_SUCCESS(Status)) - { - /* FIXME: Set it as a owed breakpoint */ KdpDprintf("Failed to restore breakpoint at address 0x%p\n", KdpBreakpointTable[BpIndex].Address); + KdpBreakpointTable[BpIndex].Flags |= KD_BREAKPOINT_PENDING; + KdpOweBreakpoint = TRUE; return FALSE; }
/* Clear any possible previous pending flag and return success */ - KdpBreakpointTable[BpIndex].Flags &= ~KdpBreakpointPending; + KdpBreakpointTable[BpIndex].Flags &= ~KD_BREAKPOINT_PENDING; return TRUE; }
@@ -178,16 +312,16 @@ ULONG BpIndex = BpEntry - 1;
/* Check for invalid breakpoint entry */ - if (!(BpEntry) || (BpEntry > KD_BREAKPOINT_MAX)) return FALSE; + if (!BpEntry || (BpEntry > KD_BREAKPOINT_MAX)) return FALSE;
/* If the specified breakpoint table entry is not valid, then return FALSE. */ if (!KdpBreakpointTable[BpIndex].Flags) return FALSE;
/* Check if the breakpoint is suspended */ - if (KdpBreakpointTable[BpIndex].Flags & KdpBreakpointSuspended) - { - /* Check if breakpoint is not ...? */ - if (!(KdpBreakpointTable[BpIndex].Flags & KdpBreakpointExpired)) + if (KdpBreakpointTable[BpIndex].Flags & KD_BREAKPOINT_SUSPENDED) + { + /* Check if breakpoint is not being deleted */ + if (!(KdpBreakpointTable[BpIndex].Flags & KD_BREAKPOINT_EXPIRED)) { /* Invalidate it and return success */ KdpBreakpointTable[BpIndex].Flags = 0; @@ -215,7 +349,7 @@ for (BpIndex = 0; BpIndex < KD_BREAKPOINT_MAX; BpIndex++) { /* Make sure that the breakpoint is active and matches the range. */ - if ((KdpBreakpointTable[BpIndex].Flags & KdpBreakpointActive) && + if ((KdpBreakpointTable[BpIndex].Flags & KD_BREAKPOINT_ACTIVE) && ((KdpBreakpointTable[BpIndex].Address >= Base) && (KdpBreakpointTable[BpIndex].Address <= Limit))) { @@ -241,11 +375,11 @@ for (BpIndex = 0; BpIndex < KD_BREAKPOINT_MAX; BpIndex++) { /* Check if they are valid, suspended breakpoints */ - if ((KdpBreakpointTable[BpIndex].Flags & KdpBreakpointActive) && - (KdpBreakpointTable[BpIndex].Flags & KdpBreakpointSuspended)) + if ((KdpBreakpointTable[BpIndex].Flags & KD_BREAKPOINT_ACTIVE) && + (KdpBreakpointTable[BpIndex].Flags & KD_BREAKPOINT_SUSPENDED)) { /* Unsuspend them */ - KdpBreakpointTable[BpIndex].Flags &= ~KdpBreakpointSuspended; + KdpBreakpointTable[BpIndex].Flags &= ~KD_BREAKPOINT_SUSPENDED; KdpLowRestoreBreakpoint(BpIndex); } } @@ -258,11 +392,11 @@ ULONG BpIndex = BpEntry - 1;
/* Check if this is a valid, unsuspended breakpoint */ - if ((KdpBreakpointTable[BpIndex].Flags & KdpBreakpointActive) && - !(KdpBreakpointTable[BpIndex].Flags & KdpBreakpointSuspended)) + if ((KdpBreakpointTable[BpIndex].Flags & KD_BREAKPOINT_ACTIVE) && + !(KdpBreakpointTable[BpIndex].Flags & KD_BREAKPOINT_SUSPENDED)) { /* Suspend it */ - KdpBreakpointTable[BpIndex].Flags |= KdpBreakpointSuspended; + KdpBreakpointTable[BpIndex].Flags |= KD_BREAKPOINT_SUSPENDED; KdpLowWriteContent(BpIndex); } }
Modified: trunk/reactos/ntoskrnl/kd64/kdinit.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/kd64/kdinit.c?rev=... ============================================================================== --- trunk/reactos/ntoskrnl/kd64/kdinit.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/kd64/kdinit.c [iso-8859-1] Fri Aug 28 03:03:26 2015 @@ -281,7 +281,7 @@ KdDebuggerDataBlock.KernBase = (ULONG_PTR)KdVersionBlock.KernBase;
/* Initialize the debugger if requested */ - if ((EnableKd) && (NT_SUCCESS(KdDebuggerInitialize0(LoaderBlock)))) + if (EnableKd && (NT_SUCCESS(KdDebuggerInitialize0(LoaderBlock)))) { /* Now set our real KD routine */ KiDebugRoutine = KdpTrap; @@ -289,9 +289,18 @@ /* Check if we've already initialized our structures */ if (!KdpDebuggerStructuresInitialized) { - /* Set the Debug Switch Routine and Retries*/ + /* Set the Debug Switch Routine and Retries */ KdpContext.KdpDefaultRetries = 20; KiDebugSwitchRoutine = KdpSwitchProcessor; + + /* Initialize breakpoints owed flag and table */ + KdpOweBreakpoint = FALSE; + for (i = 0; i < KD_BREAKPOINT_MAX; i++) + { + KdpBreakpointTable[i].Flags = 0; + KdpBreakpointTable[i].DirectoryTableBase = 0; + KdpBreakpointTable[i].Address = NULL; + }
/* Initialize the Time Slip DPC */ KeInitializeDpc(&KdpTimeSlipDpc, KdpTimeSlipDpcRoutine, NULL);
Modified: trunk/reactos/ntoskrnl/ke/amd64/cpu.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/amd64/cpu.c?rev... ============================================================================== --- trunk/reactos/ntoskrnl/ke/amd64/cpu.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/amd64/cpu.c [iso-8859-1] Fri Aug 28 03:03:26 2015 @@ -136,7 +136,7 @@ { PKPRCB Prcb = KeGetCurrentPrcb(); ULONG Vendor; - ULONG FeatureBits = KF_WORKING_PTE;; + ULONG FeatureBits = KF_WORKING_PTE; CPU_INFO CpuInfo;
/* Get the Vendor ID */
Modified: trunk/reactos/ntoskrnl/ke/amd64/trap.S URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/amd64/trap.S?re... ============================================================================== --- trunk/reactos/ntoskrnl/ke/amd64/trap.S [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/amd64/trap.S [iso-8859-1] Fri Aug 28 03:03:26 2015 @@ -15,6 +15,7 @@ EXTERN FrLdrDbgPrint:DWORD EXTERN KeBugCheckWithTf:PROC EXTERN MmAccessFault:PROC +EXTERN KdSetOwedBreakpoints:PROC EXTERN KiSystemFatalException:PROC EXTERN KiNpxNotAvailableFaultHandler:PROC EXTERN KiGeneralProtectionFaultHandler:PROC @@ -508,8 +509,16 @@
/* Check for success */ test eax, eax - jge PageFaultReturn - + jl PageFaultError + + /* + * We succeeded. Check whether the kernel debugger has + * owed breakpoints to be inserted, then return. + */ + call KdSetOwedBreakpoints + jmp PageFaultReturn + +PageFaultError: /* Disable interrupts again for the debugger */ cli
@@ -527,7 +536,6 @@ je SpecialCode
InPageException: - /* Dispatch in-page exception */ mov r11d, eax // Param3 = Status mov eax, STATUS_IN_PAGE_ERROR // ExceptionCode
Modified: trunk/reactos/ntoskrnl/ke/i386/traphdlr.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/traphdlr.c... ============================================================================== --- trunk/reactos/ntoskrnl/ke/i386/traphdlr.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/i386/traphdlr.c [iso-8859-1] Fri Aug 28 03:03:26 2015 @@ -1275,7 +1275,15 @@ (PVOID)Cr2, KiUserTrap(TrapFrame), TrapFrame); - if (NT_SUCCESS(Status)) KiEoiHelper(TrapFrame); + if (NT_SUCCESS(Status)) + { + /* + * We succeeded. Check whether the kernel debugger has + * owed breakpoints to be inserted, then return. + */ + KdSetOwedBreakpoints(); + KiEoiHelper(TrapFrame); + }
/* Check for syscall fault */ #if 0