Site Tools


wiki:gcc-debugging

Table of Contents

GCC Debugging

Debug symbols (-g flag) embed source file names, line numbers, and variable information into the binary. GDB uses these to map machine instructions back to source code.

gcc -g -o app app.c                 # include debug symbols
gcc -g -O0 -o app app.c             # debug build (no optimization)
gcc -g -O3 -o app app.c             # optimized with debug symbols (can work)

Always use -g when compiling for debugging. The flag doesn't increase runtime overhead—it only adds metadata to the binary. You can remove it later with strip.

Debug symbols and optimization: At -O0, line numbers and variable locations are precise. At -O3, the compiler reorders code and optimizes variables away, so line number attribution becomes approximate. For serious debugging, use -O0 -g. For production debugging of optimized code, accept that stepping through source may jump around unexpectedly.

DWARF versions: -gdwarf-4 (default on GCC 10+) uses DWARF version 4. Older tools may need -gdwarf-3. Unless you have compatibility issues, use the default.

Separate debug symbols:

gcc -g -o app app.c
objcopy --only-keep-debug app app.debug
objcopy --strip-debug app app_stripped
objcopy --add-gnu-debuglink=app.debug app_stripped

This separates debug info from the binary, reducing binary size while keeping debuggability. The app.debug file can be stored separately.

Testing with gdb:

gcc -g -O0 -o app app.c
gdb ./app
(gdb) break main
(gdb) run
(gdb) next
(gdb) print variable_name

With debug symbols, gdb shows function names, file names, line numbers, and can print variable values. Without -g, you only get memory addresses and registers.

Core dumps: When a program crashes, the OS can save a core dump (memory snapshot). Debug with it using gdb:

ulimit -c unlimited              # enable core dumps
./app                            # program crashes, produces core
gdb ./app ./core                 # debug the core dump
(gdb) bt                         # backtrace: where did it crash?
(gdb) print variable_at_crash

Core dumps let you debug crashes that happened earlier, without re-running the program.

Address Sanitizer: Detect memory errors at runtime (similar to Valgrind but faster):

gcc -fsanitize=address -g -O1 -o app app.c
./app  # reports memory errors: use-after-free, buffer overflow, etc.

-fsanitize=address adds instrumentation to catch memory bugs. It's slower than native execution but faster than Valgrind. -O1 is recommended (optimizations make debugging harder, but -O0 adds more overhead).

wiki/gcc-debugging.md · Last modified: by 127.0.0.1