This guide explains how to use GDB for proactive debugging, particularly focusing on debugging segfaults and other issues in the verbose_minunit implementation.
First, ensure your Makefile includes debug symbols:
CC = gcc
CFLAGS = -Wall -Wextra -I. -g -O0
LDFLAGS = -lmThe -g flag includes debug symbols, and -O0 disables optimizations for easier debugging.
gdb ./verbose_minunit_example- Launches GDB with your program loaded
- The
-gflag ensures debug symbols are included -O0disables optimizations for easier debugging
break main
break mu_check_verbosebreak(orb) sets a breakpoint where execution will pause- You can set breakpoints at:
- Function names
- Line numbers (e.g.,
break verbose_minunit_example.c:42) - File and line (e.g.,
break minunit_verbose.h:123)
run- Starts program execution
- Will stop at first breakpoint
- You can also run with arguments:
run arg1 arg2
next # Execute next line, stepping over function calls
step # Execute next line, stepping into function calls
continue # Continue execution until next breakpointnext(orn) is good for moving through your codestep(ors) is useful when you want to dive into a functioncontinue(orc) resumes normal execution
print variable_name
print *pointer
print array[0]@10 # Print first 10 elements of arrayprint(orp) shows variable values- Can evaluate expressions
- Can print memory contents
backtrace- Shows the call stack
- Very useful when you hit a segfault
- Shows the chain of function calls that led to the crash
x/10x pointer # Examine 10 words in hex
x/10c pointer # Examine 10 bytes as characters
x/10i pointer # Examine 10 instructionsxcommand is powerful for memory inspection- Can show memory in different formats
- Useful for finding buffer overflows
watch variable_name- Stops execution when a variable changes
- Great for tracking down where values change unexpectedly
break minunit_verbose.h:123 if count == 5- Only breaks when condition is true
- Useful for debugging loops or specific cases
frame 2 # Switch to frame 2 in backtrace
up # Move up one frame
down # Move down one frame- Helps navigate the call stack
- Useful for examining different contexts
list # Show current location
list 20,30 # Show lines 20-30
list function_name- Shows source code around current position
- Helps orient yourself in the code
When you hit a segfault:
- Use
backtraceto see where it occurred - Use
frameto move to the relevant stack frame - Use
printto examine variables - Use
xto examine memory if needed - Set breakpoints before the crash to catch it earlier
Using GDB is much more powerful than printf because:
- You can examine any variable at any time
- You can step through code line by line
- You can see the exact state when a crash occurs
- You can modify variables during execution
- You can set conditional breakpoints
- You can examine memory directly
- You can see the full call stack
Here's an example of debugging a segfault in verbose_minunit:
# Start GDB
gdb ./verbose_minunit_example
# Set breakpoint at the test function
break test_check_verbose
# Run the program
run
# When it stops at the breakpoint, step through
step
# If it crashes, examine the backtrace
backtrace
# Move to the relevant frame
frame 2
# Examine variables
print variable_name
# Continue execution
continueThis approach allows you to systematically track down issues without modifying your code with printf statements.