Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

Finding a crash with gdb

After this lesson: I can find the line where a program crashes with a debugger.

55 min lesson8 commandsCompilers and computer architecture lab: gcc, flex, bison and RISC-V in one VM

A debugger shows the line that crashed

A debugger such as gdb runs your program under its control. You can stop it, look at its variables and see which line crashed it. Reading a crash this way is faster than adding printf lines and guessing.

A program prints Segmentation fault and nothing else. gdb tells you the line, the function and the call that led there.

By the end of this lesson

Note

I can find the line where a program crashes with a debugger.

Key words

WordWhat it meansExample
Debuggera tool that runs a program under your controlgdb
Debug symbolsextra information that lets a debugger name lines and variablesgcc -g
Signala message the system sends to stop or warn a processSIGSEGV
Segmentation faulta crash from using memory the program may not use
Backtracethe list of function calls that led to a point
Breakpointa place where the debugger stops the program

The cells students fill in are left blank in this preview.

A segmentation fault is a bad memory access

A segmentation fault happens when a program reads or writes memory it is not allowed to use. The system stops it with the signal SIGSEGV.

The usual cause is a pointer that holds NULL, or an address that is wrong. The program below does exactly that, by writing through a NULL pointer.

A function that writes through NULL

Code: c
#include <stdio.h>

void fill(int *slot) {
  *slot = 5;      // crashes when slot is NULL
}

int main(void) {
  int *p = NULL;
  fill(p);
  printf("done\n");   // never reached
  return 0;
}

Write the crashing program to a file

Command
printf '%s\n' '#include <stdio.h>' 'void fill(int *slot) {' '  *slot = 5;' '}' 'int main(void) {' '  int *p = NULL;' '  fill(p);' '  printf("done\n");' '  return 0;' '}' > crash.c

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Build it with debug symbols

Command
gcc -g -Wall -o crash crash.c

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Run it and print the exit status

Command
bash -c './crash; echo "status $?"'

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

A backtrace lists the calls to the crash

gdb can run the program and stop it when the signal arrives. The command bt, short for backtrace, then lists every function that was running, newest first.

Frame #0 is the line that crashed. Frame #1 is the function that called it, and so on out to main. The lines also show each argument's value.

How to read what gdb prints

What you seeWhat it tells you
Program received signal SIGSEGVThe kind of crash
fill (slot=0x0)The function, and its argument slot is NULL
at crash.c:3The file and the line number
#1 main () at crash.c:7The caller: main made the call on line 7

The cells students fill in are left blank in this preview.

Run it in gdb and print the backtrace

Command
gdb -batch -ex run -ex bt ./crash

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Stop in fill and print its argument

Command
gdb -batch -ex "break fill" -ex run -ex "print slot" ./crash

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

A common mistake

Warning

Many people think the line gdb shows is the line with the bug. It is the line where the program fell over. Here the crash is in fill, but main passed the NULL, so look at frame 1 as well.

A breakpoint stops the program where you choose

A crash is not the only time to look. A breakpoint stops the program before a chosen line runs. Then print shows a variable, and continue runs on to the next stop.

The table shows what a loop that adds ten times a number looks like when stopped at its body each time.

Worked example: stops inside a loop

Stopitotal, before the line runs
110
2210
3330
4460

The cells students fill in are left blank in this preview.

Write a loop program to a file

Command
printf '%s\n' '#include <stdio.h>' 'int main(void) {' '  int total = 0;' '  for (int i = 1; i <= 4; i++) {' '    total = total + i * 10;' '  }' '  printf("total %d\n", total);' '  return 0;' '}' > sum.c

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Build the loop with debug symbols

Command
gcc -g -Wall -o sum sum.c

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Stop twice in the loop and print

Command
gdb -batch -ex "break 5" -ex run -ex "print total" -ex continue -ex "print total" -ex "print i" ./sum

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

About this lab and its source: Compilers and computer architecture lab: gcc, flex, bison and RISC-V in one VM

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.