GDB runs a compiled executable under its control, allowing breakpoints (pausing execution at a specific line), stepping through code one line or one function call at a time, and inspecting variable values and the call stack at any paused point. This matters especially in C because the language itself gives almost no runtime diagnostic information — a segfault just terminates the program with no line number, no stack trace, and no explanation, unless a debugger was attached to capture that moment. The -g compiler flag is required beforehand, embedding the debug symbols GDB needs to map machine code back to source lines and variable names.
Compiling with debug symbols and starting GDB
Without -g, the executable still runs identically, but GDB has no way to connect machine instructions back to your original source lines or variable names — it would only show raw addresses and registers.
$ gcc -g -Wall -o myapp main.c // -g embeds debug symbols
$ gdb ./myapp
(gdb) run // starts the program under GDB's controlBreakpoints and stepping
next steps over a function call (running it to completion without descending into it); step descends INTO the called function — the distinction matters when you want to skip past code you already trust is correct.
(gdb) break main // set a breakpoint at the start of main()
(gdb) break 25 // or at a specific line number
(gdb) run
(gdb) next // execute the next line, stepping OVER function calls
(gdb) step // execute the next line, stepping INTO function calls
(gdb) print x // inspect a variable's current value
(gdb) continue // resume running until the next breakpointPost-mortem debugging: finding a crash after the fact
backtrace is often the single most useful GDB command for a real crash — it shows the exact chain of function calls that led to the failure, which is precisely the information a bare segfault message never provides on its own.
(gdb) run
Program received signal SIGSEGV, Segmentation fault.
0x0000555555555169 in processData (data=0x0) at main.c:15
15 return data->value; // data was NULL — now we know exactly where and why
(gdb) backtrace // shows the full call chain that led here
#0 processData (data=0x0) at main.c:15
#1 main () at main.c:22