Debugging a Memory Dump with GDB
1. What a “memory dump” actually is
Before touching gdb, it’s critical to understand what you are debugging.
A memory dump (often called a core dump) is a snapshot of a process’s virtual address space at a specific moment—usually when it crashes (e.g., segmentation fault, abort). The operating system writes this snapshot to disk so that you can inspect the exact state of the program after the fact.
A core dump typically contains:
- The memory mappings (stack, heap, shared libraries, etc.)
- CPU register state for all threads
- The call stacks
- Values of variables as they existed at crash time
- Signal information (SIGSEGV, SIGABRT, etc.)
📌 Key idea:
You are not running the program. You are post-mortem debugging a frozen corpse.
2. When and why memory dumps are useful
Memory dumps are especially valuable when:
- The crash happens in production
- The bug is timing-dependent or hard to reproduce
- Interactive debugging is impossible
- You need to reconstruct how execution reached the failure
In real-world Unix systems, this often happens in:
- Long-running daemons
- Low-level C/C++ services
- Kernel-adjacent or performance-critical software
3. Preparing for meaningful debugging
3.1 You must have the correct binary
GDB needs the exact executable that produced the core dump:
$ file core.1234
core.1234: ELF 64-bit LSB core file x86-64, from ‘myapp’
$ gdb /path/to/myapp core.1234
If the binary doesn’t match:
- Function names may be wrong
- Line numbers meaningless
- Stack frames unusable
3.2 Debug symbols matter
Without debug symbols, gdb becomes a blunt instrument.
gcc -g -O0 myapp.c -o myapp
Symbols allow:
- Source lines (
list) - Variable names (
print) - Struct inspection
Stripped binaries severely limit analysis.
4. Your first steps inside GDB
When you open the core file, GDB immediately restores the crash context:
Program terminated with signal SIGSEGV, Segmentation fault.
4.1 Inspect the backtrace
This is always step one:
(gdb) bt
This shows:
- The call stack at crash time
- Function arguments
- Local variables (if symbols exist)
Example:
#0 strcpy () from /lib/x86_64-linux-gnu/libc.so.6
#1 process_input (buf=0x0) at main.c:42
#2 main () at main.c:88
The top frame is where it crashed.
The lower frames explain why.
5. Examining stack frames
Navigate frames like a historian retracing events:
(gdb) frame 1
(gdb) info locals
(gdb) info args
This lets you inspect:
- Corrupted pointers
- Unexpected values
- Invalid arguments passed deeper into the call stack
You are reconstructing logical causality, not just reading code.
6. Understanding memory-related failures
6.1 Common crash patterns
| Symptom | Typical Cause |
|---|---|
SIGSEGV at address 0x0 | NULL pointer dereference |
| SIGSEGV near random address | Use-after-free |
Crash in malloc or free | Heap corruption |
| Stack smash detection | Buffer overflow |
Inspect addresses carefully:
(gdb) print ptr
(gdb) x/16x ptr
Show more lines
6.2 Examining memory directly
GDB allows raw memory inspection:
Plain Text
gdb isn’t fully supported. Syntax highlighting is based on Plain Text.
(gdb) x/32xb buffer
(gdb) x/10gx heap_ptr
Format letters tell gdb how to interpret memory:
x→ hexd→ decimals→ stringi→ instruction disassembly
This is essential when debugging corrupted structures.
7. The role of threads
Modern programs are rarely single-threaded.
List threads:
(gdb) info threads
Switch threads:
(gdb) thread 3
(gdb) bt
Often:
- The crashing thread is a victim
- Another thread performed the corruption earlier
This is a crucial mental shift for concurrent debugging.
8. Registers and low-level clues
Inspect CPU state:
(gdb) info registers
Registers can tell you:
- Which pointer was invalid
- Whether the instruction pointer jumped incorrectly
- If the stack pointer is corrupted
On x86-64:
rip→ instruction pointerrsp→ stack pointerrdi,rsi, etc. → function arguments
9. Limitations of core dump debugging
As an instructor, I must emphasize the constraints:
- You cannot continue execution
- You cannot step forward
- You only see the final state
This is why good engineers combine:
- Core dumps
- Logging
- Sanitizers (ASan, UBSan)
- Reproducer test cases
Core dumps answer “What state caused the crash?”
They do not automatically explain “How the state was created.”
10. Final advice
Think of core dump debugging as forensics, not surgery.
You must:
- Reconstruct context from incomplete evidence
- Infer temporal order from static snapshots
- Use systems knowledge (ABI, memory layout, calling conventions)
If you approach GDB expecting a magic button, you’ll be disappointed.
If you approach it like a detective, it becomes one of the most powerful diagnostic tools in Unix.
Leave a Reply