gdbDebugger

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
SymptomTypical Cause
SIGSEGV at address 0x0NULL pointer dereference
SIGSEGV near random addressUse-after-free
Crash in malloc or freeHeap corruption
Stack smash detectionBuffer 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 → hex
  • d → decimal
  • s → string
  • i → 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 pointer
  • rsp → stack pointer
  • rdi, 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:

  1. Reconstruct context from incomplete evidence
  2. Infer temporal order from static snapshots
  3. 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.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *