Docs
Debugging
Debugging with GDB
Overview
GDB (GNU Debugger) is a powerful command-line debugger for C/C++ programs. It allows you to inspect program state, set breakpoints, step through code, and find bugs.
Learning Objectives
By the end of this section, you will understand:
- •Starting and running programs in GDB
- •Setting breakpoints and watchpoints
- •Stepping through code
- •Inspecting variables and memory
- •Debugging crashes and core dumps
- •Using GDB with multi-threaded programs
Compilation for Debugging
┌─────────────────────────────────────────────────────────────────────────┐
│ COMPILE WITH DEBUG SYMBOLS │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ # Basic compilation with debug symbols │
│ g++ -g program.cpp -o program │
│ │
│ # Recommended flags for debugging │
│ g++ -g -O0 -Wall -Wextra program.cpp -o program │
│ │
│ # With CMake │
│ cmake -DCMAKE_BUILD_TYPE=Debug .. │
│ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ -g : Include debug symbols │ │
│ │ -O0 : Disable optimizations (easier to debug) │ │
│ │ -ggdb : Include extra GDB-specific info │ │
│ │ -g3 : Maximum debug info (includes macros) │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Starting GDB
┌─────────────────────────────────────────────────────────────────────────┐
│ STARTING GDB │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ # Start GDB with a program │
│ gdb ./program │
│ │
│ # Start with arguments │
│ gdb --args ./program arg1 arg2 │
│ │
│ # Attach to running process │
│ gdb -p <pid> │
│ │
│ # Debug a core dump │
│ gdb ./program core │
│ │
│ # Start in TUI mode (text user interface) │
│ gdb -tui ./program │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Essential GDB Commands
Running and Execution
┌─────────────────────────────────────────────────────────────────────────┐
│ EXECUTION COMMANDS │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Command Short Description │
│ ───────────────────────────────────────────────────────── │
│ run [args] r Start program (with optional args) │
│ continue c Continue after breakpoint │
│ next n Step over (don't enter functions) │
│ step s Step into (enter functions) │
│ finish fin Run until current function returns │
│ until [location] u Run until line or location │
│ kill Kill running program │
│ quit q Exit GDB │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Breakpoints
┌─────────────────────────────────────────────────────────────────────────┐
│ BREAKPOINT COMMANDS │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ # Set breakpoints │
│ break main # At function │
│ break file.cpp:42 # At line in file │
│ break 42 # At line in current file │
│ break *0x401234 # At address │
│ │
│ # Conditional breakpoints │
│ break 42 if x > 10 # Break only if condition true │
│ │
│ # Manage breakpoints │
│ info breakpoints # List all breakpoints │
│ delete 1 # Delete breakpoint #1 │
│ delete # Delete all breakpoints │
│ disable 1 # Disable breakpoint #1 │
│ enable 1 # Enable breakpoint #1 │
│ │
│ # Temporary breakpoint (auto-delete after hit) │
│ tbreak main │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Watchpoints
┌─────────────────────────────────────────────────────────────────────────┐
│ WATCHPOINTS (Data Breakpoints) │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ # Break when variable changes │
│ watch x # Break when x changes │
│ watch *0x601050 # Watch memory address │
│ │
│ # Break when expression becomes true │
│ watch x == 10 │
│ │
│ # Read watchpoint (break on read) │
│ rwatch x │
│ │
│ # Access watchpoint (break on read or write) │
│ awatch x │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Inspecting Variables
┌─────────────────────────────────────────────────────────────────────────┐
│ INSPECTION COMMANDS │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ # Print variables │
│ print x p x Print variable x │
│ print/x x Print as hex │
│ print/d x Print as decimal │
│ print/t x Print as binary │
│ print *ptr Print dereferenced pointer │
│ print arr[0]@10 Print 10 elements of array │
│ print (int*)0x601050 Print with cast │
│ │
│ # Display (auto-print on each step) │
│ display x Show x after each step │
│ undisplay 1 Remove display #1 │
│ info display List displays │
│ │
│ # Examine memory │
│ x/10xb &var # 10 bytes in hex │
│ x/4xw &var # 4 words in hex │
│ x/s str # As string │
│ x/i $pc # As instruction │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Stack Inspection
┌─────────────────────────────────────────────────────────────────────────┐
│ STACK COMMANDS │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ backtrace bt Show call stack │
│ backtrace full bt f Stack with local variables │
│ frame 2 f 2 Select stack frame #2 │
│ up Move up one frame │
│ down Move down one frame │
│ info frame Info about current frame │
│ info locals Show local variables │
│ info args Show function arguments │
│ │
│ Example backtrace: │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ #0 crash_func (x=42) at bug.cpp:10 │ │
│ │ #1 process (data=0x7fff...) at bug.cpp:25 │ │
│ │ #2 main (argc=1, argv=0x7fff...) at bug.cpp:40 │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Source Code Navigation
┌─────────────────────────────────────────────────────────────────────────┐
│ SOURCE CODE COMMANDS │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ list l List source around current line │
│ list 20 List around line 20 │
│ list func List function │
│ list file.cpp:1 List from file │
│ list - List previous │
│ set listsize 20 Set lines to show │
│ │
│ info source Current source file info │
│ info sources All source files │
│ info functions All functions │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Debugging Workflow
┌─────────────────────────────────────────────────────────────────────────┐
│ TYPICAL DEBUGGING SESSION │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ │
│ │ Compile -g │ │
│ └────────┬─────────┘ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ gdb ./program │ │
│ └────────┬─────────┘ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ Set breakpoints │ break main │
│ └────────┬─────────┘ break suspect_function │
│ ▼ │
│ ┌──────────────────┐ │
│ │ run │ │
│ └────────┬─────────┘ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ Inspect & step │ print var, next, step │
│ └────────┬─────────┘ backtrace, info locals │
│ ▼ │
│ ┌──────────────────┐ │
│ │ Find the bug │ │
│ └────────┬─────────┘ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ Fix & retry │ │
│ └──────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Debugging Common Issues
Segmentation Fault
┌─────────────────────────────────────────────────────────────────────────┐
│ DEBUGGING SEGFAULT │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ $ gdb ./program │
│ (gdb) run │
│ Program received signal SIGSEGV, Segmentation fault. │
│ 0x0000000000401234 in crash_func (ptr=0x0) at bug.cpp:10 │
│ │
│ (gdb) backtrace │
│ #0 crash_func (ptr=0x0) at bug.cpp:10 │
│ #1 main () at bug.cpp:20 │
│ │
│ (gdb) frame 0 │
│ (gdb) list │
│ 10 return *ptr; <-- Dereferencing null pointer! │
│ │
│ (gdb) print ptr │
│ $1 = (int *) 0x0 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Core Dump Analysis
┌─────────────────────────────────────────────────────────────────────────┐
│ CORE DUMP ANALYSIS │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ # Enable core dumps │
│ ulimit -c unlimited │
│ │
│ # Run program (crashes and creates core file) │
│ ./program │
│ Segmentation fault (core dumped) │
│ │
│ # Analyze core dump │
│ gdb ./program core │
│ (gdb) backtrace │
│ (gdb) info registers │
│ (gdb) x/10i $pc │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Memory Issues
┌─────────────────────────────────────────────────────────────────────────┐
│ MEMORY DEBUGGING │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ # Detect memory leaks with Valgrind │
│ valgrind --leak-check=full ./program │
│ │
│ # Address Sanitizer (compile-time) │
│ g++ -fsanitize=address -g program.cpp -o program │
│ ./program │
│ │
│ # GDB memory commands │
│ (gdb) info proc mappings # Show memory maps │
│ (gdb) x/100xb &buffer # Examine buffer contents │
│ (gdb) find &arr, +1000, 42 # Find value in memory │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Multi-threaded Debugging
┌─────────────────────────────────────────────────────────────────────────┐
│ THREADING COMMANDS │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ info threads # List all threads │
│ thread 2 # Switch to thread 2 │
│ thread apply all bt # Backtrace all threads │
│ thread apply 1-3 print x # Apply command to threads 1-3 │
│ │
│ # Set scheduler locking │
│ set scheduler-locking on # Only current thread runs │
│ set scheduler-locking step # Lock during step │
│ set scheduler-locking off # All threads run │
│ │
│ # Break in specific thread │
│ break file.cpp:10 thread 2 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
TUI Mode (Text User Interface)
┌─────────────────────────────────────────────────────────────────────────┐
│ TUI MODE COMMANDS │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ # Start in TUI mode │
│ gdb -tui ./program │
│ │
│ # Toggle TUI in GDB │
│ Ctrl-x a # Toggle TUI │
│ Ctrl-x 1 # One window (source) │
│ Ctrl-x 2 # Two windows (source + asm) │
│ Ctrl-L # Refresh display │
│ │
│ # Layout commands │
│ layout src # Source window │
│ layout asm # Assembly window │
│ layout split # Source and assembly │
│ layout regs # Registers window │
│ │
│ # Focus commands │
│ focus src # Focus on source │
│ focus cmd # Focus on command line │
│ │
└─────────────────────────────────────────────────────────────────────────┘
GDB Init File
┌─────────────────────────────────────────────────────────────────────────┐
│ ~/.gdbinit FILE │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ # ~/.gdbinit - Loaded automatically when GDB starts │
│ │
│ # Better display │
│ set print pretty on │
│ set print array on │
│ set print object on │
│ set print static-members on │
│ set print vtbl on │
│ │
│ # History │
│ set history save on │
│ set history size 10000 │
│ set history filename ~/.gdb_history │
│ │
│ # Pagination │
│ set pagination off │
│ │
│ # Custom commands │
│ define bpl │
│ info breakpoints │
│ end │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Quick Reference
| Action | Command |
|---|---|
| Start debugging | gdb ./program |
| Run program | run or r |
| Set breakpoint | break main or b main |
| Continue | continue or c |
| Step over | next or n |
| Step into | step or s |
| Print variable | print x or p x |
| Show backtrace | backtrace or bt |
| List source | list or l |
| Quit | quit or q |
Next Steps
- •Practice with
examples.cpp - •Complete the
exercises.cppchallenges - •Try debugging real programs with bugs
- •Explore LLDB as an alternative debugger