# How to Debug LLVM Using Crash Dumps: A Step-by-Step Guide

> Learn to debug LLVM with crash dumps. Use core dumps in LLDB or GDB to inspect compiler state after a fatal signal. Follow our step-by-step guide for effective LLVM debugging.

- Repository: [LLVM/llvm-project](https://github.com/llvm/llvm-project)
- Tags: how-to-guide
- Published: 2026-09-11

---

**LLVM automatically registers signal handlers via `llvm::sys::PrintStackTraceOnErrorSignal` that emit stack traces on fatal signals, enabling developers to load OS-generated core dumps into LLDB or GDB to inspect the complete compiler state at the moment of failure.**

Debugging the LLVM compiler infrastructure requires specialized techniques when crashes occur deep within optimization passes or target code generation. When you need to debug LLVM using crash dumps, you leverage the framework's built-in crash recovery architecture to capture the full memory state of a failed compilation process. This methodology allows precise root cause analysis of segmentation faults and assertion failures by examining the exact LLVM IR and variable states present at the crash point.

## Prerequisites for Capturing LLVM Crash Dumps

Before analyzing failures, you must configure your system and LLVM build to generate actionable crash data.

### Building LLVM with Debug Symbols

Debug symbols allow the debugger to map machine addresses back to source lines, IR instructions, and variable names. Configure your build with assertions enabled:

```bash
cmake -S llvm -B build \
  -DCMAKE_BUILD_TYPE=Debug \
  -DLLVM_ENABLE_ASSERTIONS=ON \
  -DLLVM_ENABLE_PROJECTS="clang"
ninja -C build

```

### Enabling System-Level Core Dumps

On Linux systems, the operating system must be configured to write core files when a process receives a fatal signal. Set this limit before running any LLVM tools:

```bash
ulimit -c unlimited

```

This ensures that when LLVM crashes, the system creates a `core.<pid>` file containing the complete memory image of the process.

## How LLVM Captures Crash Information

LLVM's Support library implements a centralized crash handling infrastructure that operates automatically when integrated tools start.

### Signal Handling in InitLLVM.cpp

The entry point `InitLLVM` in [`llvm/lib/Support/InitLLVM.cpp`](https://github.com/llvm/llvm-project/blob/main/llvm/lib/Support/InitLLVM.cpp) registers the fatal signal handler by calling `llvm::sys::PrintStackTraceOnErrorSignal`. According to the LLVM source code, this initialization routine installs handlers for `SIGSEGV`, `SIGABRT`, and other fatal signals that invoke `llvm::sys::PrintStackTrace` to print a human-readable backtrace to `stderr` before the process terminates.

### The CrashRecoveryContext Mechanism

For scenarios requiring crash isolation—such as testing individual passes—the `CrashRecoveryContext` class in [`llvm/lib/Support/CrashRecoveryContext.cpp`](https://github.com/llvm/llvm-project/blob/main/llvm/lib/Support/CrashRecoveryContext.cpp) provides a RAII interface that catches crashes within a specific scope. This mechanism runs vulnerable code in a separate context, executes cleanup callbacks if a crash occurs, and optionally re-throws the signal, allowing LLVM tools to recover from failures without terminating the entire process.

## Analyzing LLVM Crash Dumps Step-by-Step

Once you have generated a core dump, follow this workflow to extract diagnostic information.

### Reproducing the Crash

Execute the LLVM tool with the input that triggers the failure. The `PrintStackTraceOnErrorSignal` handler will output the stack trace to the terminal while the OS simultaneously writes the core file:

```bash
./build/bin/opt -load-pass-plugin=MyPass.so -passes=my-pass input.ll

# Output: Stack dump:

# 0.  Running pass 'My Pass' on function '@foo'

# Segmentation fault (core dumped)

```

### Loading the Core Dump into a Debugger

Use LLDB or GDB to restore the crashed process state. Load both the debug-instrumented binary and the core file:

```bash
lldb ./build/bin/opt -c core.<pid>

```

Within the debugger, analyze the failure:

```lldb
(lldb) bt all              # Display all thread backtraces

(lldb) frame select 3      # Navigate to the crashing frame

(lldb) print *F            # Inspect LLVM IR function objects

(lldb) image dump sections # Verify debug info sections are loaded

```

### Symbolizing Addresses with llvm-symbolizer

If you have a raw address from a stack trace but lack debug symbols in the core file, use the `llvm-symbolizer` tool to resolve instruction pointers to source locations:

```bash
llvm-symbolizer -obj ./build/bin/opt -eip 0x0000000000abcdef

```

This command queries the binary's debug information to return the corresponding function name, file path, and line number.

## Advanced Crash Debugging Techniques

Beyond basic core dump analysis, LLVM provides facilities for automated crash reproduction and safe failure isolation.

### Using CrashRecoveryContext in Custom Passes

When developing custom LLVM passes, wrap potentially unsafe operations in a `CrashRecoveryContext` to prevent the entire compiler from crashing on unexpected inputs. The implementation in [`llvm/lib/Support/CrashRecoveryContext.cpp`](https://github.com/llvm/llvm-project/blob/main/llvm/lib/Support/CrashRecoveryContext.cpp) allows you to attempt dangerous transformations safely:

```cpp
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/IR/PassManager.h"

struct SafePass : PassInfoMixin<SafePass> {
  PreservedAnalyses run(Function &F, FunctionAnalysisManager &) {
    llvm::CrashRecoveryContext CRC;
    bool Success = CRC.RunSafely([&] {
      // Attempt operation that might dereference null or corrupt memory
      processUnsafeTransformation(F);
    });
    
    if (!Success) {
      llvm::errs() << "Crash detected in pass – aborting safely.\n";
      return PreservedAnalyses::none();
    }
    return PreservedAnalyses::all();
  }
};

```

This pattern is extensively used in the MLIR PassManager and LLVM unit tests to ensure flaky transformations do not crash the test harness.

### Generating Crash Reproducers

To create minimal test cases that reproduce crashes, LLVM offers crash-reproducer generation integrated into the PassManager. As implemented in [`mlir/lib/Pass/PassCrashRecovery.cpp`](https://github.com/llvm/llvm-project/blob/main/mlir/lib/Pass/PassCrashRecovery.cpp), you can enable the `PassCrashReproducerGenerator` by passing:

```bash
./build/bin/opt -enable-crash-reproducer-generation=repro.mlir \
  -passes=my-pass input.ll

```

When a pass crashes, this facility dumps a minimal IR file containing only the constructs necessary to trigger the failure. This reproducer file is invaluable for filing detailed bug reports or creating regression tests.

## Summary

- **Debug builds are essential**: Compile LLVM with `-DCMAKE_BUILD_TYPE=Debug` and `-DLLVM_ENABLE_ASSERTIONS=ON` to ensure line number and IR mapping information is available in crash dumps.
- **Core dumps capture complete state**: Enable `ulimit -c unlimited` to preserve the full process memory image when `PrintStackTraceOnErrorSignal` fires.
- **Debuggers restore context**: Load the binary and core file into LLDB or GDB to inspect stack frames, LLVM IR values, and local variables at the exact crash point.
- **Use `llvm-symbolizer`** to resolve raw addresses from stack traces into human-readable function names and source locations.
- **Leverage `CrashRecoveryContext`** in custom passes to isolate failures and prevent complete compiler crashes during development.
- **Generate crash reproducers** using the PassManager's built-in facilities to create minimal test cases automatically.

## Frequently Asked Questions

### How do I enable core dumps on Linux when debugging LLVM?

Run `ulimit -c unlimited` in your shell before executing the LLVM tool. This removes the size limit on core files, ensuring the operating system writes a complete memory dump to `core.<pid>` when LLVM receives a fatal signal. You may also need to configure `/proc/sys/kernel/core_pattern` to control where core files are saved.

### What is the difference between PrintStackTraceOnErrorSignal and CrashRecoveryContext?

`PrintStackTraceOnErrorSignal`, registered in [`llvm/lib/Support/InitLLVM.cpp`](https://github.com/llvm/llvm-project/blob/main/llvm/lib/Support/InitLLVM.cpp), is a global signal handler that prints a backtrace and terminates the process when a fatal signal occurs. In contrast, `CrashRecoveryContext` in [`llvm/lib/Support/CrashRecoveryContext.cpp`](https://github.com/llvm/llvm-project/blob/main/llvm/lib/Support/CrashRecoveryContext.cpp) is a scoped recovery mechanism that catches crashes within a specific code block, executes cleanup code, and allows the program to continue execution rather than terminating.

### How can I generate a minimal test case from an LLVM crash?

Pass the `-enable-crash-reproducer-generation=<filename>` option to the PassManager when running `opt` or MLIR tools. As implemented in [`mlir/lib/Pass/PassCrashRecovery.cpp`](https://github.com/llvm/llvm-project/blob/main/mlir/lib/Pass/PassCrashRecovery.cpp), this triggers the `PassCrashReproducerGenerator` to dump a reduced IR file upon crash, containing only the necessary instructions to reproduce the failure.

### Which debugger works best with LLVM crash dumps?

Both LLDB and GDB work effectively with LLVM core dumps. LLDB often provides better integration with LLVM's data formatters for `SmallVector`, `StringRef`, and other LLVM-specific types. Ensure your debugger matches the architecture of the LLVM binary (e.g., 64-bit debugger for 64-bit builds) and that the binary was compiled with debug symbols to resolve source-level information.