pete > guides > gdb


The GNU debugger, gdb, is a program that allows one to... uh... debug programs. When you compile your program with a special flag, you can then run your program from within gdb, control its execution, and examine it state (registers, memory, etc) while it's running.

The official documentation is available here.

Invoking gdb on your program

When you compile your program, add the "-g" flag. For example:

$ gcc -g -o foo foo.c

Then you can start debugging the just-compiled program thusly (everything after the first line is printed out in response):

$ gdb foo
GNU gdb (GDB) 7.10
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from foo...done.
(gdb)

You'll see a bunch of inscrutable like the ones shown above. If the last line before the "(gdb)" prompt says something like, "Reading symbols from foo...(no debugging symbols found)...done." then you forgot to compile with -g. Go back and fix that.

Now you can type gdb commands at the "(gdb)" prompt.

Useful GDB commands

What follows is far from an exhaustive list (run "help" inside gdb to see everything and to get help on individual commands). Many commands have abbreviated versions: they are given in parentheses below.

run (r)

When you feed your program to gdb, it doesn't start running automatically. Use the "run" command to run it:

(gdb) run
Starting program: /home/pete/tmp/foo/foo 
[Inferior 1 (process 3502) exited normally]

If you want to give command-line arguments to your program, just add them after "run":

(gdb) run arg1 arg2
Starting program: /home/pete/tmp/foo/foo 
[Inferior 1 (process 3502) exited normally]

break (b)

Use the "break" command to insert a breakpoint. When the program reaches a breakpoint, it will stop and return you to the gdb prompt, allowing you to enter other commands. For all of the following, execution will stop immediately before the line of code/instruction indicated by the breakpoint.

You can break on a line number:

(gdb) b 3
Breakpoint 1 at 0x4004c1: file foo.c, line 3.

If your program has multiple source files, you can specify both filename and line number:

(gdb) b bar.c:19
Breakpoint 1 at 0x4004c1: file bar.c, line 19.

You can break at the beginning of a particular function, identified by name:

(gdb) break myfunc 
Breakpoint 1 at 0x4004d3: file foo.c, line 14.

Finally, you can break at a specific instruction, identified by memory address (ie, when the program counter has that value, execution will stop). Note the asterisk!

(gdb) break *0x400507
Breakpoint 1 at 0x400507: file foo.c, line 25.

When execution reaches a breakpoint, gdb will print out the line of code that will be executed next.

clear

Clear (ie, remove) a breakpoint using the "clear" command. It takes the same arguments as "break". You can use the "info breakpoints" command to list all breakpoints. You can also remove breakpoints by number (the leftmost column in the output of "info breakpoints"): for instance, "delete break 3" will remove breakpoint #3.

continue (c)

If your program has started running but has stopped (because, eg, it hit a breakpoint) you can continue running it using the "continue" command.

(gdb) continue
Continuing.

step (s) & next (n)

Instead of continuing until you hit the next breakpoint, you can instead nudge your program forward by a single line of code. The "step" and "next" commands used for this differ only when the next line of code to execute is a function call. In this case, "step" will cause you to descend into the called function and debug it, whereas "next" will treat the function call as a single line of code.

Just as with breakpoints, when you use step or next, gdb will print out the line of code that will be executed next.

info reg

When your program is running but stopped (eg, you used the "run" command but execution hit a breakpoint), you can examine the contents of all registers with the "info reg" command.

(gdb) info reg
rax            0x4004b6 4195510
rbx            0x0  0
rcx            0x0  0
rdx            0x7fffffffe828   140737488349224
rsi            0x7fffffffe818   140737488349208
rdi            0x1  1
rbp            0x7fffffffe730   0x7fffffffe730
rsp            0x7fffffffe700   0x7fffffffe700
r8             0x400610 4195856
r9             0x7ffff7dea670   140737351951984
r10            0x83e    2110
r11            0x7ffff7a57520   140737348203808
r12            0x4003c0 4195264
r13            0x7fffffffe810   140737488349200
r14            0x0  0
r15            0x0  0
rip            0x4004d3 0x4004d3 <main+29>
eflags         0x206    [ PF IF ]
cs             0x33 51
ss             0x2b 43
ds             0x0  0
es             0x0  0
fs             0x0  0
gs             0x0  0

The first column is the name of the register, the second column is the value in hex, and the third column is gdb's best attempt at rendering the value in a meaningful format. (For example, "rbp" and "rsp" show as pointers, whereas "cs" and "ss" show as unsigned ints.)

print

Sometimes "info reg" is too much. You can print the contents of individual registers with "print", like so:

(gdb) print $rip
$1 = (void (*)()) 0x4004d3 <main+29>
(gdb) print $rbp
$2 = (void *) 0x7fffffffe730

Note the leading dollar sign to indicate that the thing you want to print is a register.

Perhaps more usefully, you can print the values of C variables!

(gdb) print x
$3 = 4195744

You can also print compound variables like structs:

(gdb) print b
$4 = {x = 4195744, y = 0}

(The $4 bit at the beginning just says this is the fourth thing you've printed out. You can play games with this, but those are beyond the scope of this documentation.)

No matter what you try to print, gdb will do its best to present it to you in as intuitive a format as possible.

x

Printing registers and variables is nice, but sometimes you need to poke around memory, which is what the eXamine command does. This one has lots of variations: you can optionally specify how much data you want to examine, what units you're specifying, and the address to start at. The basic pattern is: x/<num><type> <address>, where any of the three options are... optional. (If you omit both num and type, you can ditch the slash.) Examples follow.

To check out the 4 32-bit values starting at address 0x7fffffffe730:

(gdb) x/4x 0x7fffffffe730
0x7fffffffe730: 0x004005a0  0x00000000  0xf7a57610  0x00007fff

To check out the 2 32-bit integers starting immediately following the chunk of memory you just examined (that is, if you don't specify the address, it'll assume you want to examine memory sequentially from your previous examination):

(gdb) x/2d
0x7fffffffe740: -6120   32767

To check out the 5 instructions starting at address 0x4004be (the "=>" helpfully indicates the current value of the program counter):

(gdb) x/5i 0x4004cc
   0x4004cc <main+22>:  mov  DWORD PTR [rbp-0xc],0x0
=> 0x4004d3 <main+29>:  mov  DWORD PTR [rbp-0x20],0x4
   0x4004da <main+36>:  mov  DWORD PTR [rbp-0x1c],0x3
   0x4004e1 <main+43>:  lea  rdx,[rbp-0x20]
   0x4004e5 <main+47>:  lea  rax,[rbp-0x10]

Instead of addresses, you can use registers. So to check out the current stack frame:

(gdb) x/12x $rbp
0x7fffffffe730: 0x004005a0  0x00000000  0xf7a57610  0x00007fff
0x7fffffffe740: 0xffffe818  0x00007fff  0xffffe818  0x00007fff
0x7fffffffe750: 0x00000000  0x00000001  0x004004b6  0x00000000

IMPORTANT: Because x86 is a little-endian architecure, the byte ordering listed above may be kind of counterintuitive. Within each 32-bit hex value above, the bytes are ordered from right to left. Compare this output with the first hex value on the first line of the previous command:

(gdb) x/b $rbp
0x7fffffffe730: 0xa0
(gdb) x/b $rbp+1
0x7fffffffe731: 0x05
(gdb) x/b $rbp+2
0x7fffffffe732: 0x40
(gdb) x/b $rbp+3
0x7fffffffe733: 0x00

This is easily the most complicated command you'll need in the medium term. For more info, check out "help x".

disassemble (disas)

You can ask gdb to disassemble (parts of) your program for you.

With no parameters, it will disassemble the current function (notice the helpful "=>"):

(gdb) disas
Dump of assembler code for function main:
   0x00000000004004b6 <+0>:     push   rbp
   0x00000000004004b7 <+1>:     mov    rbp,rsp
   0x00000000004004ba <+4>:     sub    rsp,0x30
   0x00000000004004be <+8>:     mov    DWORD PTR [rbp-0x24],edi
   0x00000000004004c1 <+11>:    mov    QWORD PTR [rbp-0x30],rsi
   0x00000000004004c5 <+15>:    mov    DWORD PTR [rbp-0x10],0x0
   0x00000000004004cc <+22>:    mov    DWORD PTR [rbp-0xc],0x0
=> 0x00000000004004d3 <+29>:    mov    DWORD PTR [rbp-0x20],0x4
   0x00000000004004da <+36>:    mov    DWORD PTR [rbp-0x1c],0x3
   0x00000000004004e1 <+43>:    lea    rdx,[rbp-0x20]
   0x00000000004004e5 <+47>:    lea    rax,[rbp-0x10]
   0x00000000004004e9 <+51>:    mov    rsi,rdx
   0x00000000004004ec <+54>:    mov    rdi,rax
   0x00000000004004ef <+57>:    call   0x400508 <dist_squared>
   0x00000000004004f4 <+62>:    pxor   xmm0,xmm0
   0x00000000004004f8 <+66>:    cvtsi2ss xmm0,eax
   0x00000000004004fc <+70>:    movss  DWORD PTR [rbp-0x4],xmm0
   0x0000000000400501 <+75>:    mov    eax,0x0
   0x0000000000400506 <+80>:    leave  
   0x0000000000400507 <+81>:    ret    
End of assembler dump.

Or you can give it a function name:

(gdb) disas dist_squared_better 
Dump of assembler code for function dist_squared_better:
   0x0000000000400550 <+0>:     push   rbp
   0x0000000000400551 <+1>:     mov    rbp,rsp
   0x0000000000400554 <+4>:     mov    QWORD PTR [rbp-0x18],rdi
   0x0000000000400558 <+8>:     mov    QWORD PTR [rbp-0x20],rsi
   0x000000000040055c <+12>:    mov    rax,QWORD PTR [rbp-0x18]
   0x0000000000400560 <+16>:    mov    edx,DWORD PTR [rax]
   0x0000000000400562 <+18>:    mov    rax,QWORD PTR [rbp-0x20]
   0x0000000000400566 <+22>:    mov    eax,DWORD PTR [rax]
   0x0000000000400568 <+24>:    sub    edx,eax
   0x000000000040056a <+26>:    mov    eax,edx
   0x000000000040056c <+28>:    mov    DWORD PTR [rbp-0x4],eax
   0x000000000040056f <+31>:    mov    rax,QWORD PTR [rbp-0x18]
   0x0000000000400573 <+35>:    mov    edx,DWORD PTR [rax+0x4]
   0x0000000000400576 <+38>:    mov    rax,QWORD PTR [rbp-0x20]
   0x000000000040057a <+42>:    mov    eax,DWORD PTR [rax+0x4]
   0x000000000040057d <+45>:    sub    edx,eax
   0x000000000040057f <+47>:    mov    eax,edx
   0x0000000000400581 <+49>:    mov    DWORD PTR [rbp-0x8],eax
   0x0000000000400584 <+52>:    mov    eax,DWORD PTR [rbp-0x4]
   0x0000000000400587 <+55>:    imul   eax,DWORD PTR [rbp-0x4]
   0x000000000040058b <+59>:    mov    edx,eax
   0x000000000040058d <+61>:    mov    eax,DWORD PTR [rbp-0x8]
   0x0000000000400590 <+64>:    imul   eax,DWORD PTR [rbp-0x8]
   0x0000000000400594 <+68>:    add    eax,edx
   0x0000000000400596 <+70>:    pop    rbp
   0x0000000000400597 <+71>:    ret    
End of assembler dump.

Or an address, in which case it dumps the entire function containing that address:

(gdb) disas 0x0000000000400581
Dump of assembler code for function dist_squared_better:
   0x0000000000400550 <+0>:     push   rbp
   0x0000000000400551 <+1>:     mov    rbp,rsp
   0x0000000000400554 <+4>:     mov    QWORD PTR [rbp-0x18],rdi
   0x0000000000400558 <+8>:     mov    QWORD PTR [rbp-0x20],rsi
   0x000000000040055c <+12>:    mov    rax,QWORD PTR [rbp-0x18]
   0x0000000000400560 <+16>:    mov    edx,DWORD PTR [rax]
   0x0000000000400562 <+18>:    mov    rax,QWORD PTR [rbp-0x20]
   0x0000000000400566 <+22>:    mov    eax,DWORD PTR [rax]
   0x0000000000400568 <+24>:    sub    edx,eax
   0x000000000040056a <+26>:    mov    eax,edx
   0x000000000040056c <+28>:    mov    DWORD PTR [rbp-0x4],eax
   0x000000000040056f <+31>:    mov    rax,QWORD PTR [rbp-0x18]
   0x0000000000400573 <+35>:    mov    edx,DWORD PTR [rax+0x4]
   0x0000000000400576 <+38>:    mov    rax,QWORD PTR [rbp-0x20]
   0x000000000040057a <+42>:    mov    eax,DWORD PTR [rax+0x4]
   0x000000000040057d <+45>:    sub    edx,eax
   0x000000000040057f <+47>:    mov    eax,edx
   0x0000000000400581 <+49>:    mov    DWORD PTR [rbp-0x8],eax
   0x0000000000400584 <+52>:    mov    eax,DWORD PTR [rbp-0x4]
   0x0000000000400587 <+55>:    imul   eax,DWORD PTR [rbp-0x4]
   0x000000000040058b <+59>:    mov    edx,eax
   0x000000000040058d <+61>:    mov    eax,DWORD PTR [rbp-0x8]
   0x0000000000400590 <+64>:    imul   eax,DWORD PTR [rbp-0x8]
   0x0000000000400594 <+68>:    add    eax,edx
   0x0000000000400596 <+70>:    pop    rbp
   0x0000000000400597 <+71>:    ret    
End of assembler dump.

backtrace (bt)

When your program is running but stopped (eg, you used the "run" command but execution hit a breakpoint), you can print the trail of cookie crumbs that got you there, called a backtrace.

For instance:

(gdb) bt
#0  baz (p1=10) at double-func.c:39
#1  0x0000000000400505 in foo (p1=10) at double-func.c:23
#2  0x00000000004004d6 in main (argc=1, argv=0x7fffffffe828) at double-func.c:14

This tells us that we're currently in the function baz(), on line 39. We got there because foo() called baz() on line 23. We got there because main() called foo() at line 14. The numbers in the left-hand column are the indices of the stack frames: the stack frame for baz() is on top, then the frame for foo(), and finally the frame for main().

frame (f)

When you try to print the values of variables, gdb will only allow you to print global variables and variables local to the current stack frame. You can use the "frame" command to change the stack frame you're looking at. (This example uses the same stack arrangement as in the "bt" example.)

(gdb) f 1
#1  0x0000000000400505 in foo (p1=10) at double-func.c:23
23      b = baz(p1);

Now I can examine variables local to foo(), whereas before I could only examine variables local to baz().

info frame

You can ask gdb for information about the current frame using, unsurprisingly, the info frame command. (This example was run immediately following the "f 1" command in the "frame" example.)

(gdb) info frame
Stack level 1, frame at 0x7fffffffe720:
 rip = 0x400505 in foo (double-func.c:23); saved rip = 0x4004d6
 called by frame at 0x7fffffffe750, caller of frame at 0x7fffffffe6f0
 source language c.
 Arglist at 0x7fffffffe710, args: p1=10
 Locals at 0x7fffffffe710, Previous frame's sp is 0x7fffffffe720
 Saved registers:
  rbp at 0x7fffffffe710, rip at 0x7fffffffe718

Last modified: