Usually, people put breakpoints on an instruction. These breakpoints are set by replacing the first byte of an instruction with the ‘int 3’ instruction (0xcc). When the processor executes the ‘int 3’ instruction, it causes the OS to generate STATUS_BREAKPOINT exception, and your program stops.
There is another type of breakpoint that the debugger can also set for you – a data breakpoint. Data breakpoints fire when data is changed. To set one, go to Debug->New Breakpoint, then switch to the ‘Data’ tab.
There are really two types of data breakpoints that the native debugger supports – hardware data breakpoints, and emulated data breakpoints. Hardware data breakpoints are the useful ones. They are implemented with the debug registers of the processor. Unlike emulated breakpoints, these are fast and reliable. On the downside, the processor doesn’t have many of them. Also, all data breakpoints (including hardware breakpoints) won’t fire when the memory is written from kernel mode. With emulated breakpoints, the debugger uses instruction breakpoints to try and break when a variable is changed. However, this is a very challenging operation, and doesn’t always work. This also slows down the execution of your program, sometimes dramatically. Because of the problems with emulated breakpoints, this feature is likely going to be removed in a future product. One thing we would like to do is expose all the breakpoint register features of the processor. This would let you set a breakpoint on data read, write and execute instead of just write.
Now that you know the difference between a hardware and emulated breakpoint, here is how you set a hardware breakpoint:
- Determine what address you want to watch
- Open the new breakpoint dialog, and switch to the data tab
- Enter the address that you want to watch in the variable column
- The context is ignored. You can clear this if you want.
- Set the item count. If you are using an address, this should be the number of bytes (example: 4 for a DWORD)
One downside to data breakpoints are that they are only supported for native debugging. Maybe sometime they will work for managed. In some ways, this is a much harder feature for managed because the GC moves objects around in memory. I think data breakpoints are probably far less important for managed code since there is no heap corruption, and properties allow setting a breakpoint on the set function instead.