Debugging with GDB
Here's information on the gdb debugger. See "man gdb" for a complete
description of gdb's command. Other debuggers exist, including dbx,
but those won't be covered.
To compile your program for gdb, compile each source file prog.c as
gcc -g prog.c
The "-g" causes symbol table information and some other stuff to be
included in the executable file, in order to allow you to use symbol
names when debugging. If you're using a Makefile, just add the
following line at the top and replace every occurrence of `gcc' with
`$(CC)'.
CC = gcc -g
You can run your program from gdb, as follows:
% gdb a.out
(gdb) run
If you're familiar with Emacs, you can run gdb from within Emacs with
"M-x gdb" (type "C-h m" to see useful key bindings). This is much
better than running gdb from the Unix prompt, since Emacs shows you
where you are in the code.
Consider the program
bad-bst.c,
which implements a binary search tree of integers and accepts commands
from the input to insert, delete, seek, and print. I have introduced
a small bug into this program. Following is the debugging session
with some comments added.
You should copy bad-bst.c into your own account (click on the pointer
above) and do these same steps, first running gdb from the Unix
prompt. Only then should you run gdb from within Emacs; things will
be somewhat different than described below.
% gcc -g bad-bst.c /* Compile with debugging stuff */
% a.out /* Run a.out */
i 1 /* Try to insert a 1 into the BST */
Segmentation fault (core dumped)
% gdb a.out /* Run the debugger on your program */
... GDB introductory message ...
(gdb) run /* Run a.out again, from within gdb */
Starting program: a.out
i 1 /* Try to insert a 1 into the BST */
/* (YOU TYPE THIS "i 1") */
Program received signal SIGSEGV, Segmentation fault.
0x10e80 in BST_insert (k=1) at bad-bst.c:176
176 if (k < y->key)
(gdb) where /* Show a stack trace: we are now at */
/* BST_insert (called with k=1), on */
/* line 176 of bad-bst.c. This */
/* was called from line 78 in main(). */
#0 0x10e80 in BST_insert (k=1) at bad-bst.c:176
#1 0x10c0c in main (argc=1, argv=0xeffffa1c) at bad-bst.c:78
(gdb) list 170,180 /* List the source file */
170
171 /* point tree node to new node */
172
173 if (y = NULL)
174 root = new_node; /* tree was empty */
175 else
176 if (k < y->key)
177 y->left = new_node; /* new node is to left of y */
178 else
179 y->right = new_node; /* new node is to right of y */
180
/* Looking at line 176, you see two */
/* potential errors, in the values of */
/* "k" and "y->key". */
(gdb) print k /* Print the current value of k */
$1 = 1 /* k = 1 */
(gdb) print y->key /* Print the current value of y->key */
Cannot access memory at address 0x0. /* y->key is garbage, so look at y */
(gdb) print y /* Print the current value of y */
$2 = (NODE *) 0x0 /* y = NULL pointer */
(gdb) quit /* The bug is found: y is NULL, so */
/* y->key is an invalid expression. */
/* Looking at line 173, y is NULL */
/* because the test is (y = NULL) */
/* instead of (y == NULL). */
The program is running. Quit anyway (and kill it)? (y or n) y
%
Some useful gdb commands are listed below.
help - Generic help, by subject
help [command] - Show information about [command]
run - Run the program. Typing ^C will bring you back to gdb.
run < [file] - Run the program with [file] in place of the standard input.
where - Print the procedure call stack.
list [x],[y] - List the source file between lines [x] and [y].
print [expr] - Evaluate and print an expression [expr]. [expr] can be
very complicated, and can include things like function
calls, pointer dereferencing (* and ->), and structure
accessing (.).
set [var] = [expr] - Set the value of a variable.
whatis [ident] - Describe the type of an identifier.
break [line] - Stop execution when [line] is reached. There are other
versions of this command. Use "help breakpoints" to see
them. This particular command just sets a breakpoint.
cont - Continue execution from where it last stopped.
step - Execute the next line, then stop.