The VikiD Truth

Knowledge base / Computing / C & systems languages

Readinglist | Quick Links | Algorithms | Apple | AssemblyLanguage | BASH | C-Programmming | CommonLisp | Computer Security | CuisSmalltalk | Databases | Emacs | Exploitation | Functional Programming | Firewalls | Git | GNUSmalltalk | Haskell | Javascript | Julia | Linux | Machine Learning | Metasploit |Machine Learning | Networking | Operating Systems |Open Data Science | Odin | Picolisp | Pharo Smalltalk | Purescript | Python | Racket | Scheme | Social Engineering | Unity | vim | V | Web Development | Windows WSL | Zig

Using the C Debugger

The GBD Tutorial, Online Docs

Here is the truth about debuggers: a debugger is a time machine with a pause button. Instead of guessing what your program did and sprinkling printf everywhere, you stop it at the moment that matters and look at everything: every variable, the whole call stack, even the CPU registers. GDB, the GNU Debugger, is that time machine for C (and C++, Rust, Zig, Go, Fortran and assembly).

What it is, in plain words

GDB was written by Richard Stallman in 1986 and is still actively developed (the 16.x series is current in 2026). It runs your program under its control using the kernel’s ptrace interface, and uses the debug information that gcc -g puts into the binary (in DWARF format) to map machine addresses back to your source lines and variable names.

The core loop is always the same:

  1. Stop – with a breakpoint (stop at this line or function), a watchpoint (stop when this variable changes) or a catchpoint (stop on a signal, exception or system call). Or the program stops itself by crashing.
  2. Look – print variables, backtrace the stack, info locals, x to examine raw memory.
  3. Move – next (step over calls), step (step into calls), finish (run until this function returns), continue.
  4. Change – set var x = 5 and carry on to test a theory without recompiling.

Why it matters

An everyday analogy: a video replay referee

In a football match you see a blur and argue about whether it was a foul. The video referee pauses the replay, steps forward frame by frame, zooms in on the boot and checks the angle from another camera. GDB is the replay booth for your program. You do not argue about what happened; you look.

A hands-on example: find the bug in 60 seconds

/* buggy.c */
#include <stdio.h>
#include <string.h>

int count_vowels(const char *s) {
    int n = 0;
    for (size_t i = 0; i <= strlen(s); i++)      /* bug: <= */
        if (strchr("aeiou", s[i])) n++;
    return n;
}

int main(void) {
    printf("%d\n", count_vowels("vikix"));      /* expect 2 */
}

It prints 3. Why?

gcc -g -O0 buggy.c -o buggy
gdb -q ./buggy
(gdb) break count_vowels
(gdb) run
(gdb) display i
(gdb) display s[i]
(gdb) next            # press Enter to repeat; watch i and s[i]
...
1: i = 5
2: s[i] = 0 '\000'
(gdb) print strchr("aeiou", 0)

At i = 5, s[i] is the terminating zero byte, and strchr counts the string’s own terminator as a match. The loop should be i < strlen(s). Found by looking, not guessing.

Habits that pay off:

gdb -tui ./buggy                  # split screen: source above, commands below
ulimit -c unlimited               # allow core dumps, then after a crash:
gdb ./buggy core                  # post-mortem: 'bt' shows where it died
gdb -batch -ex run -ex bt ./buggy # run and print a backtrace, non-interactive

Put settings in ~/.gdbinit, for example set history save on and set print pretty on. Inside Emacs, M-x gdb gives a multi-window IDE-style debugger; see Emacs Notes.

Common misconceptions

Connections

GDB command reference

Common Commands














Last edited · 14 revisions

Tags: #Computing