gdb Command: Tutorial & Examples

Debug and inspect programs from the command line

The gdb command is the GNU Debugger, a powerful and versatile tool used to debug programs on Linux systems. It enables developers and system administrators to pause program execution, inspect variables, analyze program flow, and identify the causes of crashes or unexpected behavior. This article explains how gdb works, its importance in software development, common usage patterns, and advanced features, providing detailed examples and best practices for effective debugging.

What the gdb Command Does

The gdb command launches the GNU Debugger, which allows you to control the execution of programs written in languages such as C, C++, Rust, and Go. Using gdb, you can run your program step-by-step, set breakpoints to pause execution at specific locations, inspect and modify variables, examine call stacks, and debug multi-threaded applications. It also supports debugging of programs post-mortem using core dumps.

How the gdb Command Works

gdb works by attaching to a program process or loading an executable file and controlling its execution through debugging symbols embedded in the program. When started, gdb loads the executable and its debugging information (usually compiled with the -g flag). It then allows the user to interactively control the program's execution via a command-line interface, providing commands to inspect the internal state, control flow, and memory.

Internally, gdb uses operating system interfaces such as ptrace to control the target program, pause it, and read or modify its memory and registers. This low-level control enables precise inspection and manipulation of program execution.

Importance of the gdb Command

Debugging is a fundamental activity in software development and system administration, crucial for identifying and resolving software bugs, crashes, memory leaks, and unexpected behavior. Without a debugger like gdb, diagnosing such issues can be extremely difficult and time-consuming.

gdb empowers developers to:

  • Understand program flow and logic
  • Identify the location and cause of crashes
  • Inspect variable values and memory state at runtime
  • Analyze multi-threaded behavior and race conditions
  • Debug optimized or stripped binaries when debug symbols are available

By providing deep insights into running programs, gdb significantly reduces the time needed to locate and fix errors, improving software quality and reliability.

Installation of gdb

Most Linux distributions include gdb by default. To check if it is installed, run:

gdb --version

If it is not installed, you can install it using your distribution's package manager. For example, on Debian or Ubuntu:

sudo apt-get update
sudo apt-get install gdb

On CentOS or Fedora:

sudo dnf install gdb

Basic Usage of gdb

To start debugging a program, invoke gdb with the path to the executable file:

gdb ./myprogram

This will start gdb and load the program myprogram. Inside the gdb prompt, you can enter commands to control execution, set breakpoints, and inspect program state.

Common gdb Internal Commands

  • run
    Starts execution of the program inside gdb. You can pass arguments to your program as follows:

      run arg1 arg2
    
  • break
    Sets a breakpoint to pause execution at a specific function or line number. Examples:

      break main  
      break 42  # Break at line 42 in the current source file
    
  • next
    Executes the next line of code, stepping over function calls.

  • step
    Executes the next line of code, stepping into function calls.

  • continue
    Resumes execution until the next breakpoint or program termination.

  • print
    Displays the value of a variable or expression. Example:

      print myVar
    
  • backtrace
    Shows the call stack leading to the current execution point.

  • list
    Displays source code around the current line or a specified location.

  • quit
    Exits gdb.

Common gdb Command-Line Options

  • -tui
    Launches gdb in Text User Interface mode, providing a split-screen view with source code and registers.

  • -p <pid>
    Attaches gdb to a running process identified by its process ID.

  • -c <corefile>
    Loads a core dump file for post-mortem debugging.

Advanced Usage and Features

Debugging Core Dumps

A core dump is a snapshot of a program's memory taken when it crashes. You can debug a core dump with gdb using:

gdb ./myprogram corefile

This allows you to inspect the program state at the moment of the crash.

Multi-threaded Debugging

gdb supports debugging multi-threaded programs. You can list threads with:

info threads

Switch to a thread with:

thread <thread-number>

and control execution or inspect variables in that thread context.

Remote Debugging

gdb can connect to a remote target via gdbserver. On the target machine, start:

gdbserver :1234 ./myprogram

On the host machine, connect with:

gdb ./myprogram
target remote <target-ip>:1234

Scripting and Automation

gdb supports scripting in its own command language or Python to automate repetitive debugging tasks.

Potential Problems and Pitfalls

  • Lack of Debug Symbols
    If a program is compiled without the -g flag, gdb will not have access to debugging symbols, making inspection difficult.

  • Stripped Binaries
    Some distributions ship stripped binaries that remove symbol information to save space.

  • Complex Command Set
    The large number of gdb commands can be overwhelming for beginners; it requires practice to become proficient.

  • Permissions
    Attaching to running processes may require superuser privileges, especially for processes owned by other users.

  • Optimized Code
    Compiler optimizations can reorder or remove code, making debugging more challenging.

Common Errors and Troubleshooting

  • Cannot find source file
    Ensure the source files are accessible and correctly referenced.

  • Permission denied when attaching to process
    Run gdb as root or the same user as the target process.

  • Program terminates immediately when running
    Check for missing dependencies or runtime errors.

Tips and Best Practices

  • Always compile your programs with debugging symbols enabled (-g).

  • Use the list command frequently to view source code context.

  • Combine break with conditional expressions to pause only when certain conditions are met.

  • Use watch to monitor variable changes during execution.

  • Take advantage of gdb's logging features to save debugging sessions.

Examples Using gdb

  1. Start debugging a program named hello:

    gdb ./hello
    
  2. Set a breakpoint at the main function:

    break main
    
  3. Run the program with arguments:

    run arg1 arg2
    
  4. Print the value of a variable named counter:

    print counter
    

    Sample output:

    $1 = 42
    
  5. Step through the next line without entering functions:

    next
    
  6. View the current call stack:

    backtrace
    
  7. Exit gdb:

    quit
    

See Also

  • strace - System call tracing tool
  • valgrind - Memory debugging tool
  • make - Build automation tool (compiling with debug symbols)
  • readelf - ELF file inspection tool
  • nm - List symbols from object files
  • debugging - The process of identifying and removing errors

Further Reading

As an Amazon Associate, I earn from qualifying purchases.

The text above is licensed under CC BY-SA 4.0 CC BY SA