As a developer, how do you use gdb to track down bugs within your code? What techniques tricks do you use to make your life easier?
In general you find something that isn't how it should be, and work backwards until you understand why.
The most obvious is the most useful: Setting a breakpoint on a function or line number and walking through the code line by line.
Another handy tip is to have show functions for all your structures/objects even if they are never used in your program, because you can run these functions from within gdb:
gdb> p show_my_struct(struct)
My custom display of Foo:
...
Watchpoints can be really handy too, but may slow down your program a lot. These break the flow when the value of a variable or address changes.:
gdb> watch foo
Watchpoint4: foo
gdb>
Some hints:
- use a graphical frontend (kdbg is quite good, ddd is at least better than command-line gdb, kdevelop has a nice gdb frontend but has some bgs, nemiver looks quite nice as well but is still in the works)
- make sure to have debug symbols and source code for all important parts (your own code and also some system libs)
- on RedHat, you can install the -debuginfo packages to make both symbols and source code magically appear in the debugger - really cool because you can looks into libc function calls etc.
- on Debian/Ubuntu, you can install the -dbg packages to get symbols; installing appropriate source files for system packages seems to be difficult, though
- I tend to add assert() and abort() calls in places that should not be reached, or in places that I want to study (some kind of heavy-weight breakpoint)
- ideally the assert() or abort() calls should be wrapped in some method or macro that only enables them in Debug releases, or even better that only enables them if a certain env var is set
- install a signal handler for SIGSEGV and SIGABRT; personally I check if a certain env var is set before installing the handlers; and in the handler I execute a hardcoded external command which usually lives somewhere in ~/.local/bin/; that command might then start kdbg and attach it to the crashing app. Voila, debugger pops up the moment your app does something bad.
- If you use unit tests, you could similarly attach a debugger whenever a test case fails, to inspect the app then.
Use ddd, a visual front-end for gdb. It lets you do things easily with a few mouse clicks and visualise how the code works, plus in the debugger console you have an intercative gdb.
One particularly useful feature of gdb is its ability to inspect the final state of a program that's crashed.
To inspect a crash dump (or core file, as it's more commonly called), start gdb as follows:
gdb <program-name> <core-file>
For example:
gdb a.out core
Upon running this command on a core file, gdb will tell you how the program terminated and display where in the program the error occurred:
Program terminated with signal 11, Segmentation fault.
#0 0x08048364 in foo () at foo.c:4
4 *x = 100;
In the example above, you can see that the program terminated with a segmentation fault while trying to assign a value to a pointer. By typing backtrace (or bt or where) at gdb's prompt, you can view the program's complete backtrace:
(gdb) backtrace
#0 0x08048364 in foo () at foo.c:4
#1 0x0804837f in main () at foo.c:9
At this point, you know that main()
called foo()
and foo()
crashed on line 4 while trying to assign a value to *x
. Many times, this provides enough information to allow you to fix the bug.
I do a lot of parallel-program dev, so I've found that using a simple wrapper in python/ruby that allows me to have gdb attached to all processes on all nodes and communicating back to me is extraordinarily helpful (I haven't found a better way if anyone knows of one, not to hijack the thread, though...)
I'm not sure how experienced the OP is, so:
The GDB docs are pretty nice and all encompassing. The first chapter is a good introduction to all the basics.
http://www.gnu.org/software/gdb/documentation/
Although not gdb, they are related: I've personally found that breaking complex lines down to aid in determining which statements are erroring helps.
Also, Valgrind (http://valgrind.org/) is really nice/usefull for tackling buffer-overflows and the like (I haven't had luck with gdb for doing this.