How to use the GDB debugger - basics

Most installations of the GNU c++ compiler (g++) also include the GNU debugger, GDB. This page is meant to be a guide to doing some basic debugging with GDB. Be aware that there are many other features available, this is just a basic introduction.

Why use a debugger?

Debuggers are useful for debugging runtime errors. Whenever a program crashes, it will print out the output up to that point and then give you an error message indicating what is wrong (e.g. "segmentation fault"). These messages are not always very helpful, as they tell you what went wrong, but not where. If your program has a lot of output, you can use that to narrow down where the error is occuring. However, that is not very useful for a program without much output.

One common strategy for debugging is to include some extra output statements throughout the code that will be removed before the final version of the code is complete. These may be simple labels (e.g. "About to enter for loop") or print out the values of variables. While this strategy often works well, especially if you have a reasonable idea of where in the code errors are likely to occur, sometimes it is not enough to quickly get to the heart of the problem. A debugger can both help speed up this process and give you a better idea of what is happening as your program is running.

Enabling Debugging Symbols

Normally when you compile using the g++ (or gcc) compiler, you would use a command similar to this:

	g++ -c main.cpp
or
	g++ -o main main.o
In order to use a debugger, however, you need to tell the compiler to include a debugging symbol table. A debugging symbol table is information included in the binary file that maps the compiled instructions to the corresponding line, function, and/or variable in the original source code. This is not something you would want to do with your final builds of any code, as it makes the final executable larger and slower. However, it is very useful when debugging.

To tell the compiler to include the symbol table, you use the -g flag when compiling. So, as an example:

	g++ -g -o main main.cpp

Using the command line debugger

Once you have compiled an executable file that includes a debugging symbol table, you debug it by opening it in gdb. This is done by running gdb using the following format:

	gdb program_name
So, for example, if you wanted to debug the program "main", you would run:
	gdb main
At this point, you will be at the gdb command prompt. You can do various things before running the program, but are not required to. The simplest step at this point is to just run the program using the command:
	run
which will run the program exactly as if you had run it from the command line. If the program encounters a runtime error then gdb will usually print a line number, then save the state of the program at the time of the error and allow you to interact with it to get more information at the gdb prompt.

Getting the program state

There are various commands for getting information about the current state of the program when at the gdb prompt (shortcuts will be in parentheses when appropriate):

Controlling the program flow

When you are debugging a program, it is often useful to get the program state before it actually comes to the error. For example, if have an error because you are dereferencing a null pointer, it may help you find where the pointer gets set to null. The most common way of doing this is to set a breakpoint. When a running program in GDB encounters a breakpoint, it will immediately stop and allow you to view the program state. You can also use GDB commands at this time to continue running the program, either one line at a time or until it hits the next breakpoint/runtime error. Some of the useful commands for controlling program flow are:

Additional Tips

When you have multiple source files and you need to refer to one in particular, you use filename: before the line number. For example, to set a breakpoint at line 120 in the file other.cpp, you would use:

	break other.cpp:120
Debugging in GDB can take a while to get used to. A good way to get comfortable is to first get used to using some of the most common. I would recommend starting with bt and print. Then look at break, next, and step. From there, you can add in more commands as you need them.

For more advanced topics, including the commands not listed here, there are other tutorials on the web and you can always use GDB's help command.

Also be aware that there are other ways to use GDB than just running your program directly (you can use a core dump, for example).

Examples

Each of these examples has at least one run-time error possible. Try using GDB to debug these errors and fix them. Make sure to use -g when compiling these!