puck tools — test your egress policy against real C2 traffic →
#linux#gdb

Basic config

Before we go too far, let’s handle some basic setup. Everything after this lesson assumes the settings below, so the output you see will match the output printed here.

Out of the box GDB has no command history between sessions, prints structures as one unreadable line, stops every twenty lines to ask if you want to see more, and shows you AT&T assembly syntax. All four are one line each to fix.

GDB settings

Put this in ~/.gdbinit:

# Remember what I typed, across sessions.
set history save on
set history size 10000
set history filename ~/.gdb_history

# Intel syntax. Matches Ghidra, IDA, and every exploit write-up you will read.
set disassembly-flavor intel

# Print structures across multiple lines instead of one 400-column smear.
set print pretty on
# Follow pointers one level when printing a struct that contains them.
set print object on

# Stop asking "---Type <return> to continue---" every screenful.
set pagination off
# Stop asking "are you sure" for things I clearly meant.
set confirm off

# Show 8 disassembled instructions around the stop, always.
set disassemble-next-line on

What is disassembly flavour?. Everything else in the reverse-engineering world speaks Intel syntax as god intended. With intel syntax the destination comes first: mov rbp, rsp. GDB defaults to AT&T, where the destination comes last: mov %rsp, %rbp. Reading one while writing the other will cost you an hour eventually.

$ gdb -q ./hello
Reading symbols from ./hello...
(gdb) disassemble check
Dump of assembler code for function check:
   0x0000000000401176 <+0>:	endbr64
   0x000000000040117a <+4>:	push   rbp
   0x000000000040117b <+5>:	mov    rbp,rsp
   0x000000000040117e <+8>:	sub    rsp,0x10

That is with set disassembly-flavor intel. Without it the third line reads mov %rsp,%rbp, which means the same thing backwards.

Per-project config

GDB also reads .gdbinit from the current directory. That is where project-specific setup belongs, such as the breakpoints you always want and the pretty printers for your own types:

file ./hello
break check
run CONTEXT

Modern GDB refuses to auto-load a .gdbinit from a directory you do not own, because otherwise cloning a repository would be enough to run arbitrary commands on your machine. When it declines, it tells you exactly what to add:

add-auto-load-safe-path /home/you/projects

Add the paths you trust. Do not set set auto-load safe-path / and forget about it. That is the setting whose absence is protecting you.

The TUI

GDB has a built-in split-screen mode. Ctrl-X A toggles it, or start with gdb -tui.

(gdb) layout src      # source over command line
(gdb) layout asm      # disassembly instead
(gdb) layout split    # both at once
(gdb) layout regs     # add a register pane
(gdb) focus cmd       # arrow keys go to the prompt again

The TUI is useful and mildly cursed. It redraws badly over slow SSH, and any program that writes to the terminal will scribble on your panes. Ctrl-L repaints. If it gets stuck, tui disable gets you back.

Keep that annoyance in mind. There is a better answer than the TUI, and we get to it in the last lesson.

One command worth knowing early

start is break main plus run in a single word, which is how most sessions actually begin.

That is stock GDB configured about as well as it goes.

Next: what break actually did to your program.