Proper debugging tools are invaluable for developing working software. Both valgrind and gdb are excellent bug hunting utilities. Up until now I had not thought that these utilities could be combined together, but valgrind does indeed communicate with gdb.

If you have done C or C++ programming on a Unix system you are likely familiar with both of these tools. Through gdb you can step through a program and inspect the state of the program as execution progresses. Valgrind on the other end is usually useful for non-interactive inspection of memory errors at runtime. For both tools, this only scratches the surface of their capabilities, but it defines their overall domain. <!-- :truncate: -→

For a good example, here is a short program that contains an uninitialized variable bug.

#include <stdio.h>

int main()
{
int dat[100];

//initialize all elements but one
for(int i=0; i<100; ++i)
if(i!=10)
dat[i] = i%2;

for(int i=0; i<100; ++i)
if(dat[i])
printf("%d is even\n", i);

return 0;
}

Now for the setup to show the bug.

First the program needs to be compiled with debugging symbols.

g++ -g buggy.cpp

Then valgrind needs to be started in its gdb server mode.

valgrind --vgdb=yes --vgdb-error=0 a.out

Lastly, in another terminal gdb needs to get connected to valgrind.

gdb a.out
(gdb) target remote | vgdb

At this point gdb is in control of stepping through the program and valgrind will interrupt execution whenever an error is detected. To demonstrate this, the program was executed until the bug at line 13, where the index i shows that valgrind has signalled gdb at the correct iteration of the loop:

(gdb) continue
Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap.
0x00000000004005a4 in main () at tmp.cpp:13
13              if(dat[i])
(gdb) list
8           for(int i=0; i<100; ++i)
9               if(i!=10)
10                  dat[i] = i%2;
11
12          for(int i=0; i<100; ++i)
13              if(dat[i])
14                  printf("%d is even\n", i);
15
16          return 0;
17      }
(gdb) p i
\$1 = 10
(gdb) continue
Continuing.
Remote connection closed

So why am I excited about this combination of tools? For more complicated examples the line information provided by valgrind is usually not sufficient to immediately see where the error is. When gdb is added to the mix it allows one to see the entire state of the program when the bug is encountered. This significantly reduces the time it takes to localize a bug, thus making debugging a bit less frustrating.