Watchpoints

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.[11] 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.

For example, in Extended GDB Example, we looked at a program named swap. In this program, a local variable c was used for temporary storage. You would not be able to set a watch on c until GDB reached line 3 of swapper.c, where c is defined. Additionally, if you did set a watch on c, the watch would be automatically deleted once GDB returned from swapper() since c would no longer be in existence.

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. You can read more about this in Chapter 5.

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:

 1  #include <stdio.h>
 2  int i = 0;
 3
 4  int main(void)
 5  {
 6    i = 3;
 7    printf("i is %d.\n", i);
 8
 9    i = 5;
10   printf("i is %d.\n", i);
11
12   return 0;
13  }

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.

1  (gdb) watch i > 4
2  Hardware watchpoint 2: i > 4
3  (gdb) continue
4  Continuing.
5  Hardware watchpoint 2: i > 4
6
7  Old value = 0
8  New value = 1
9  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).

You can use this method to set watchpoints with DDD in the Console Window; however, you might find it more convenient to use the GUI interface. In the Source Window, locate the variable you want to set a watchpoint on. It doesn't need to be the first instance of the variable; you can use any mention of the variable within the source code. Left-click the variable to highlight it, then left-click the watchpoint symbol in the icon Menu Bar. There won't be an indication that a watchpoint is set like the red stop sign for breakpoints. To see which watchpoints you've set, you'll have to actually list all your breakpoints, which we covered in Breakpoint Lists in DDD.

In Eclipse, you can set a watchpoint by right-clicking in the source window, selecting Add a Watch Expression, and then filling in the desired expression in the dialog box.

We saw an example of using an expression with GDB's watch command. It turns out that there are quite a few GDB commands, like print, that also accept expression arguments. Therefore, we should probably mention a bit more about them.

An expression in GDB can contain many things:

So, if you were debugging a Fortran-77 program and wanted to know when the variable i became larger than 4, instead of using watch i > 4 as you did in the last section, you would use watch i .GT. 4.

You often see tutorials and documentation that use C syntax for GDB expressions, but that's due to the ubiquitous nature of C and C++; if you use a language other than C, GDB expressions are built from elements of that language.



[11] Expressions will be discussed more fully in Expressions.

[12] As of this writing, the official GNU GDB User's Manual states that pre-processor macros cannot be used in expressions; however, this is not true. If you compile the program with GCC's -g3 option, pre-processor macros can be used in expressions.