~5Y ago I blogged about data breakpoints . A hefty bit of the discussion was devoted to persistence of hardware breakpoints across a thread switch: all four implementations linked to assumed that hardware breakpoints persist across thread boundaries, and some rough testing showed that was indeed the case back then. Alas, somewhere between Windows 7 and Windows 10 – this assumption broke. The naïve implementation via SetThreadContext indeed sets the debug registers only in the context of a specific thread. I suspect a deep change in the OS scheduler broke it – possibly today hardware tasks are used where they previously weren’t, but I have no proof of that.
Failed Attempts at a Solution
I’m aware of a single attempt to address this shortcoming and implement a truly cross-thread data breakpoint: A year ago my friend Meir Meshi published code that not only enumerates all existing threads and sets debug registers in their context, but also hooks thread creation (actually RtlCreateThread) via a coded assembly trampoline to make sure any thread created after a breakpoint is set would trigger it when appropriate. The code seemed to work marvelously for a while, and broke again in Windows 10 – where MS understandably recognizes patching of thread creation as an exploit, and banned it.
I set out to find a working alternative to hooking thread creation. Two immediate directions popped to mind: DLL_THREAD_ATTACH and the lesser known TLS callbacks . These are two documented hooks available to user mode upon thread creation, and seemed like a natural place to access the list of set breakpoints and apply them to the context of the current threads. Both these attempts fell short again, however, since it seems these hooks are called before the target thread created (from the stack of a different process thread), and setting the debug registers in this context does not persist to the target thread.
Bottom line, it seems that as of 2016, you really have to be a debugger to manage hardware breakpoints. I was told by John Robbins in a recent convention that the VS team are aware of this need but it just isn’t currently a priority (this might change if this UserVoice suggestion gets a bit more votes, though). Luckily, VS isn’t the only debugger in the MS universe – and in fact it integrates with a much stronger one.
A Real Solution
WinDBG (and siblings) had ba – which implements hardware breakpoints perfectly – since forever. It is a less known fact that VS integrates rather nicely with WinDBG, and for completeness I’ll rehash here the integration steps taken from an older post .
(1) Install WDK , and check integration with VS.
(2) Run the debugee without a debugger (Ctrl+F5) and attach to it via the newly added ‘Windows User Mode Debugger’ transport:
The debugging engine is now that of WinDBG. The debugging experience is noticeably different: the expression evaluator is different (the view at the watch window and what it agrees to process is changed), Threads pane no longer has thread IDs (why??) etc. – but all in all the large majority of VS commands and keyboard shortcuts are nicely mapped to this new engine.
You should see a new ‘Debugger Immediate Window’ pane, that accepts command line inputs identical to that of WinDBG, and with a nice bonus of auto-completes and auto help:
While at a breakpoint, type at this window a ba command. For example, to break upon read (r) of any of the 4 bytes (r4) following the address 0x000000c1`3219f7f4 (the windbg engine likes a ` separator in the middle of x64 addresses), type:
ba r4 0x000000c1`3219f7f4
And enjoy your shiny new read breakpoints that works across existing threads and is inherited by newly created ones.