Jeffrey D. Oldham
2000 Mar 22
A debugger is a tool permitting your program to run in ``slow motion'' so you can examine how your program runs or why it crashes. With a debugger, one can
Since the Gnu debugger gdb works nicely with emacs and Xemacs so we will be describing it. We assume you are running either of these editors.
gdb has many more features than can be described here. Other sources of information include
The debugger needs more information than the compiler usually places in the executable so compile your program using the -g compiler flag. For example,
To run a program named factorial using gdb inside emacs, type M-x gdb. (The M-x is Meta-x, probably Alt-x or ESC-x on your keyboard.) Enter factorial when queried for the executable's name. A gdb buffer will appear.
To starting running factorial, type
To stop execution when the program enters the main function, type
To execute the next line, type the
To specify command-line arguments, type them after run. For example,
Starting each function call adds a frame to the stack while finishing a function call removes a frame from the stack. To inspect the stack, i.e., to see a listing of all the frames, try
Another way to inspect calls to factorial, is to set a breakpoint at its beginning. One could type break factorial, but instead move the cursor the function's first line and type C-x space. gdb will indicate a breakpoint has been set. Then, start running the program again. To continue execution until reaching the next breakpoint, type
When dealing with pointers and dynamic memory, segmentation faults are frequent occurrences. gdb will automatically stop execution when one occurs. Try running this program. To determine its state when it halts, use the backtrace command. To move up and down in the stack, use the up and down commands. Some stack frames are for functions automatically called by the compiler or by other functions.
In this particular case, we learn the segmentation fault occurs in the destructor, but it is hard to tell why. Solving this problem requires thought beyond what the debugger can reveal, but we can watch obj1's and obj2's values change as the program executes. To print the values of *(obj1.b) or *(obj2.b), use