A watchpoint is a special kind of breakpoint which, like a normal breakpoint, is an instruction that tells GDB to pause execution of your program. The difference is that watchpoints don’t “live” at a line of source code. Instead, a watchpoint is an instruction that tells GDB to pause execution whenever an expression changes value.
That expression can be quite simple, like the name of a variable:
(gdb) watch i
which will make GDB pause whenever i changes value. The expression can also be quite complex:
(gdb) watch (i | j > 12) && i > 24 && strlen(name) > 6
You can think of a watchpoint as being “attached” to an expression; when the value of that expression changes, GDB will pause the program’s execution.
Although watchpoints and breakpoints are managed the same way, there is an important difference between them. A breakpoint is associated with a location within your source code.
Since your code doesn’t change, there is no risk of a line of code “going out of scope.” Because C has rigid scoping rules, you can only watch a variable that exists and is in scope.
Once the variable no longer exists in any frame of the call stack (when the function containing a local variable returns), GDB automatically deletes the watchpoint.
Having GDB break any time a variable changes can be something of a nuisance in tightly wrapped loops or repetitive code. Although watchpoints sound great, well-placed breakpoints may be far more useful. However, watchpoints are invaluable if one of your variables changes, especially a global variable, and you have no idea where or how it changed.
If you’re dealing with threaded code, watchpoints have limited usefulness; GDB is only capable of watching a variable within a single thread.
When the variable var exists and is within scope, you can set a watchpoint on it by using the command
watch var
which will cause GDB to break whenever the value for the variable “var” changes. This is how many people think of watchpoints, because it’s simple and convenient; however, there’s a bit more to the story. What GDB really does is break if the memory location for "var" changes value.
Normally, it doesn’t matter whether you think of a watchpoint as watching the variable or the address of the variable, but it may be important in special cases, like when dealing with pointers to pointers.
Let’s look at one example scenario in which watchpoints would be very useful. Suppose you have two int variables, x and y , and somewhere in the code you perform p = &y when you meant to do p = &x . This could result in y mysteriously changing value somewhere in the code. The actual location of the resulting bug may be well hidden, so a breakpoint may not be very useful. However, by setting a watchpoint, you could instantly know when and where y changes value.
There’s even more to the story. You aren’t limited to watching a variable. In fact, you can watch an expression involving variables. Whenever the expression changes value, GDB will break.
As an example, consider the following code:
#include <stdio.h>
int i = 0;
int main(void)
{
i = 3;
printf("i is %d.\n", i);
i = 5;
printf("i is %d.\n", i);
return 0;
}
We’d like to know whenever i becomes greater than 4. So let’s put a breakpoint at the entry of main() in order get i in scope, and set a watchpoint to tell you when i becomes larger than 4. You can’t set a watchpoint on i because, before the program runs, i doesn’t exist. So you have to set a breakpoint at main() first, and then set a watchpoint on i:
(gdb) break main
Breakpoint 1 at 0x80483b4: file test2.c, line 6.
(gdb) run
Starting program: test2
Breakpoint 1, main () at test2.c:6
Now that i is in scope, set the watchpoint and tell GDB to continue executing the program. We fully expect that i > 4 becomes true at line 9.
(gdb) watch i > 4
Hardware watchpoint 2: i > 4
(gdb) continue
Continuing.
Hardware watchpoint 2: i > 4
Old value = 0
New value = 1
main () at test2.c:10
Sure enough, GDB is paused between lines 9 and 10, where the expression i > 4 changed value from 0 (not true) to 1 (true).
watch
given by GDB(gdb) help watch
Set a watchpoint for an expression.
Usage: watch [-l|-location] EXPRESSION
A watchpoint stops execution of your program whenever the value of
an expression changes.
If -l or -location is given, this evaluates EXPRESSION and watches
the memory to which it refers.
(gdb)
You may see a message about a “hardware” watchpoint when you set a watchpoint:
(gdb) watch i
Hardware watchpoint 2: i
or list your breakpoints:
(gdb) info breakpoints
Num Type Disp Enb Address What
2 hw watchpoint keep y i
Clearly, 2 refers to the watchpoint identifier, and i is the variable being watched, but what is this “hardware” stuff about?
Many platforms have dedicated hardware that can be used to implement a watchpoint. GDB will try to use the hardware, if it’s available, because implementing anything with hardware is fast.
It’s possible that GDB cannot set hardware watchpoints (the platform may not have the necessary hardware, or the hardware may be busy with something else). If so, GDB will try to implement the watchpoint using VM techniques, which is also fast.
If neither technique is available, GDB will implement the watchpoint itself, via software, which can be very, very slow.
Your CPU can implement only a limited number of hardware-assisted breaks, which includes watchpoints and hardware-assisted breakpoints. This number is architecture dependent, but if you exceed this limit, GDB will print the message:
Stopped; cannot insert breakpoints.
You may have requested too many hardware breakpoints and watchpoints.
If you see this message, you should delete or disable some of your watchpoints or hardware-assisted breakpoints.