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.
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.
Normally when you compile using the g++ (or gcc) compiler, you would use a command similar to this:
g++ -c main.cppor
g++ -o main main.oIn 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
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_nameSo, for example, if you wanted to debug the program "main", you would run:
gdb mainAt 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:
runwhich 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.
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):
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:
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:120Debugging 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.