Project 2: The Crash - Core Dump Analysis

Build a crashing C program and perform a post-mortem GDB analysis with a core file.

Quick Reference

Attribute Value
Difficulty Beginner
Time Estimate 1-2 hours
Language GDB commands (C target)
Prerequisites Project 1, basic pointers
Key Topics SIGSEGV, core dumps, backtrace, memory inspection

1. Learning Objectives

By completing this project, you will:

  1. Enable and locate core dumps on your system.
  2. Load a core dump into GDB and identify the crash site.
  3. Inspect registers, locals, and memory at the moment of failure.
  4. Explain the root cause of a crash without re-running the program.

2. Theoretical Foundation

2.1 Core Concepts

  • Signals and SIGSEGV: A segmentation fault occurs when a process accesses invalid memory; the kernel delivers SIGSEGV and may write a core file.
  • Core Files: A snapshot of memory, registers, and process state at the time of the crash.
  • Post-mortem Debugging: You analyze a frozen state, not a running process.

2.2 Why This Matters

Many production crashes are non-reproducible. Core files are often the only evidence you get. Learning to read them is a real-world debugging superpower.

2.3 Historical Context / Background

Core dumps have existed since early Unix to help developers diagnose fatal errors after the fact. Modern systems can route them to custom paths or crash-reporting services.

2.4 Common Misconceptions

  • “Core dumps are optional”: They are essential for post-mortem debugging.
  • “You need a live process”: Core files contain enough information to pinpoint the crash.

3. Project Specification

3.1 What You Will Build

A minimal C program that dereferences a NULL pointer. You will capture a core dump and analyze it in GDB.

3.2 Functional Requirements

  1. Enable core dumps for the shell session.
  2. Reproduce a SIGSEGV and capture a core file.
  3. Use backtrace, frame, and print to identify the root cause.

3.3 Non-Functional Requirements

  • Performance: Not relevant.
  • Reliability: Crash should reproduce consistently.
  • Usability: Core file should be easy to locate.

3.4 Example Usage / Output

$ ulimit -c unlimited
$ ./crash
Segmentation fault (core dumped)
$ gdb ./crash core
(gdb) backtrace

3.5 Real World Outcome

You should see a clear GDB report of the faulting line and variable state:

$ gcc -g -O0 -o crash crash.c
$ ulimit -c unlimited
$ ./crash
Segmentation fault (core dumped)
$ gdb ./crash core
GNU gdb (GDB) 14.1
Core was generated by './crash'.
Program terminated with signal SIGSEGV, Segmentation fault.
(gdb) backtrace
#0  crash_me () at crash.c:5
#1  main () at crash.c:9
(gdb) frame 0
5           *p = 'A';
(gdb) print p
$1 = (char *) 0x0

4. Solution Architecture

4.1 High-Level Design

┌────────────┐     ┌──────────────┐     ┌──────────────┐
│  crash.c   │────▶│  core file   │────▶│  gdb session │
└────────────┘     └──────────────┘     └──────────────┘

4.2 Key Components

Component Responsibility Key Decisions
Crashing target Produce deterministic SIGSEGV Keep code minimal
Core file Snapshot crash state Ensure ulimit allows it
GDB session Analyze snapshot Use backtrace + locals

4.3 Data Structures

struct CoreFindings {
    const char *function;
    int line;
    void *fault_addr;
};

4.4 Algorithm Overview

Key Algorithm: Post-mortem analysis loop

  1. Load core file with matching binary.
  2. Identify faulting frame.
  3. Inspect variables and registers.

Complexity Analysis:

  • Time: O(F) for number of frames inspected.
  • Space: O(1) within the debugger.

5. Implementation Guide

5.1 Development Environment Setup

ulimit -c unlimited

5.2 Project Structure

project-root/
├── crash.c
├── crash
└── core (generated)

5.3 The Core Question You’re Answering

“How do I debug a crash that happened when I was not watching?”

5.4 Concepts You Must Understand First

Stop and research these before coding:

  1. SIGSEGV
    • What causes it?
    • How does the kernel report it?
  2. Core dump generation
    • ulimit -c and core_pattern
    • Where core files are stored
  3. Pointer basics
    • NULL vs garbage pointers
    • Dereference behavior

5.5 Questions to Guide Your Design

  1. How do you confirm you are using the exact binary that produced the core?
  2. Which frame tells you the most about the crash?
  3. What does the faulting address indicate (NULL vs non-NULL)?

5.6 Thinking Exercise

If the backtrace shows malloc as the top frame, list three possible causes that are not a NULL pointer.

5.7 The Interview Questions They’ll Ask

  1. How do you load a core file in GDB?
  2. What does the top frame in a backtrace represent?
  3. Why might a core file be missing?

5.8 Hints in Layers

Hint 1: Enable core

  • ulimit -c unlimited

Hint 2: Load core

  • gdb ./crash core

Hint 3: Inspect

  • backtrace, frame 0, print p

5.9 Books That Will Help

Topic Book Chapter
Core dumps TLPI Ch. 23
Signals TLPI Ch. 20
Debugging “The Art of Debugging with GDB” Ch. 4-5

5.10 Implementation Phases

Phase 1: Foundation (30 minutes)

Goals:

  • Generate a core dump.

Tasks:

  1. Compile crash.c with symbols.
  2. Run the binary and confirm core file exists.

Checkpoint: Core file created in expected location.

Phase 2: Core Functionality (30 minutes)

Goals:

  • Analyze the crash.

Tasks:

  1. Load core file in GDB.
  2. Run backtrace and inspect frame 0.

Checkpoint: Identify exact crashing line.

Phase 3: Polish & Edge Cases (20 minutes)

Goals:

  • Inspect memory and registers.

Tasks:

  1. Use info registers and x/10x $rsp.
  2. Explain why the crash occurred.

Checkpoint: Clear root-cause explanation.

5.11 Key Implementation Decisions

Decision Options Recommendation Rationale
Core file location cwd or system path cwd Easier to find
Optimization level -O0 vs -O2 -O0 Clearer variable info

6. Testing Strategy

6.1 Test Categories

Category Purpose Examples
Setup Verify core generation ulimit -c reports unlimited
Analysis Confirm GDB reads core backtrace shows source lines
Root cause Validate pointer value print p is NULL

6.2 Critical Test Cases

  1. Core file exists after crash.
  2. Backtrace points to crash_me().
  3. Pointer inspection shows 0x0.

6.3 Test Data

NULL dereference in crash.c

7. Common Pitfalls & Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Core not generated No core file Set ulimit -c unlimited
Wrong binary Line numbers wrong Rebuild and rerun
Stripped symbols Only addresses shown Compile with -g

7.2 Debugging Strategies

  • Compare build timestamp with core generation time.
  • Use info files to confirm symbol loading.

7.3 Performance Traps

Not applicable here.


8. Extensions & Challenges

8.1 Beginner Extensions

  • Trigger a crash via stack overflow.
  • Use info registers to interpret rip.

8.2 Intermediate Extensions

  • Analyze a core from an optimized build.
  • Inspect memory around the faulting address.

8.3 Advanced Extensions

  • Configure core_pattern to route core files.
  • Practice with a multi-threaded crash.

9. Real-World Connections

9.1 Industry Applications

  • Production incidents: Core dumps are often required for root-cause analysis.
  • Security: Core analysis can reveal exploit paths and corrupted states.
  • coredumpctl (systemd) - manages core files on Linux.
  • gdb - primary tool for inspection.

9.3 Interview Relevance

  • Shows you can debug crashes without reproduction.
  • Demonstrates understanding of signals and memory errors.

10. Resources

10.1 Essential Reading

  • “The Linux Programming Interface” - Signals and core dumps.
  • GDB Manual - “Debugging Programs”.

10.2 Video Resources

  • Search: “GDB core dump analysis”.

10.3 Tools & Documentation

  • GDB: https://sourceware.org/gdb/
  • man 5 core: Format details.

11. Self-Assessment Checklist

11.1 Understanding

  • I can explain why SIGSEGV happens.
  • I can load a core and read a backtrace.
  • I can interpret a faulting address.

11.2 Implementation

  • I generated a core file successfully.
  • I found the crashing line.
  • I explained the root cause.

11.3 Growth

  • I can debug a crash from a production core.

12. Submission / Completion Criteria

Minimum Viable Completion:

  • Generate a core file and locate the crashing line in GDB.

Full Completion:

  • Inspect registers and memory to explain the crash mechanism.

Excellence (Going Above & Beyond):

  • Analyze a crash in optimized code or multi-threaded code.

This guide was generated from LEARN_GDB_DEEP_DIVE.md. For the complete learning path, see the parent directory README.