Running a Program

Starting GDB

First, to start GDB, there are three basic options. Let’s say the program you are debugging is called foo:

  1. gdb foo

    This loads the program foo into the debugger, with it ready to run.

  2. gdb foo core

    This loads the program foo into the debugger, but gets the program’s state from a core file. This is a snapshot of memory generated when the program crashes, and allows you to recreate the point at which the crash occurred without having to re-run the program. The file is called core because early computers had a drum core that served as its RAM. It used to be common, at least on Posix (and earlier UNIX) systems, for the system to dump a core file every time the program crashed. Now, this is typically disabled, but you can enable it by running:

    ulimit -S -c unlimited

    The -S sets the soft limit (which does not restrict further increases) for the resource. The -c unlimited sets the core file size to unlimited, which means it can be as large as it needs to in order to contain the full program memory, subject to available disk space. To reset this to the default behavior, run:

    ulimit -S -c 0
  3. gdb -p 1234

    Instead of specifying the program to run, this attaches GDB to a running process with the process ID (PID) 1234. This can be useful if you have a program that is taking longer than you expect or is otherwise behaving oddly.

Running a Program in GDB

To start a program, the simplest command is

run

This begins the program with no command-line arguments. If you want to provide arguments (since you cannot do this directly through the gdb command), you can provide them as arguments to run. Say we’re running ulimit in GDB. We might start it with:

run -S -c unlimited

If you are trying to identify the cause of a segmentation fault (segfault, or SEGV), this might be the only thing you need to do from this chapter. Usually, you will want to do something from the following section before calling run.

Synonyms

Setting Breakpoints

Unless you are examining a core file or simply running until a segmentation fault occurs, you will likely want to set a breakpoint before you call run. This is the point at which execution should stop and return control to the user (you).

When you specify the breakpoint, you will usually use a linespec, which specifies the line on which to break. The simplest forms of this are

You can also specify the file in which to break, if you have a program with multiple files. For example:

Another option is to break at a specific address. If you want to break at the instruction beginning 23 bytes from the beginning of the fuction foo, for example, you could call:

There are many other options, including boolean conditionals, so that execution only breaks if a certain condition holds.

Synonyms

Controlling Execution

Once execution reaches a breakpoint, you will frequently want to continue executing instructions while examining the program’s status. When the source is available (that is, the code was compiled with debugging symbols and the source files can be found by GDB), you can execute line-by-line with either next or step. The difference is that step descends into functions, while next does not. As an example, consider the following code:

#include <stdio.h>

void g() {
   printf("in g()\n");
}

void f() {
   printf("in f()\n");
   g();
}

int main(int argc, char** argv) {
   printf("in main()\n");
   f();
   return 0;
}

Here is the behavior when we use next:

Breakpoint 1, f () at example.c:8
8      printf("in f()\n");
(gdb) next
in f()
9      g();
(gdb) next
in g()

Here is the behavior when we use step:

Breakpoint 1, f () at example.c:8
8      printf("in f()\n");
(gdb) step
0x00007f02e6687be8 in __GI__IO_puts (str=0x55787595c00b "in f()")
    at ./libio/ioputs.c:35
warning: 35 ./libio/ioputs.c: No such file or directory
(gdb) step
__strlen_evex () at ../sysdeps/x86_64/multiarch/strlen-evex-base.S:72
warning: 72 ../sysdeps/x86_64/multiarch/strlen-evex-base.S: No such file or directory

Both next and step take an optional argument N which steps N times instead of just once.

While next and step attempt to step by source code lines, we sometimes want to step by CPU instructions. For this, we can use stepi, which behaves like step, but by instructions, not source code lines.

If you want to resume execution until the program completes, produces an error, or reaches the next breakpoint, you can use the continue command.

Synonyms