Core Dumps, Debug Symbols, DWARF
This chapter explains core dumps (post-mortem debugging) and the debug information (DWARF) that makes source-level debugging possible.
Why This Matters
When a program crashes in production, you often cannot run it interactively. A core dump captures the crash state so you can debug it later. DWARF is the format that ties that state back to your source code.
Prerequisites
c.debug.1— GDB/LLDB.
Core Concept
Core dumps
A core dump is a file containing a snapshot of a process's memory and registers at the moment of a crash. You load it into GDB/LLDB to inspect the crash:
ulimit -c unlimited # enable core dumps (POSIX)
./app # crashes, produces "core"
gdb ./app core
Debug symbols
-g tells the compiler to emit debug info. This does not affect code generation (at -O0); it adds sections mapping addresses to source lines, variables, and types.
DWARF
DWARF is the standard debug format. It stores:
- line table (address → source file:line);
- variable locations (which register/stack slot holds each variable);
- type information (struct layouts, sizes, members);
- call frame information (for unwinding).
Examples
Inspecting DWARF
readelf --debug-dump=info app # DWARF info (ELF)
dwarfdump app # macOS
Post-mortem debugging
(gdb) bt # backtrace at crash
(gdb) info locals
(gdb) print x
How It Works
When a fatal signal (e.g., SIGSEGV) arrives, the OS (if core dumps are enabled) writes the process's memory and register state to a core file. GDB loads the executable and core together, using DWARF to reconstruct source context.
Variations
Minidumps (Windows)
Windows uses minidumps instead of Unix core files; the concept is the same.
Separate debug files
Debug info can be stripped into a separate file (.debug/.dSYM) to keep the shipped binary small while retaining debuggability.
Common Mistakes
- Assuming
-gslows the program at run time (it does not; it only adds file
size, though it can affect inlining decisions at high optimization).
- Forgetting to enable core dumps (
ulimit -c unlimited). - Debugging a stripped binary without debug symbols.
Undefined Behavior
- None; core dumps and DWARF are tooling/OS features.
Portability
- Core dumps are POSIX-ish (Windows uses minidumps). DWARF is used by GCC/
Clang on most platforms; MSVC uses PDB.
Under the Hood
DWARF is a structured, section-based format. The line table maps every instruction address to a source line. Call frame information lets the debugger unwind the stack even without frame pointers.
Practical Usage
- Enable core dumps and set a capture location for production crashes.
- Keep debug symbols (or separate debug files) for deployed binaries.
- Use
btandinfo localson a core to diagnose crashes post-mortem.
Exercises
1. Enable core dumps, crash a program, and inspect the core with GDB. 2. Use readelf --debug-dump to find the line table and a variable's type. 3. Strip debug info into a separate file and confirm GDB still works.
Deep Challenge
Debug a crash from a core dump where the binary was optimized: reconstruct the backtrace, explain which variables are optimized out, and correlate the crash address to a source line using DWARF.
Related Concepts
c.debug.1— GDB/LLDB.c.debug.5— debugging optimized builds.c.build.8— debug flags.
References
- DWARF specification, GDB manual, OS core dump documentation.
Verification
- Core dump and DWARF behavior are platform/tool features.
PLATFORM-SPECIFIC - No example was executed during generation unless noted. `Execution not
verified.`
Progress
- [ ] Read
- [ ] Understand
- [ ] Complete examples
- [ ] Complete exercises
- [ ] Complete deep challenge
Concept checkboxes
- [ ] Core dumps
- [ ] Debug symbols (-g)
- [ ] DWARF line table
- [ ] Post-mortem debugging
Mastery levels
| Concept | Current level (0–8) | Target level |
|---|---|---|
| c.debug.core | 0 | 6 |
| c.debug.dwarf | 0 | 6 |