A Quick Tutorial on the gdb Debugger

EECS E6870: Speech Recognition

March 16, 2016

Table of Contents

1. Introduction

What is a debugger, and why use one? For those of you who are not robots or cyborgs, you will undoubtedly introduce bugs into your source code at some time or another. One simple way to debug stuff is to place print statements everywhere. However, it will make your life much easier in the long run if you learn how to use a debugger. A debugger lets you stop the execution of your program at any point and examine any values you wish, which makes this much more general and powerful than the print statement technique.

Which debugger are we going to use? The canonical C++ debugger on Linux systems is the GNU gdb debugger, a command-line debugger. While there exist GUI wrappers for gdb, we have no idea how to use them because we are old-school.

2. Launching a Program In The Debugger

First, compile the program with debugging information on This is the default in the Makefile's supplied by us. (When g++ is invoked, the -g flag should be present.) If you have compiled a program with optimization on (as is sometimes done in the later parts of labs), then you should run

make clean
and then recompile the program.

Use the -dbg flag with scripts, if available If a script runs only a single command, then the -dbg flag can be used with the script to launch that command in the debugger, e.g.,

lab3_p1a.sh -dbg

Otherwise, it's a little more complicated The -dbg flag is not available for scripts that run multiple commands. In this case, run the script with the prefix bash -x to see what commands are being run, e.g.,

bash -x lab3_p2a.sh
Then, select which command you want to debug, and run that command with the prefix dbg.sh. For example, to debug the last command run in the preceding script, you would run
dbg.sh lab3_lm --vocab lab3.syms --train minitrain.txt \
    --test test1.txt --delta 0.0001 --n 3 --word_probs p2a.3.probs
The -dbg flag described in the last section just calls dbg.sh.

What's going on underneath The normal way to invoke the debugger is as follows:

gdb my_prog
However, you cannot provide command-line arguments for my_prog when you do this; instead, they must be supplied as arguments to the run command described below. This is inconvenient, so we supply a wrapper script dbg.sh that lets you directly invoke the debugger with command-line arguments. It also sets a couple of useful breakpoints.

3. Debugging

3.1. Basics

3.2. Stopping Execution

A basic technique in debugging is to stop the execution of your program at strategic points and to examine the values of variables to make sure they are correct. In this section, we discuss different ways of stopping execution.

When an error occurs Your program will automatically stop when there is a segmentation fault, an assert failure, or an exception. (For the latter conditions, dbg.sh sets breakpoints for you.)

Setting breakpoints You can specify a particular line where a program should stop using the break or b command. For example,

b lang_model.C:92
will cause execution to stop whenever line 92 in the file lang_model.C is hit. Then, you can use the cont or c command to continue execution until a breakpoint is hit.

3.3. Advancing Execution in a Controlled Manner

3.4. Examining Variables

Selecting a stack frame When you examine a local variable, the debugger displays the local variables of the current function. Normally, the current function is set to what you want, but if execution is stopped due to an assert failure or exception, then the current function will be set to the corresponding C++ library function. In this case, what you want to do is set the current function to be the function that called the current function. This can be done with the following command:

up
This tells the debugger to pop up one function in the call stack. More generally, the command
where
can be used to print the whole call stack, and the commands up and down can be used to move up and down in the call stack.

Printing variables To print a variable, use the print or p command. Here are example print commands:

p wordCnt
p this->m_n
p m_n
p (*this)->m_n
p (*this)->m_n + 5
As you can see, gdb can evaluate complex C++ expressions. You can also examine vectors, e.g.,
p ngramBuf.size()
p ngramBuf[0]

For more information You can use the built-in command

help
or look at a gdb tutorial and there's always Google.

help. To start gdb, type gdb <program>. Within gdb, type run <arguments> to start the program. Commands that you should know about include breakpoint, print, cont, step, next, where, up, down, and finish. Don't forget to compile your program with the -g flag (see Section ??).