WatchPoint
Watchpoints – more than watch and continue
Hello! Welcome to gdbWatchPoint where we’re looking at GDB tips and tricks to make your debugging life easier. This episode of gdbWatchPoint is, somewhat confusingly on watchpoints, which I’m sure most of you will have used, if perhaps in their simplest form. But there’s more to watchpoints than simply watch and continue. Let’s start at the begining to make sure everyone is up to speed. Here’s a very simple little program: This has a structure, a couple of instances of the structure and maintains a pointer to that structure. We can then compile in the normal way and load into GDB: In GDB, start debugging with: Now let’s watch the pointer, We’ll immediately continue and, because we’re watching for changes in …where we can see that it was set to 0 (zero) but it’s new a pointer to I’m now going to restart the program by running I want to watch not just If I then continue with Interestingly, the watchpoint won’t change when the memory is written, it will change when the memory is changed. You’ll have noticed the “Hardware watchpoint” in the output from GDB. Watchpoints preceed hardware support and GDB has a notion of software watchpoints as well. If we start the program again with … you can see that GDB watches that with a hardware watchpoint, but if this structure was a big array or it was misaligned then GDB would use a software watchpoint. An easy way to always get a software whatpoint is to watch a register because you can’t use hardware watchpoints with registers on x86. If you do this, you will notice the difference – this is “watchpoint” not “hardware watchpoint”: Watchpoint (that is, software watchpoint) is the default; but hardware watchpoint is almost always what you want. If I now continue the program, GDB is going to single step one instruction at a time, then GDB is going to observe this and ask “has the watch data changed?”. In some situations that might be what you want, but if you’re watching data and you go into this single step mode, it probably isn’t because it’s super slow – 10,000s times slower… Let’s look now at location based watchpoints. Often with C and C++ programs, I’m looking for memory corruption errors, so some kind of pointer error. What variables are in scope and what they’re set to at the time aren’t really what I care about. What I care about is a location in memory and who’s overwriting it. Again, let’s start gdb. You might also need to delete your watchpoints with Start, do If I then continue, the watchpoint isn’t hit because that doesn’t get changed. Let’s modify the program to show what happens if it does get changed. Update the code so that after the Recompile this, launch GDB again, and let’s debug again: When I continue (the last line), GDB stops on line 19: Event though To see how this works, you can look at the assembly using: The hardware will stop the program after the instruction that writes to the memory has completed. The highlighted line above is the write which increments Another feature of watchpoints is read watchpoints which are triggered when the location is read (rather than written). To set this for (Not all hardware supports this. x86 does.) That’s it for watchpoints. Hope you have good fun with them! GDB TrainingIntroduction
A simple program
include <stdio.h>
struct st
{
int a;
int b;
};
struct st foo = {1,2};
struct st bar = {3,4};
int
main(void)
{
struct st *p= &foo;
printf("p->a is %d\n", p->a);
p = &bar;
printf("p->b is %d\n", p->a);
return 0;
}
gcc -g watch.c
gdb a.out
Debugging in GDB
(gdb) start
p
:(gdb) watch p
Hardware watchpoint 2: p
p
we hit the first line which modifes p:(gdb) c
foo
. If you continue again, we’re stopped when p changes (because we’re watching it) and p
is now a pointer to bar
.Watching pointers
start
in gdb, and then list all watchpoints by running info break
. (Do this for yourself of follow along in the video.)p
but also p->a
. I can’t do this when I’ve initially started the program in GDB because p
is null, which GDB can’t reference. But if I do n
(for next) then I can watch p->a
:c
then the watchpoint does trigger because even though a within foo hasn’t changed, p
is now pointing to bar
and so p->a
has changed from 1 to 3:Software watchpoints
start
. If I then do:(gdb) watch foo
Hardware watchpoint 6: foo
watch $sp
Location based watchpoints
delete
.next
and watch
:(gdb) start
(gdb) n
(gdb) watch -l p->a
p = &bar;
line your code reads as follows:p = &bar;
for.a++;
(gdb) start
(gdb) n
(gdb) watch -l foo->a
(gdb) c
p->a
has not been aftected by that line, we were watching the location and so GDB did stop. (In the video I show how you can do this with older versions of GDB which don’t support this way of doing location based watchpoints.)How all this works
(gdb) disas
foo.a
and the line after is where we stop.Read watchpoints
p
I would do:(gdb) rwatch p
Master GDB and save time debugging
Learn more »
Want debugging tips directly in your inbox?
Share this tutorial