SrcForge

Lesson 31

Debugging with GDB

GDB (GNU Debugger) is a command-line debugging tool that allows you to pause a program, inspect variables, execute code one line at a time, examine memory, analyze crashes, and understand how your program behaves during execution. It is an essential tool for C programmers working on Linux applications, embedded systems, device drivers, and any project where printf() debugging is insufficient.

C Track

Save progress as you learn.

44 lessons

Lesson content

Debugging with GDB in C Programming: A Complete Beginner to Advanced Guide

What is GDB in C Programming?

Finding and fixing bugs is one of the most important skills for every C programmer. While printf() debugging works for small programs, it quickly becomes difficult as projects grow larger. This is where GDB (GNU Debugger) becomes an essential tool.

GDB (GNU Debugger) is a command-line debugging tool that allows you to pause a program, inspect variables, execute code one line at a time, examine memory, analyze crashes, and understand how your program behaves during execution.

Think of GDB as a pause-and-rewind remote control for your program. Instead of guessing where a bug is, you can stop execution at any point and inspect everything happening inside the program.

Why Does GDB Exist?

Without GDB, bugs are difficult to locate, developers rely on numerous printf() statements, crashes are hard to diagnose, and understanding program flow becomes challenging. With GDB, you can pause execution at any line, inspect variables and memory, step through code line by line, analyze segmentation faults, and debug complex applications efficiently.

Real-World Use Cases

GDB is widely used in:

  • Linux application development
  • Embedded systems
  • Operating system development
  • Device driver debugging
  • Open-source C/C++ projects
  • Network programming
  • High-performance computing

Prerequisites

Before learning Debugging with GDB in C programming, you should understand:

  • Basic C programming
  • Functions
  • Variables and data types
  • Pointers
  • Arrays
  • Command-line basics
  • GCC compilation

Core Concepts

What is GDB?

GDB is the GNU Debugger that lets you start a program under debugger control, pause execution, inspect and modify variable values, execute one line at a time, analyze crashes, and view the call stack.

Compiling with Debug Symbols

Always compile with the -g flag so GDB can map machine code back to your source code.

gcc -g -O0 -Wall -Wextra main.c -o main
OptionPurpose
`-g`Include debug symbols
`-O0`Disable optimization for easier debugging
`-Wall`Enable common warnings
`-Wextra`Enable additional warnings

Starting GDB

gdb ./main
run

Breakpoints

A breakpoint tells GDB where to pause execution.

break main
break 25
info breakpoints
delete 1

Stepping Through Code

CommandPurpose
`next`Execute current line without entering functions
`step`Execute current line and enter functions
`continue`Resume execution until next breakpoint
`finish`Run until current function returns

Viewing Variables

print count
display count
info locals

Examining Memory

print ptr
x/10x ptr

Call Stack

backtrace

Watchpoints

A watchpoint pauses execution when a variable changes.

watch total

Code Examples

Example 1: Beginner – Debugging a Simple Program

#include <stdio.h>              // Include standard input/output library

int main()                      // Program entry point
{
    int number = 10;            // Initialize variable

    printf("%d\n", number);     // Print value

    return 0;                   // Exit successfully
}
gcc -g simple.c -o simple
gdb ./simple
break main
run
next
print number
continue

Example 2: Intermediate – Finding a Logic Bug

#include <stdio.h>                  // Include standard I/O library

int main()                          // Program entry point
{
    int sum = 0;                    // Initialize sum

    for (int i = 1; i <= 5; i++)    // Loop from 1 to 5
    {
        sum = i;                    // Bug: overwrites sum instead of accumulating
    }

    printf("%d\n", sum);            // Print result

    return 0;                       // Exit program
}
break 8
run
display sum
next

Example 3: Intermediate – Debugging a Segmentation Fault

#include <stdio.h>                  // Standard I/O library

int main()                          // Program entry point
{
    int *ptr = NULL;                // Null pointer

    *ptr = 100;                     // Causes segmentation fault

    return 0;                       // Exit program
}
gcc -g crash.c -o crash
gdb ./crash
run
backtrace
print ptr

Example 4: Advanced – Debugging Functions

#include <stdio.h>                  // Standard I/O library

int square(int x)                   // Function to compute square
{
    return x * x;                   // Return square
}

int main()                          // Program entry point
{
    int result = square(5);         // Call function

    printf("%d\n", result);         // Print result

    return 0;                       // Exit program
}
break square
run
step
print x
finish

Example 5: Advanced – Tracking Variable Changes with Watchpoints

#include <stdio.h>                  // Standard I/O library

int main()                          // Program entry point
{
    int counter = 0;                // Initialize counter

    for(int i = 0; i < 5; i++)      // Loop five times
    {
        counter += i;               // Update counter
    }

    printf("%d\n", counter);        // Print result

    return 0;                       // Exit program
}
watch counter
run
continue

Common Mistakes and Pitfalls

WrongCorrect
Compiling without -gCompile using gcc -g
Using optimized builds while debuggingUse -O0 for easier debugging
Depending only on printf()Use breakpoints and variable inspection
Forgetting to remove old breakpointsUse delete or clear
Ignoring the call stack after crashesAlways check backtrace

Wrong:

gcc main.c -o main

Correct:

gcc -g -O0 -Wall -Wextra main.c -o main

Best Practices

  • Compile with -g -O0 while debugging.
  • Enable compiler warnings with -Wall -Wextra.
  • Use breakpoints instead of excessive printf() statements.
  • Inspect variables frequently using print and display.
  • Use watchpoints to track unexpected changes.
  • Analyze crashes with backtrace.
  • Debug one issue at a time.
  • Remove temporary breakpoints when finished.
  • Learn GDB keyboard shortcuts to improve productivity.
  • Combine GDB with tools like AddressSanitizer and Valgrind for memory-related bugs.

When NOT to Use This

While GDB is powerful, it may not be the best choice when:

  • You only need quick logging output.
  • Debugging timing-sensitive code where breakpoints alter behaviour.
  • Working with highly optimized release binaries where variables may be optimized away.
  • Performing performance profiling, where specialized profilers are better suited.

Summary / Key Takeaways

  • GDB is the standard debugger for C and C++ programs.
  • Always compile with -g and preferably -O0.
  • Breakpoints pause execution at specific locations.
  • step enters functions, while next executes the current line without entering functions.
  • Use print, display, and info locals to inspect variables.
  • Watchpoints detect when variables change.
  • backtrace helps identify the source of crashes.
  • GDB significantly reduces debugging time compared to relying solely on printf().

FAQ About Debugging with GDB in C

1. What is GDB in C programming?

GDB (GNU Debugger) is a tool that allows developers to run, pause, inspect, and debug C programs interactively.

2. Why should I compile with -g?

The -g option includes debugging symbols so GDB can display source code, variable names, and line numbers instead of only machine instructions.

3. What is the difference between step and next?

step executes the current line and enters called functions. next executes the current line but skips over function calls.

4. What is a breakpoint?

A breakpoint is a marker that tells GDB to pause program execution at a specific line or function so you can inspect the program's state.

5. Can GDB fix bugs automatically?

No. GDB helps you identify and understand bugs, but it is the programmer's responsibility to modify the source code and correct the issue.

Prev: MakefilesBack to hub