6 min read 1355 words Updated Sep 12, 2026 Created Sep 12, 2026

summary

GDB debugger - info and some basics

a well-known debugger for Linux programs that should come pre-installed
use it to manipulate and inspect binaries and executables
if you do need to install:
sudo apt-get install gdb

enhancements:
set intel as the default assmebly flavor:
echo 'set disassembly-flavor intel' >> ~/.gdbinit

install gef plugin to enable view of registers and stack at each break, plus extra commands:

$ wget -O ~/.gdbinit-gef.py -q https://gef.blah.cat/py
$ echo source ~/.gdbinit-gef.py >> ~/.gdbinit

info functions - list functions
info variables - list variable
info registers - list registers
disas main - disassemble a function
run - run program
start - run program but break on entry

functions - list and call
info function <name>- info on a specific function
call function - may require return type and args:
call (char) function(arg)

breakpoints - use breakpoints to stop execution and inspect or set values
break *0x4551ad - asterisk before address to specify memory address, not a function or line number
break main+20
break puts()
break fcnName

c - continue execution
s - step to next line of code or function
si - step inside current function
ni - next instruction

examine:
x/s 0x402a4 - examine string at that address

set values (such as a register):
set $rip = 0x438457 - set instruction pointer to an address

Intro and Installation

GNU Debugger (GDB)

To debug our binaries, we will be using a well-known debugger for Linux programs called GNU Debugger (GDB). There are other similar debuggers for Linux, like Radare and Hopper, and for Windows, like Immunity Debugger and WinGDB. There are also powerful debuggers available for many platforms, like IDA Pro and EDB. In this module, we will be using GDB. It is the most reliable for Linux binaries since it is built and maintained directly by GNU, which gives it an excellent integration with the Linux system and its components.

Install gdb

GDB is installed in many Linux distributions, and it is also installed by default in Parrot OS and PwnBox. In case it is not installed in your VM, you can use apt to install it with the following commands:

$ sudo apt-get update
$ sudo apt-get install gdb

set intel disassembly flavor in gdb init
$ echo 'set disassembly-flavor intel' >> ~/.gdbinit

install gef plugin

One of the great features of GDB is its support for third-party plugins. An excellent plugin that is well maintained and has good documentation is GEF. GEF is a free and open-source GDB plugin that is built precisely for reverse engineering and binary exploitation. T

To add GEF to GDB, use the following commands:

$ wget -O ~/.gdbinit-gef.py -q https://gef.blah.cat/py
$ echo source ~/.gdbinit-gef.py >> ~/.gdbinit

Getting Started

Now that we have both tools installed, we can run gdb to debug our HelloWorld binary using the following commands, and GEF will be loaded automatically:

$ gdb -q ./helloWorld

gef➤

As we can see from gef➤, GEF is loaded when GDB is run. If you ever run into any issues with GEF, you can consult with the GEF Documentation, and you will likely find a solution.

Going forward, we will frequently be assembling and linking our assembly code and then running it with gdb. To do so quickly, we can use the assembler.sh script we wrote in the previous section with the -g flag. It will assemble and link the code, and then run it with gdb, as follows:

  GNU Debugger (GDB)

fluffyfluffyhead@htb[/htb]$ ./assembler.sh helloWorld.s -g
...SNIP...
gef➤

Info

Once GDB is started, we can use the info command to view general information about the program, like its functions or variables.

Tip: If we want to understand how any command runs within GDB, we can use the help CMD command to get its documentation. For example, we can try executing help info

Functions

To start, use the info command to check which functions are defined within the binary:
`(gdb) info functions

Variables

use the info variables command to view all available variables within the program:
` info variables

Disassemble

To view the instructions within a specific function, we can use the disassemble or disas shortcut along with the function name, as follows:
` gdb➤ disas main

info breakpoints
info functions - list functions

functions

info function <name> - info on a specific function
call function - may require return type and args:
call (char) function(arg)

breakpoints

break *0x4551ad - asterisk before address to specify memory address, not a function or line number
disable, enable, delete - breakpoint options

conditional breakpoints

examples:
b loopFib if $rbx > 10
b *loopFib+9 if $rbx . 10
b *401012 if $rbx > 10

r, run
set args <arg>

x = examine
x/FMT ADDRESS = examine, format ( x, s, i ) , address
format can be : x hex, s string, i instruction

format can take 3 characters as arguments:
count: , starting at address
format: x,s,i x hex, s string, i instruction
size: b(byte), h(halfword), w(word), g(giant, 8 bytes)

Note: if we don't specify the Size or Format, it will default to the last one we used.

print the value of the IP ( Instruction Pointer ) register:

  • x $rip

print the value of the next 4 instructions:

  • x/4ig $rip

examine string at 0x40200:

  • x/s 0x40200

print...
p/d $rbx - print rbx as a decimal

si - step into function calls, assembly instructins one by one
s / step - until next line of code or function
ni - step over, stay in current (main) functionhandle SIGILL nostop noprint pass

continue - run until next break point
info registers to see addresses and values

set the instruction pointer

set $rip=0xaddr - set the instruction pointer to a spot you want to run next

.rodata- read only data - get from objdump -x - all headers

stepping through errors:

handle SIGILL nostop noprint pass handle SIGSEGV nostop noprint pass

setting and modifying

set in gdb
patch in GEF

patch string 0x402000 "Patched!\\x0a
set $rdx=0x9 = the space allocated in rdx for the original string was 18, but our patch is only 9, so we change rdx to the size of our string

address randomization

set disable-randomization on

 your executable is a Position-Independent Executable (PIE) with ASLR (Address Space Layout Randomization) enabled. Here's why this happens:
 ## 1. PIE Behavior

  • At disassembly time (before running), GDB shows relative offsets from the link-time base address (typically 0x0000000000001000 for modern Linux PIEs)
    So if:
Original disassembly offset: 0x115d
Actual runtime base address: 0x555555554000
Final runtime address: 0x555555554000 + 0x115d = 0x55555555515d

Why GDB Shows Different Addresses

  • Pre-run disassembly: Displays link-time addresses (0x115d in your case)
  • Runtime addresses: Show actual loaded addresses (0x55555555515d)

Check if your executable is PIE:
`file /home/kali/assemblyLearn/fileName
-- Output should include: "ELF 64-bit LSB pie executable"

  • Disable ASLR for stable addresses during debugging:
  • echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
  • OR
  • (gdb) set diasable-randomization on

to get addressing consistent with disassembly, run the program before disassembling

break main
run
disassemble main
info functions fg --> list functions, look for 'fg'

show registers - list the value of the registers

display/i $eip       # Show current instruction
display $eax         # Show EAX every step
display $ebx         # You can do others like $ecx, $edx...

gef

registers - print out current value of all registers

Auto-import radare2’s function list into GDB (quick & dirty)

Have r2 analyze and emit a little GDB script that matches r2's functions analysis and names the addresses accordingly

# Generate a gdb script with "set $fcn_..." lines
r2 -e scr.color=0 -Aqc 'afl' ./stone \
| sed -r 's/\x1B\[[0-9;]*[A-Za-z]//g' \
| awk '{
addr=$1; name=$NF;
sub(/^sym\./,"",name);
gsub(/[^A-Za-z0-9_]/,"_",name);
printf "set $%s = %s\n", name, addr
}' > r2syms.gdb

# Then in GDB:

source r2syms.gdb
set disable randomization on

b *$fcn_004006ee ( or functions per r2 list )

Note: We replace . with _ because GDB convenience vars can’t contain dots.