Table of Contents

GDB tutorial

Loading a program

In order to start debugging using GDB, you need to specify the program to be inspected. There are two options for doing this:

➜ gdb buggy
➜ gdb
...
pwndbg> file buggy
Reading symbols from buggy...

Once the debugging symbols from the executable were loaded, you can start executing your program using the run command.

pwndbg> run

You do not need the specify the full command, GDB can fill in the rest of a word in a command for you, if there is only one possibility.

E.g.: r, ru and run are equivalent; c, co, continue are equivalent.

In order to specify arguments for the debugged program, you can either:

pwndbg> set args a b
pwndbg> run a b

You do not need to specify the arguments each time: run with no arguments uses the same arguments used by the previous run, or those set by the set args command.

Breakpoints

Breakpoints represent places in your program where the execution should be stopped. They are added using the break command. Here are the most common usages:

You can see an overview of the current breakpoints using the info break command.

pwndbg> info b
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x000011de in wanted at buggy.c:6
2       breakpoint     keep y   0x00001229 in copy at buggy.c:16
3       breakpoint     keep y   0x00001281 in main at buggy.c:22

Short for info break is i b.

In order to remove breakpoints, you can use the clear or the delete (d) command. With the clear command you can delete breakpoints according to where they are in your program. With the delete command you can delete individual breakpoints by specifying their breakpoint numbers.

pwndbg> delete 2
pwndbg> clear buggy.c:6
Deleted breakpoint 1

Once you want to resume execution, you can use the continue (c) command.

pwndbg> continue
Continuing.
...
[Inferior 1 (process 11131) exited normally]

Start

The start command is very similar to run, but instead of running the program until it ends (or until it crashes), it sets a breakpoint at the beginning of the main function.

Stepping

There might be situations when you only want to execute one line of source code, or one machine instruction from your program. This action is called step and can be categorized as follows:

There are also equivalent functions for the machine instructions: stepi and nexti. Those are useful when the binary uses various compiler optimizations and the source lines debug metadata are unreliable (i.e., they skip too much).

If you stepped into a function and you want to continue the execution until the function returns, you can use the finish or f (step out) command.

Printing variables and memory

No need to manually print registers anymore, but you still might need to print the content of a variable:

pwndbg> print argc
$1 = 2

The print or p command allows you to specify the format of the output like this (you can find a full list of possible format specifiers here):

pwndbg> p/x $esp
$1 = 0xffffd860

pwndbg> x/2x 0xffffd860
0xffffd860:     0xffffd8a0      0xf7fbe66c

pwndbg> p/d $esp
$2 = -10144

pwndbg> p/s buf
$3 = "hey"

pwndbg> p/x buf
$4 = {0x68, 0x65, 0x79, 0x0}

Reading and modifying memory

You can use the command x (for examine) to examine memory in several formats, independently of your program's data types.

pwndbg> x/nfu addr

n, f, and u are all optional parameters that specify how much memory to display and how to format it.

addr is an expression giving the address where you want to start displaying memory.

E.g.: Print 10 words in hexadecimal format, starting from the address of the current stack pointer.

pwndbg> x/10wx $esp
0xffffd850:     0xffffd890      0xf7fbe66c      0xf7fbeb20      0x00796568
0xffffd860:     0xffffd880      0xf7fa9000      0xf7ffd020      0xf7da0519
0xffffd870:     0xffffdabd      0x00000070

In order to change the value of a variable or of a specific memory area, you can use the set command:

pwndbg> set g = 4
pwndbg> set {int}0xffffd890 = 4

Stack info

A backtrace is a summary of how your program got where it is. It shows one line per frame, for many frames, starting with the currently executing frame (frame zero), followed by its caller (frame one), and on up the stack.

backtrace or bt - Print a backtrace of the entire stack: one line per frame for all frames in the stack.

E.g.:

pwndbg> backtrace
#0  copy () at buggy.c:16
#1  0x565562ca in main (argc=2, argv=0xffffd934) at buggy.c:29
#2  0xf7da0519 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

It is also possible to move up or down the stack using the following commands:

Another useful command for printing information related to the current stack frame is info frame. This command prints a verbose description of the selected stack frame, including: