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.