Skip to content

GDB - GNU Debugger

The GNU Debugger (GDB) stands as the most widely-used and feature-rich debugger in the Unix and Linux ecosystem, serving as an indispensable tool for software developers, system administrators, and security researchers worldwide. Originally developed as part of the GNU Project by Richard Stallman and others, GDB has evolved over more than three decades into a sophisticated debugging platform that supports multiple programming languages including C, C++, Ada, Fortran, Go, Rust, and many others. Its comprehensive feature set encompasses everything from basic breakpoint debugging to advanced capabilities like reverse debugging, remote debugging, and multi-threaded application analysis. GDB's command-line interface, while initially daunting to newcomers, provides unparalleled power and flexibility for diagnosing complex software issues, making it the debugger of choice for everything from embedded systems development to large-scale enterprise applications and operating system kernel debugging.

Installation and Setup

Installing GDB on Different Platforms

bash
# Ubuntu/Debian installation
sudo apt update
sudo apt install gdb

# Install GDB with additional features
sudo apt install gdb gdb-multiarch

# Install GDB for specific architectures
sudo apt install gdb-arm-linux-gnueabihf
sudo apt install gdb-aarch64-linux-gnu

# CentOS/RHEL/Fedora installation
sudo dnf install gdb
sudo yum install gdb  # Older systems

# macOS installation (using Homebrew)
brew install gdb

# Note: On macOS, you may need to code-sign GDB
# Create a certificate in Keychain Access and sign:
codesign -s gdb-cert /usr/local/bin/gdb

# Windows installation (MinGW/MSYS2)
pacman -S gdb

# Verify installation
gdb --version
gdb --help

# Check supported architectures
gdb --batch --ex "show architecture"

# Check supported languages
gdb --batch --ex "info languages"

GDB Configuration

bash
# GDB configuration file locations
# System-wide: /etc/gdb/gdbinit
# User-specific: ~/.gdbinit
# Project-specific: .gdbinit (in current directory)

# Sample ~/.gdbinit configuration
cat > ~/.gdbinit << 'EOF'
# Enable history
set history save on
set history size 10000
set history filename ~/.gdb_history

# Pretty printing
set print pretty on
set print array on
set print array-indexes on
set print elements 200

# Disassembly settings
set disassembly-flavor intel
set disassemble-next-line auto

# Auto-load settings
set auto-load safe-path /

# Python support
python
import sys
sys.path.insert(0, '/usr/share/gdb/python')
end

# Convenience variables
set $SHOW_CONTEXT = 1
set $SHOW_NEST_INSN = 0

# Custom commands
define hook-stop
    info registers
    x/5i $pc
end
EOF

# Environment variables
export GDBHISTFILE=~/.gdb_history
export GDBHISTSIZE=10000

# Debugging symbols
# Ensure programs are compiled with debug information
gcc -g -O0 program.c -o program
g++ -g -O0 program.cpp -o program

# Install debug symbols for system libraries (Ubuntu/Debian)
sudo apt install libc6-dbg
sudo apt install libstdc++6-dbg

# Enable core dumps
ulimit -c unlimited
echo "core" | sudo tee /proc/sys/kernel/core_pattern

Basic GDB Usage

Starting and Controlling GDB

bash
# Start GDB with a program
gdb program
gdb ./program
gdb /path/to/program

# Start GDB with arguments
gdb --args program arg1 arg2 arg3

# Attach to running process
gdb -p PID
gdb program PID

# Start GDB in batch mode
gdb --batch --ex "run" --ex "bt" --args program

# Start GDB with core dump
gdb program core
gdb program core.12345

# Remote debugging
gdb -ex "target remote hostname:port" program

# Start program with environment
gdb --ex "set environment VAR=value" program

# Quiet startup (no banner)
gdb -q program
gdb --quiet program

# Execute commands from file
gdb -x commands.gdb program
gdb --command=commands.gdb program

# Basic GDB commands
(gdb) help                    # Show help
(gdb) help running           # Help for specific category
(gdb) help breakpoints       # Help for breakpoints
(gdb) quit                   # Exit GDB
(gdb) q                      # Short form of quit

Running and Controlling Execution

bash
# Run the program
(gdb) run
(gdb) r
(gdb) run arg1 arg2 arg3

# Set program arguments
(gdb) set args arg1 arg2 arg3
(gdb) show args

# Set environment variables
(gdb) set environment VAR=value
(gdb) unset environment VAR
(gdb) show environment

# Set working directory
(gdb) cd /path/to/directory
(gdb) pwd

# Continue execution
(gdb) continue
(gdb) c

# Step execution (into functions)
(gdb) step
(gdb) s
(gdb) step 5                 # Step 5 times

# Next execution (over functions)
(gdb) next
(gdb) n
(gdb) next 3                 # Next 3 times

# Step/next instruction level
(gdb) stepi
(gdb) si
(gdb) nexti
(gdb) ni

# Finish current function
(gdb) finish
(gdb) fin

# Until (run until line or address)
(gdb) until
(gdb) until 25               # Until line 25
(gdb) until function_name

# Jump to location
(gdb) jump 25                # Jump to line 25
(gdb) jump *0x400123         # Jump to address

# Return from function
(gdb) return
(gdb) return 42              # Return with value

Breakpoints and Watchpoints

Setting Breakpoints

bash
# Set breakpoint at function
(gdb) break main
(gdb) b main
(gdb) break function_name

# Set breakpoint at line number
(gdb) break 25
(gdb) b 25
(gdb) break file.c:25

# Set breakpoint at address
(gdb) break *0x400123
(gdb) b *main+10

# Conditional breakpoints
(gdb) break main if argc > 1
(gdb) break 25 if x == 5
(gdb) break function if strcmp(str, "test") == 0

# Temporary breakpoints (delete after hit)
(gdb) tbreak main
(gdb) tb 25

# Set breakpoint with commands
(gdb) break main
(gdb) commands
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>print "Entering main"
>print argc
>continue
>end

# Breakpoint on system calls
(gdb) catch syscall
(gdb) catch syscall write
(gdb) catch syscall 1        # sys_exit

# Breakpoint on signals
(gdb) catch signal SIGSEGV
(gdb) catch signal SIGINT

# Breakpoint on C++ exceptions
(gdb) catch throw
(gdb) catch catch
(gdb) catch exception std::runtime_error

Managing Breakpoints

bash
# List breakpoints
(gdb) info breakpoints
(gdb) info b

# Enable/disable breakpoints
(gdb) disable 1              # Disable breakpoint 1
(gdb) enable 1               # Enable breakpoint 1
(gdb) disable                # Disable all breakpoints
(gdb) enable                 # Enable all breakpoints

# Delete breakpoints
(gdb) delete 1               # Delete breakpoint 1
(gdb) delete 1-3             # Delete breakpoints 1-3
(gdb) delete                 # Delete all breakpoints
(gdb) clear                  # Clear breakpoint at current location
(gdb) clear main             # Clear breakpoint at main
(gdb) clear 25               # Clear breakpoint at line 25

# Modify breakpoint conditions
(gdb) condition 1 x > 10     # Add condition to breakpoint 1
(gdb) condition 1            # Remove condition from breakpoint 1

# Ignore breakpoint hits
(gdb) ignore 1 5             # Ignore next 5 hits of breakpoint 1

# Save and restore breakpoints
(gdb) save breakpoints file.bp
(gdb) source file.bp

Watchpoints

bash
# Watch variable for changes
(gdb) watch variable
(gdb) watch *0x400123        # Watch memory address

# Read watchpoint (break when read)
(gdb) rwatch variable
(gdb) rwatch *0x400123

# Access watchpoint (break on read or write)
(gdb) awatch variable
(gdb) awatch *0x400123

# Conditional watchpoints
(gdb) watch x if x > 100

# Watch expressions
(gdb) watch (x + y)
(gdb) watch strlen(str)

# Hardware vs software watchpoints
(gdb) set can-use-hw-watchpoints 0  # Force software watchpoints
(gdb) set can-use-hw-watchpoints 1  # Allow hardware watchpoints

# List watchpoints
(gdb) info watchpoints

Examining Program State

Stack and Frames

bash
# Show stack trace (backtrace)
(gdb) backtrace
(gdb) bt
(gdb) bt full                # Show local variables
(gdb) bt 10                  # Show only 10 frames

# Navigate stack frames
(gdb) frame 0                # Go to frame 0 (current)
(gdb) frame 2                # Go to frame 2
(gdb) up                     # Go up one frame
(gdb) down                   # Go down one frame
(gdb) up 2                   # Go up 2 frames

# Show current frame
(gdb) frame
(gdb) f

# Show frame information
(gdb) info frame
(gdb) info args              # Show function arguments
(gdb) info locals            # Show local variables
(gdb) info registers         # Show CPU registers
(gdb) info all-registers     # Show all registers including FPU

# Select frame and examine
(gdb) frame 1
(gdb) list                   # Show source code
(gdb) print variable         # Print variable in this frame

Variables and Memory

bash
# Print variables
(gdb) print variable
(gdb) p variable
(gdb) print/x variable       # Print in hexadecimal
(gdb) print/d variable       # Print in decimal
(gdb) print/o variable       # Print in octal
(gdb) print/t variable       # Print in binary
(gdb) print/c variable       # Print as character
(gdb) print/f variable       # Print as float

# Print arrays
(gdb) print array[0]@10      # Print first 10 elements
(gdb) print *array@10        # Same as above
(gdb) print array            # Print entire array (if size known)

# Print structures
(gdb) print struct_var
(gdb) print struct_var.member
(gdb) print/x struct_var     # Print in hex

# Print pointers
(gdb) print pointer
(gdb) print *pointer         # Dereference pointer
(gdb) print pointer[5]       # Array notation

# Examine memory
(gdb) x/10x 0x400123         # Examine 10 hex words at address
(gdb) x/10i $pc              # Examine 10 instructions at PC
(gdb) x/s 0x400123           # Examine string at address
(gdb) x/10c 0x400123         # Examine 10 characters

# Memory examination formats
# x/[count][format][size] address
# count: number of units to display
# format: x(hex), d(decimal), u(unsigned), o(octal), t(binary), 
#         a(address), c(char), f(float), s(string), i(instruction)
# size: b(byte), h(halfword), w(word), g(giant/8bytes)

(gdb) x/10xb 0x400123        # 10 bytes in hex
(gdb) x/5xw 0x400123         # 5 words in hex
(gdb) x/20i main             # 20 instructions starting at main

Registers and Assembly

bash
# Show registers
(gdb) info registers
(gdb) info reg
(gdb) info registers rax rbx # Show specific registers

# Show all registers including floating point
(gdb) info all-registers

# Print specific register
(gdb) print $rax
(gdb) print/x $rip
(gdb) print $pc              # Program counter

# Set register value
(gdb) set $rax = 0x12345678

# Disassemble
(gdb) disassemble
(gdb) disas
(gdb) disassemble main       # Disassemble function
(gdb) disassemble 0x400123   # Disassemble at address
(gdb) disas main,+50         # Disassemble 50 bytes from main
(gdb) disas $pc-10,$pc+10    # Disassemble around PC

# Set disassembly flavor
(gdb) set disassembly-flavor intel
(gdb) set disassembly-flavor att

# Show next instruction
(gdb) display/i $pc
(gdb) x/i $pc

# Step by instruction
(gdb) stepi
(gdb) si
(gdb) nexti
(gdb) ni

Advanced Debugging Features

Multi-threaded Debugging

bash
# Show threads
(gdb) info threads

# Switch to thread
(gdb) thread 2               # Switch to thread 2
(gdb) thread apply all bt    # Show backtrace for all threads
(gdb) thread apply 1-3 print variable  # Apply command to threads 1-3

# Thread-specific breakpoints
(gdb) break main thread 2    # Break in main only for thread 2
(gdb) break main thread 2 if x > 5

# Control thread execution
(gdb) set scheduler-locking on   # Only current thread runs
(gdb) set scheduler-locking off  # All threads run
(gdb) set scheduler-locking step # Only current thread steps

# Show thread-local storage
(gdb) info address variable

# Non-stop mode (continue other threads while debugging one)
(gdb) set non-stop on
(gdb) set target-async on

Remote Debugging

bash
# Start gdbserver on target machine
gdbserver :1234 program
gdbserver localhost:1234 program arg1 arg2

# Attach gdbserver to running process
gdbserver :1234 --attach PID

# Connect from GDB
(gdb) target remote hostname:1234
(gdb) target remote 192.168.1.100:1234

# Extended remote debugging
(gdb) target extended-remote hostname:1234
(gdb) set remote exec-file /path/to/program
(gdb) run

# File transfer
(gdb) remote put localfile remotefile
(gdb) remote get remotefile localfile

# Monitor commands
(gdb) monitor help           # Show gdbserver commands
(gdb) monitor exit           # Exit gdbserver

Core Dump Analysis

bash
# Generate core dump
ulimit -c unlimited          # Enable core dumps
kill -SEGV PID              # Force segmentation fault

# Load core dump
gdb program core
gdb program core.12345

# Analyze core dump
(gdb) bt                     # Show stack trace
(gdb) info registers         # Show register state
(gdb) print variable         # Examine variables
(gdb) x/10i $pc             # Show instructions around crash

# Generate core dump from running process
(gdb) generate-core-file
(gdb) gcore                  # Same as above

# Core dump with specific name
(gdb) generate-core-file mycore.dump

Reverse Debugging

bash
# Enable recording (required for reverse debugging)
(gdb) record
(gdb) record full            # Full recording mode

# Reverse execution commands
(gdb) reverse-continue       # Continue backwards
(gdb) rc                     # Short form
(gdb) reverse-step           # Step backwards
(gdb) rs
(gdb) reverse-next           # Next backwards
(gdb) rn
(gdb) reverse-stepi          # Step instruction backwards
(gdb) rsi
(gdb) reverse-nexti          # Next instruction backwards
(gdb) rni

# Reverse finish
(gdb) reverse-finish         # Reverse until function entry

# Set reverse breakpoints
(gdb) break main
(gdb) reverse-continue       # Will stop at previous hit

# Recording information
(gdb) info record
(gdb) record stop            # Stop recording
(gdb) record save filename   # Save recording to file
(gdb) record restore filename # Restore recording from file

Scripting and Automation

GDB Commands and Scripts

bash
# Define custom commands
(gdb) define mycommand
Type commands for definition of "mycommand".
End with a line saying just "end".
>print "Custom command executed"
>info registers
>end

# Command with arguments
(gdb) define print_array
Type commands for definition of "print_array".
End with a line saying just "end".
>print *$arg0@$arg1
>end
# Usage: print_array array 10

# Conditional commands
(gdb) define check_value
>if $arg0 > 100
>  print "Value is large"
>else
>  print "Value is small"
>end
>end

# Loop commands
(gdb) define print_range
>set $i = $arg0
>while $i <= $arg1
>  print $i
>  set $i = $i + 1
>end
>end

# Save commands to file
(gdb) set logging file commands.gdb
(gdb) set logging on
(gdb) show commands
(gdb) set logging off

# Execute commands from file
(gdb) source commands.gdb

Python Scripting

bash
# Enable Python in GDB
(gdb) python print("Hello from Python")

# Python script example
(gdb) python
>import gdb
>class MyCommand(gdb.Command):
>    def __init__(self):
>        super().__init__("mypy", gdb.COMMAND_USER)
>    def invoke(self, arg, from_tty):
>        print(f"Argument: {arg}")
>        frame = gdb.selected_frame()
>        print(f"Function: {frame.name()}")
>MyCommand()
>end

# Load Python script
(gdb) source script.py

# Python pretty printers
(gdb) python
>import gdb.printing
>class MyPrinter:
>    def __init__(self, val):
>        self.val = val
>    def to_string(self):
>        return f"MyStruct({self.val['x']}, {self.val['y']})"
>def my_printer_lookup(val):
>    if str(val.type) == "struct MyStruct":
>        return MyPrinter(val)
>    return None
>gdb.printing.register_pretty_printer(None, my_printer_lookup)
>end

# Convenience functions in Python
(gdb) python
>class MyFunction(gdb.Function):
>    def __init__(self):
>        super().__init__("myfunc")
>    def invoke(self, arg):
>        return int(arg) * 2
>MyFunction()
>end
# Usage: print $myfunc(5)

Debugging Automation

bash
# Automatic commands on breakpoint
(gdb) break main
(gdb) commands 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>silent
>printf "main called with argc=%d\n", argc
>continue
>end

# Hook commands (execute before/after other commands)
(gdb) define hook-stop
>info registers
>x/5i $pc
>end

(gdb) define hookpost-step
>print "Step completed"
>end

# Batch mode execution
gdb --batch \
    --ex "file program" \
    --ex "break main" \
    --ex "run" \
    --ex "bt" \
    --ex "quit"

# Automated testing script
cat > test_debug.gdb << 'EOF'
file program
break main
run arg1 arg2
print argc
print argv[0]
continue
break function_name
continue
print local_var
bt
quit
EOF

gdb -x test_debug.gdb

Specialized Debugging

Memory Debugging

bash
# Detect memory corruption
(gdb) set environment MALLOC_CHECK_=2

# Use AddressSanitizer with GDB
# Compile with: gcc -g -fsanitize=address program.c
(gdb) set environment ASAN_OPTIONS=abort_on_error=1

# Memory mapping information
(gdb) info proc mappings
(gdb) info files

# Heap analysis
(gdb) info heap              # If available
(gdb) heap                   # Custom command if defined

# Memory leak detection
(gdb) set environment MALLOC_TRACE=mtrace.log
# After program execution:
# mtrace program mtrace.log

Kernel Debugging

bash
# Kernel debugging with QEMU
qemu-system-x86_64 -kernel bzImage -s -S

# Connect GDB to kernel
(gdb) target remote :1234
(gdb) symbol-file vmlinux

# Load kernel modules
(gdb) add-symbol-file module.ko 0xaddress

# Kernel-specific commands
(gdb) info threads           # Show kernel threads
(gdb) thread apply all bt    # Backtrace all threads

# KGDB (kernel debugger)
# Enable in kernel config: CONFIG_KGDB=y
# Boot with: kgdboc=ttyS0,115200 kgdbwait

Embedded Systems Debugging

bash
# OpenOCD integration
# Start OpenOCD with appropriate config
openocd -f board/stm32f4discovery.cfg

# Connect GDB to OpenOCD
(gdb) target remote :3333
(gdb) monitor reset halt
(gdb) load                   # Load program to target
(gdb) monitor reset init

# ARM-specific commands
(gdb) info registers         # Show ARM registers
(gdb) info all-registers     # Include system registers

# Flash programming
(gdb) monitor flash write_image erase program.elf
(gdb) monitor flash verify_image program.elf

# Real-time debugging
(gdb) monitor poll off       # Disable polling
(gdb) monitor poll on        # Enable polling

GDB's comprehensive feature set and extensibility make it an indispensable tool for software development and debugging across a wide range of platforms and applications. From simple program debugging to complex multi-threaded applications, kernel development, and embedded systems, GDB provides the depth and flexibility needed to diagnose and resolve even the most challenging software issues. Its command-line interface, while requiring a learning curve, offers unmatched power and precision for developers who invest the time to master its capabilities.