How to debug a C/C++ program with GDB command-line debugger

What is the worst part of coding without a debugger? Compiling on your knees praying that nothing will crash? Running the executable with a blood offering? Or just having to write printf("test") at every line hoping to find where the problem is coming from? As you probably know, there are not many advantages to coding without a debugger. But the good side is that debugging on Linux is easy. While most people use the debugger included in their favorite IDE, Linux is famous for its powerful command line C/C++ debugger: GDB. However, like most command line utilities, GDB requires a bit of training to master fully. In this tutorial, I will give you a quick rundown of GDB debugger.

Installation of GDB

GDB is available in most distributions' repositories.

For Debian or Ubuntu:

$ sudo apt-get install gdb

For Arch Linux:

$ sudo pacman -S gdb

For Fedora, CentOS or RHEL:

$ sudo yum install gdb

If you cannot find it anywhere else, it is always possible to download it from the official page.

Code Sample

When you are learning GDB, it is always better to have a piece of code to try things. Here is a quick sample that I coded to show the best features of GDB. Feel free to copy paste it to try the examples. That's the best way to learn.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    int i;
    int a=0, b=0, c=0;
    double d;
    for (i=0; i<100; i++)
    {
        a++;
        if (i>97)
            d = i / 2.0;
        b++;
    }
    return 0;
}

Usage of GDB

First and foremost, you will need to compile your program with the flag "-g" (for debug) to run it via GDB. From there the syntax to start debugging is:

$ gdb -tui [executable's name]

The "-tui” option will show your code in a nice interactive terminal window (so-called "text user interface") that you can navigate in with the arrow keys, while typing in the GDB shell below.

We can now start playing around placing breakpoints anywhere in the source code with debugger. Here you have the options to set a breakpoint at a line number of the current source file:

break [line number]

or at a line number of a specific source file:

break [file name]:[line number]

or at a particular function:

break [function name]

And even better, you can set conditional breakpoints:

break [line number] if [condition]

For example, in our code sample, I can set:

break 11 if i > 97

which will have an effect of stopping me at "a++;" after 97 iterations of the for loop. As you have guessed, this is very handy when you do not want to step through the loop 97 times on your own.

Last but not least, you can place a "watchpoint" which will pause the program if a variable is modified:

watch [variable]

Here, I can set one like:

watch d

which will stop the program as soon as variable d is set to a new value (i.e. when i > 97 is true).

Once our breakpoints are set, we can run the program with the "run" command, or simply:

r [command line arguments if your program takes some]

as most words can be abbreviated in just a letter with gdb.

And without surprises, we are stopped at line 11. From there, we can do interesting things. The command:

bt

for backtrack will tell us how we got to that point.

info locals

will display all the local variables and their current values (as you can see I didn't set my d variable to anything so its value is currently garbage).

Of course:

p [variable]

will show the value of a particular variable. But even better:

ptype [variable]

shows the type of a local variable. So here we can confirm that d is double type.

And since we are playing with fire, might as well do it all the way:

set var [variable] = [new value]

will override the value of the variable. Be careful though as you can't create a new variable or change its type. But here we can do:

set var a = 0

And just like any good debugger, we can "step" with:

step

to run the next line and potentially step into a function. Or just:

next

to just go straight to the line below, ignoring any function call.

And to finish testing, you can delete a breakpoint with:

delete [line number]

Keep running the program from the current breakpoint with:

continue

and exit GDB with:

quit

To conclude, with GDB, no more praying to compile, no more blood offerings to run, no more printf("test"). Of course this post is not exhaustive and GDB's capabilities run beyond this, so I really encourage you to learn more about it on your own (or in a future post maybe?). What I am the most interested now is to integrate GDB nicely in Vim. In the meantime, here is a very big memo of all the GDB commands for future reference.

What do you think of GDB? Would you consider its advantages over a graphical debugger or an IDE's? And what about integrating into Vim? Let us know in the comments.

Subscribe to Xmodulo

Do you want to receive Linux FAQs, detailed tutorials and tips published at Xmodulo? Enter your email address below, and we will deliver our Linux posts straight to your email box, for free. Delivery powered by Google Feedburner.


Support Xmodulo

Did you find this tutorial helpful? Then please be generous and support Xmodulo!

The following two tabs change content below.

Adrien Brochard

I am a Linux aficionado from France. After trying multiple distributions, I finally settled for Archlinux. But I am always trying to improve my system by stacking up tips and tricks.

Latest posts by Adrien Brochard (see all)

9 thoughts on “How to debug a C/C++ program with GDB command-line debugger

  1. Err, without a doubt GDB is useful. That's why people use debuggers in the first place.

    But is there really nothing better than GDB after all these years? It looks woefully primitive compared to e.g. Borland or Microsoft IDE's.

    What about an IDE? What about mouse-over variable inspection? What about multiple code windows? What about inspection of structures and arrays? What about displaying structures referenced by a pointer?

    Don't get me wrong: GDB is better than nothing, but it doesn't look like anything to be particularly proud of. Or a tools you'd enjoy using.

  2. Regarding Golodh's comment:
    "What about inspection of structures and arrays? What about displaying structures referenced by a pointer?"

    I would REALLY like to know how to do this. I can obviously do this in Visual Studio, but in Linux, I have no clue where to begin. Any thoughts on how to do this or where I can find another tutorial like this?

  3. It is possible to define your own functions to print out values of
    anything you want. For example suppose you have a vector class named myvector,
    and v[i] is the i'th element. Define the mp function

    void mp(const myvector & v,int i)
    {
    cout << v[i] << endl;
    }

    and link the code in with your project. Then in a gdb session if you wanted to see the 5th
    element of a myvector object named w you would use the command

    call mp(w,5)

    As long as your vector object know its own size you could extend this so that

    call mp(w)

    would print out the entire vector.

  4. @Dave Fournier

    Clever trick, incorporating extra code to print structure values and executing that code during debugging. But I think you'll agree that it's kludgy compared to an IDE that does that kind of stuff for you.

    This way you'd probably have to debug using pencil and paper and write down the values of interest before executing a new piece of print-the-structure code. It can certainly work, but "nice tools" look different.

    • Actually the scheme I described is much more flexible than you assume. At the simplest level, one can also write the values into another file. With multiple desktops one can be examining that file with an editor at the same time. No need to write down values. I also have a scheme with named pipes
      so that values of vectors can automatically be plotted using R. For high dimensional containers one can use graophical software which presents various views of the data.

  5. Excellent article, thanks. I have only used gdb a few times, so this was a great overview of how to start using it more regularly.

Leave a comment

Your email address will not be published. Required fields are marked *