First, to start GDB, there are three basic options. Let’s say the
program you are debugging is called foo:
gdb foo
This loads the program foo into the debugger, with it
ready to run.
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 0gdb -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.
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.
run, rUnless 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
break foo: set a breakpoint at the first instruction of
function foobreak 123: set a breakpoint at line 123 of the current
fileYou can also specify the file in which to break, if you have a program with multiple files. For example:
break foo.c:123: set a breakpoint at line 123 of the
file foo.cAnother 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:
break *foo + 23There are many other options, including boolean conditionals, so that execution only breaks if a certain condition holds.
break, br, bOnce 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.
next, nstep, sstepi, sicontinue, c, fg