Ever had this happen to you? You set a seemingly normal breakpoint in your target machine from WinDBG and resume the system:
You then go back over to your target system and it is completely unresponsive. The mouse won’t move, keyboard doesn’t work, etc. So, you go back over to your debugger system, break into the target, clear the breakpoint, and all is fine again. Disassembling the routine just to make sure all is well doesn’t show anything of interest that might explain this:
So what’s up with that?
The problem is actually a variation of the issue that was described by Bryce Jonasson and Jen-Leng Chiu of the Debugging Tools for Windows team in a recent issue of The NT Insider, available here. The issue is that, even though the u command indicates otherwise, the offending code in question is actually paged out at the moment. Not entirely paged out to disk mind you, but currently in transition. We can see this by examining the state of the PTE with the !pte command:
If the page is not currently valid, then why are we seeing valid data contents when we unassemble the virtual address? The reason is that, by default, the debugger will automatically decode and display the contents of pages that are in transition. They are still in memory and the PTE contains the information necessary to find the actual memory, so why not show the data? This behavior can be changed with the nodecodeptes parameter to the .cache command:

If we now try to disassemble the address we’ll see that the virtual address is in fact current invalid:

We can restore the default behavior by specifying the decodeptes option:
But why does the system go into a tailspin when we set a breakpoint on this address? The reason is that the debugger cannot set a breakpoint on an invalid PTE. Thus, setting a breakpoint on this address sets what is called an, “owed” breakpoint. When we resume the target system, the target system will try like heck to set a breakpoint on this address every chance it gets, which might result in the system not doing much but trying to set this breakpoint.
The best workaround for this issue is to set a hardware access breakpoint on the address instead of a software breakpoint. This will utilize the support of the processor to break when someone finally executes this address instead of trying to set the breakpoint by replacing a byte of memory with an int 3 instruction:
An alternative would be to use the .pagein command to force the memory to be paged in on the target, though paging in kernel memory requires support from the operating system that is only in Windows Vista and later. There is also the .allow_bp_ba_convert command, which enabled an option that would have automatically converted our bp breakpoint into a ba breakpoint in this situation.




