Data breakpoints are now becoming a part of common breakpoint vocabulary. They help in detecting heap corruption, inadvertent data overwrites and writing past buffer boundaries.
Most programmer’s restrict the definition of data breakpoints to breakpoints that help halting the execution of code in the debugger when memory is written to. This is the kind of breakpoint that helps in catching most of the corruption bugs.
GDB provides data breakpoints (at least on Intel platforms) that do slightly more than that. As data breakpoints are implemented through hardware assistance, it is the hardware platform that provides the different kinds of data breakpoints and the debuggers provide the required interface.
watch
watch is gdb’s way of setting data breakpoints which will halt the execution of a program if memory changes at the specified location.
watch breakpoints can either be set on the variable name or any address location.
watch my_variable
watch *0x12345678
where 0x12345678 is a valid address.
Usually a crash because of heap corruption or invalid outcome due to buffer overruns shows up in the debugger when it is too late to figure out what went wrong. The watch or write data breakpoints can be used to find when a memory location has changed. The debugger at that very instant shows the reason for the inadvertent change.
The cause usually is double deletion of memory, writing to deleted memory, writing past the buffer boundary, etc. In order to fix such issues, it is more important to know when the corruption happens than to know what happens when the corruption has taken place.
Another interesting use of write data breakpoints is to find out the cause of memory leaks in reference counted objects by monitoring the increase and decrease in the reference count of the objects.
rwatch
rwatch (read-watch) breakpoints break the execution of code when the program tries to read from a variable or memory location.
rwatch iWasAccessed
rwatch *0x12345678
where 0x12345678 is a valid address.
For example, say you are new to your project and would like to figure out where exactly are your encryption routines in code. As a start, you can first search your codebase but you may hit a few false positives. If you know the memory location of your password and you set your rwatch breakpoints correctly, it would not be long before the debugger breaks execution right in your encryption algorithms which have to read the password in order to perform their function. Getting evil ideas already?
Another use of read data breakpoints is finding out the code that is reading from memory that has already been deleted and is using this corrupt information later.
awatch
awatch or access watches break execution of the program if a variable or memory location is written to or read from. In summary, awatches are watches and rwatches all in one. It is a handy way of creating one breakpoint than two separate ones.
awatch *0x12345678
where 0x12345678 is a valid address.
The problem with data breakpoints like any other breakpoint is that they can be triggered far too many times and the programmer may lose track of the problem being debugged. To ensure the breakpoints are hit the least number of times, the data being worked upon should be minimal and the breakpoint should be set as late as possible.