GDB Tutorial

Adapted from http://www.cs.princeton.edu/~benjasik/gdb/gdbtut.html

A debugger is a program that runs other programs, allowing the user to exercise control over these programs, and to examine variables when problems arise. The most popular debugger for UNIX systems is gdb, the GNU debugger. gdb has tons of features, however, you only need to use a few for it to be useful. There is complete documentation for gdb online, or you can read the man page (type "man gdb" at the unix command prompt), and the quick reference card is very handy.

Basic features of a debugger

When you are execute a program that does not behave as you like, you need some way to step through you logic other than just looking at your code. Some things you want to know are:

Starting gdb

You need to tell the compiler that you plan to debug your program. You use the -g flag to do this. If you are using C++ the command will be

g++ -g lexdriver.cpp
which will create the executable (a.out by default). If you are using the provided makefile, just change CFLAGS = -o to CFLAGS = -g -o . (Note that -g must precede the -o option, which specifies the name for the executable.)

Once your executable has been generated by the compiler, it is run under the control of gdb by typing

gdb a.out
or, if for example you have generated an executable with the name tokenize, say
gdb tokenize
This starts up the text interface to the debugger. It's much easier to use gdb under emacs, but we'll use this interface to describe the commands.

gdb commands

When gdb starts, your program is not actually running. It won't run until you tell gdb how to run it. Whenever the prompt appears, you have all the commands on the quick reference sheet available to you.

The goal of gdb is to give you enough info to pinpoint where your program crashes, and find the bad pointer that is the cause of the problem. Although the actual error probably occurred much earlier in the program, figuring out which variable is causing trouble is a big step in the right direction.

gdb under emacs

Emacs provides a much better interface to gdb that saves a lot of typing and confusion. The best way to use emacs with gdb is to compile the program with emacs and then invoke gdb.

To begin, invoke emacs and edit the source program you want to debug. The easiest way to do this is to go into the directory where the files comprising your program reside and invoke emacs with the file name of the main module--e.g., emacs lexdriver.cpp. If you are using the makefile, before doing anything else be sure you have edited the makefile to specify

CFLAGS = -g -o

(making sure the -g comes before the -o).

To compile the program, hit the f5 key, or enter M-x compile. You will get the prompt

Compile command: make -k

You can just hit return unless you want to specify your own compile command, in which case you can use the Delete key (or Backspace key, on some terminals) to erase the make -k and replace it with, for example, g++ -g -o tokenize lexdriver.cpp get_next_token.cpp char_stream.cpp error.cpp. You may get a prompt asking to save the file ; if you answer "y" emacs will save the file before compiling it.

When the program compiles, emacs creates a new buffer for the compile. Eventually, that new buffer will include a "Compilation finished" message, and will display any syntax errors that were found. If there are any such errors, you can keep typing

C-x `

(C-x and then a backward apostrophe), and emacs will automatically go to the buffer for the source file and position the cursor at the source of the error; this is a big convenience.

Now invoke gdb using the command M-x gdb. Or, to use the ddd graphical interface (recommended), type M-x gdb, then at the prompt change the command to ddd --gdb. If you use gdb without ddd, emacs will create a new buffer for gdb, and you are now ready to enter gdb commands. The first command to enter is

file tokenize

in order to provide gdb with the symbol table for the last compilation that produced the executable named tokenize. Now you can set one or more breakpoints, and then say

run lextest.dat

which runs the tokenize executable with the input file lextest.dat.

When gdb stops at a breakpoint, emacs will take the file and line number reported by gdb and display the file contents in a second buffer below the gdb buffer, with the point of the breakpoint marked with =>. As you step through a program, emacs will follow your progress in the source file. For example, if you give gdb an "n" (next) command , it will execute that statement and the "=>" marker will then advance to the next line in the source file. You can see the content of any variable at any time with the print command. The command C-x SPC will place a breakpoint at the current point of the file you are in.

Using ddd is much simpler. GNU has a good overview and summary.