C/C++: The GDB Debugger
GDB is the Gnu DeBugger, a tool that lets you control the execution of your C/C++ program and inspect what it is doing at runtime. On top of that, it also allows you to inspect your program after it has had a catastrophic error such as a segmentation fault. Debuggers are extremely important tools when it comes to building, testing, and debugging large C/C++ programs. All development environments on all platforms have some form of a debugger. Learn to use it!
Step One: compile your program with debugging information
All compilers have some sort of option to include debugging information into the resulting object code and executable program. In the Gnu tools gcc/g++ this is the “-g” flag. Include this flag when you compile and link your program – the easiest way is to add it to your CFLAGS variable in your Makefile, assuming that you have these (if you don’t, create them!).
Step Two: run your program under the debugger
Once you have a program that includes debugging information, you have to run the debugger “gdb” so that you can then run your program under the debugger’s control. The easiest way to do this is to do the command “gdb ./program” – where “program” is your executable program’s name. Do not include your program’s command line arguments on this line – you are running “gdb” at this point, not your program.
Step Three: start your program within the debugger
Once gdb starts up, it will read in your executable program, but it does not yet run it. Gdb gives you a command prompt that lets you interact with it. This prompt is “(gdb)”.
There are lots of things you can do at this point – like setting up breakpoints and watchpoints to stop your program at – but this introduction will not cover all this. You can go read lots of other tutorials. If your program already has a catastrophic failure in it, like a segmentation fault or bus error, then you can just run your program under gdb, by using the command “run any-command-line-arguments”, where the command line arguments you give are the ones for your program (including file redirection if you want.
Step Four: inspect your program after it failed
Assuming you are trying to debug a program that has a serious failure, then after that failure happens, gdb stops your program and gives you back a (gdb) command prompt. You can now inspect the current state of your program (just after the failure). The best command to start with is “backtrace” (or “bt” for short). Backtrace shows you the current call stack – the stack of functions that have been called, starting with main() on the bottom. The top function on the stack is the one that is currently executing, and each function in the call stack has the line number in the source code where it is currently stopped at (because it called the function one level up on the call stack).
Often, the top of the stack will be one or more (sometimes several!) C library calls. For example, a bad string pointer might cause a segmentation fault inside of the printf() function – but what you really want to know is where in your own program’s code is the last line that was executed. So you have to scroll down through the backtrace until you get to the top function that is in your own source code.
This is now where you start. Go look at your code at this point, and figure out what went wrong!
But you can still do more in gdb. Once you find this top call stack function in your code, in gdb you can use the command “frame #” where # is the number associated with this function in the output from the “backtrace” command. This tells gdb you want to inspect information in this function call. Then you can use the “print” command and print any variable name that is in this function’s scope, including global, local, and parameter variables. So you can look at variables and see what they contain, and figure out which one’s are bad. So saying, e.g., the command “print myString” will, if that variable is a char pointer, print the pointer value. If you then say “print *myString”, gdb will print the string that is pointed to by the variable. Yes, gdb’s print command understands the * operator! Cool! It understands array indexing, and other variable access operators, too.