Tip - Putting dynamic data breakpoints.
Details -We know that there are two kinds of breakpoints. First is the code break point. The second type of break point is the data break point that can be set on variables. We can set a data break point on any (global, member and local) variables so that when it is read/written, the execution will be suspended. Usually data breakpoints are useful in detecting application crashes. In that, the crash occurs at one point and it might be due to an invalid memory access done at a different point in code. In this case we can put a dynamic data break point on the suspected variables.
When we are working with big systems, with hundreds of DLLs, it might not be practicable to put breakpoint by first attaching the required process to a debugger, break at some point and then put the code or data breakpoint. Also, the data might be allocated dynamically from a thread that is created at runtime. So it calls for dynamic breakpoints.
Both the code and data breakpoints can be set dynamically, without the help of a debugger. During runtime, when any one of these breakpoints is encountered, Windows OS will generate an Unhandled Win32 Exception.
How To -Code breakpoints can be dynamically set using the DebugBreak() API. The compiler will generate an int 3; assembly instruction.
The data breakpoints are set by the means of the context information of a thread. Apart from other things, the context contains debug registers. The number of data break points that can be set to a thread is limited by the number of debug registers available. We can also specify on what kind of access (read/write) it should break.
In order to set a data breakpoint, following steps are done.
1. Get the current thread context.
2. Find the available register.
3. Set the following information to the thread context.
(ア) Starting memory address of the data.
(イ) Number of bytes to be monitored for access.
(ウ) Read/Write flag information. This is because we can tell whether to break on data read or data write. 1 for read and 3 for write.
(エ) Set the enable/disable. 1 for enable and 0 for disable.
4. Set the updated context.
The above steps will cause the breakpoint when the data is modified from a single thread.
What if the data is allocated from one thread and it is being accessed from different threads? In order to monitor a piece of data for read/write access from all the threads, we need to perform the above steps for each thread. One way to achieve this is to write a DLL and make use of the thread-attach notification.
Sample Implementation
The attached zip contains a DLL and a test application. The DLL exposes two APIs. One is to set the breakpoint and the other is to unset the breakpoint. During the set operation, it will update the current thread context and will keep the address, size etc inside a map. When the DLL receives a thread attaché notification, it will iterate the map and set the breakpoint for the new thread by updating its context information.Sample application Download
References: