Introduction to GDB

The GNU Project debugger (GDB) allows us to look at the state of another program while it’s running or before it crashes. These programs could be running on the same machine, another machine, or even a simulator. GDB is compatible with the most popular UNIX and Microsoft Windows variants and Mac OS X. GDB currently has support for C, C++, D, Go, Objective-C, Fortran, OpenCL C, Pascal, Rust, assembly, Modula-2, and Ada.

Press + to interact

Loading a core file

We can load a core dump file by passing it directly as a parameter while invoking GDB:

gdb -c <core-dump-file> -se <app-binary>

This will load the core-dump-file along with the symbol table from the app-binary and also treat app-binary as the file that is executed when needed.

We can also achieve the same effect from within GDB using:

core-file <core-dump-file>
file <app-binary>

The above command will output the following to the terminal:

Printing the stack trace

When we are debugging, we often would like to see where we are currently in the execution process of our application, and the most effective method to verify that is to print the stack trace. We can do so using backtrace (bt for short):

bt

The above command will output the following to the terminal:

Retrieving information

We will often need to see information about active threads, variables, and values of registers in use by the application during the debugging process. We can do this in GDB using the info command (or the short version i). We can pass different arguments to the command:

  • If we need to see the threads in use, we can use the command info threads

  • Similarly, if we want to show current values of all registers, we can use info registers or info reg for short. For a specific register, we can use info registers <register name>.

Examining contents of memory

Throughout the course, we’ll use the following command to examine memory contents at the given address:

x “specific address” 

The general form of this command is as follows:

x/[Count][Format][Unit] [Address]

Here, [Format] specifies the output format. Valid options for this are as follows:

  • x, d, o, t: This is for showing output in hexadecimal, decimal, octal, or binary format.

  • u: This is for showing the memory contents as an unsigned decimal number.

  • a: This is for showing the memory contents as addresses.

  • i: This is for showing output as an instruction.

  • s: This is for treating the given address as the starting address of a null-terminated string.

  • c: This is for showing the memory contents as a character.

The [Unit] command specifies how much content to retrieve:

  • b: This is for retrieving just a byte.

  • h: This is for retrieving a half word (2 bytes).

  • w: This is for retrieving a word (4 bytes).

  • g: This is for retrieving a giant word (8 bytes).

The [Count] command specifies how many units to retrieve.

All three of the following modifiers are optional:

  • x/24i 0x4075cb: This retrieves 24 instructions, starting from the address 0x4075cb.

  • x/5dg 0x4075cb: This retrieves 5 giant words (8×5=408 \times 5 = 40 bytes), starting from the address 0x4075cb  and displays them in decimal format.

  • x/3s 0x4075cb: This retrieves 3 null-terminated strings, starting from the address 0x4075cb.

Disassembling a function

The last thing that we will cover in this lesson is how we can disassemble any function or address. We can disassemble in GDB with the disassemble command (short form disass). 

disassemble "function name" 

This will return the disassembled code of the function with the specified name, while the disassemble address will show the disassembled code of the function that contains the given instruction.

Other frequently used GDB commands

We have discussed the main commands that we will be using in the course, but here are a few other commands that we might occasionally see during the debugging process later on in the course.

  1. set logging on/off: This is for saving the output of the GDB session to a text file in the current working directory.

  2. set pagination on/off: This is for enabling/disabling page-breaks in the GDB output.

  3. frame <number>: This is for selecting the stack frame <number> and printing a brief description.

  4. q: This is for exiting the GDB debugger.

  5. c: This is for continuing the execution.

We can find the complete list of GDB commands on this website. We can type the following command in the GDB terminal for help on using a command:

help “command”

Try it out

You can try out these commands in an interactive session below.

Note: It’s recommended that you click the “Run” button periodically to extend your session.

# Loading the core file

gdb -c core.App0 -se App0

# Printing the stack trace

bt

# Retrieving information

info threads
info registers
info registers rip

# Examining contents of memory

x/24i 0x4075cb
x/5dg 0x4075cb
x/3s 0x4075cb

# Disassembling a function

disassemble raise

# Help

help disassemble
Common GDB commands for debugging