Skip to main content

MCP Server for rr Reverse Debugging

Project description

karellen-rr-mcp

Gitter Build Status Coverage Status

karellen-rr-mcp Version karellen-rr-mcp Python Versions karellen-rr-mcp Downloads Per Day karellen-rr-mcp Downloads Per Week karellen-rr-mcp Downloads Per Month

MCP Server for rr Reverse Debugging.

Overview

karellen-rr-mcp is an MCP (Model Context Protocol) server that enables any MCP-compliant LLM client to use rr for reverse debugging. Instead of iteratively adding debug output and rebuilding, the LLM can record a failing test with rr, then replay it with full forward and reverse debugging via GDB/MI, inspecting program state without modifying source code.

Requirements

  • Linux (rr only supports Linux)
  • rr installed and on PATH
  • Python >= 3.9
  • perf_event_paranoid set to allow recording (<= 1):
    sudo sysctl kernel.perf_event_paranoid=1
    

Installation

pip install karellen-rr-mcp

Or with pipx for an isolated environment:

pipx install karellen-rr-mcp

Claude Code Integration

Configure the MCP server

Add to your Claude Code settings (~/.claude/claude_code_config.json for global, or .claude/claude_code_config.json for per-project):

{
  "mcpServers": {
    "karellen-rr-mcp": {
      "command": "karellen-rr-mcp"
    }
  }
}

If installed with pipx, use the full path:

{
  "mcpServers": {
    "karellen-rr-mcp": {
      "command": "pipx",
      "args": ["run", "karellen-rr-mcp"]
    }
  }
}

Teach Claude the debugging workflow

Claude will automatically discover all rr_* tools, but to teach it when and how to use them effectively, add the following to your project's CLAUDE.md:

## Reverse Debugging with rr

### When to Use rr

Run tests and code normally. When you encounter a crash, segfault, test failure, or bug
that is hard to understand from the output alone, **re-run the failing command under rr
recording** and then debug it:

```
rr_record(command=["make", "test"])
rr_record(command=["./failing_test"])
rr_record(command=["ctest", "--test-dir", "build"], working_directory="/path/to/project")
```

Keep the record-replay-debug cycle going until all problems are resolved. rr captures
the full execution deterministically, so the failure is replayed exactly as it happened.

### Debugging a SIGSEGV or Crash

When a crash occurs, re-run the crashing command with `rr_record`, then debug backwards:

1. **Start replay**: `rr_replay_start()`
2. **Run forward to the crash**: `rr_continue()` — the program will stop at the signal
   (SIGSEGV, SIGABRT, etc.) with the crashing frame
3. **Examine the crash site**: `rr_backtrace()` to see the full call stack,
   `rr_locals()` to see variable values, `rr_evaluate("*ptr")` to inspect the
   faulting pointer or expression
4. **Reverse-step to find the root cause**: `rr_next(reverse=True)` or
   `rr_step(reverse=True)` to walk backwards from the crash instruction-by-instruction,
   watching how variables and memory changed
5. **Set a watchpoint and reverse-continue**: if a variable or pointer was corrupted,
   use `rr_watchpoint_set("my_var")` then `rr_continue(reverse=True)` — this will stop
   at the exact moment the variable was last modified before the crash
6. **Use checkpoints**: `rr_checkpoint_save()` at interesting points so you can
   `rr_checkpoint_restore(id)` to jump back without replaying from the start
7. **Clean up**: `rr_replay_stop()` when the bug is understood

### General Debugging Workflow

For non-crash bugs (wrong output, logic errors, test assertion failures):

1. **Record** the failing test: `rr_record(command=["./failing_test"])`
2. **Start replay**: `rr_replay_start()`
3. **Set breakpoints** at the assertion or where wrong behavior is observed:
   `rr_breakpoint_set("test_function")` or `rr_breakpoint_set("file.c:42")`
4. **Run forward** to the breakpoint: `rr_continue()`
5. **Inspect state**: `rr_backtrace()`, `rr_locals()`, `rr_evaluate("expr")`
6. **Go backward** to find where state diverged: `rr_continue(reverse=True)`,
   `rr_step(reverse=True)`, `rr_next(reverse=True)`
7. **Clean up**: `rr_replay_stop()`

### Key Principles

- **Re-run under rr when stuck**: if a test fails or a program crashes and the cause
  isn't obvious from the output, re-run with `rr_record` and debug the trace — don't
  waste cycles adding printf statements
- **Work backwards from symptoms**: go forward to where the bug manifests, then reverse
  to find the cause — this is the opposite of printf-debugging and far more efficient
- **Watchpoints + reverse = root cause**: setting a watchpoint on a corrupted variable
  and reverse-continuing finds the exact write that caused corruption
- **Never modify source to debug**: rr replay gives full access to program state at every
  point in execution — no need for debug prints, trace output, or conditional breakpoints
  in source code

### rr Best Practices

- **Build with debug symbols**: compile with `-g` (and preferably `-O0` or `-Og`) so that
  rr traces include full source-level information — function names, line numbers, local
  variables, and type info are all available during replay
- **rr records the entire process tree**: child processes and threads are all captured,
  so multi-process and multi-threaded bugs can be debugged deterministically
- **Traces are deterministic**: replaying a trace always reproduces the exact same
  execution, including thread interleavings and signal delivery — race conditions and
  heisenbugs that are impossible to reproduce with printf become trivially repeatable
- **Traces survive the session**: rr traces are stored in `~/.local/share/rr/` by default
  and persist across sessions. Use `rr_list_recordings()` to see available traces and
  `rr_replay_start(trace_dir="/path/to/trace")` to replay an older one
- **Multiple replays from one recording**: a single trace can be replayed as many times
  as needed with different breakpoints and inspection strategies — no need to re-record
- **Conditional breakpoints narrow the search**: use
  `rr_breakpoint_set("file.c:100", condition="i == 42")` to stop only when specific
  conditions hold, then reverse from there
- **Checkpoints avoid re-replaying**: save checkpoints at key points with
  `rr_checkpoint_save()` and jump back to them with `rr_checkpoint_restore(id)` instead
  of replaying from the beginning
- **rr has overhead constraints**: rr only supports Linux on x86-64 (and experimentally
  aarch64), does not support programs that use hardware performance counters directly,
  and adds ~1.2x slowdown for CPU-bound code (more for I/O-heavy or syscall-heavy code)
- **Environment variables in recording**: pass `env={"MALLOC_CHECK_": "3"}` or similar
  to `rr_record` to enable additional runtime checks during recording that may surface
  bugs earlier

Available Tools

Session Lifecycle

Tool Description
rr_record Record a command with rr. Returns trace directory path.
rr_replay_start Start replay session (launches rr gdbserver + GDB/MI).
rr_replay_stop Stop current replay session, clean up.
rr_list_recordings List available rr trace recordings.

Breakpoints

Tool Description
rr_breakpoint_set Set breakpoint at function/file:line/address.
rr_breakpoint_remove Remove a breakpoint.
rr_breakpoint_list List all breakpoints.
rr_watchpoint_set Set hardware watchpoint (write/read/access).

Execution Control

Tool Description
rr_continue Continue forward or backward.
rr_step Step into (forward or reverse).
rr_next Step over (forward or reverse).
rr_finish Run to function return (or call site if reverse).
rr_run_to_event Jump to specific rr event number.

State Inspection

Tool Description
rr_backtrace Get call stack.
rr_evaluate Evaluate C/C++ expression in current context.
rr_locals List local variables with values.
rr_read_memory Read raw memory bytes.
rr_registers Read CPU registers.
rr_source_lines List source code around current position.

Checkpoints

Tool Description
rr_checkpoint_save Save checkpoint at current position.
rr_checkpoint_restore Restore to saved checkpoint.

License

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

karellen_rr_mcp-0.1.0.tar.gz (21.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

karellen_rr_mcp-0.1.0-py3-none-any.whl (19.3 kB view details)

Uploaded Python 3

File details

Details for the file karellen_rr_mcp-0.1.0.tar.gz.

File metadata

  • Download URL: karellen_rr_mcp-0.1.0.tar.gz
  • Upload date:
  • Size: 21.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for karellen_rr_mcp-0.1.0.tar.gz
Algorithm Hash digest
SHA256 674152bcd4f8b167a8e93f833bee788bc508f0b921fb336b934260e3893c199a
MD5 a1659aee2a4b9d19689392adc6a8e624
BLAKE2b-256 d3f2d59af562abeeab56e7c2534ed2871deafc770c1b439e0623db258762acd9

See more details on using hashes here.

File details

Details for the file karellen_rr_mcp-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for karellen_rr_mcp-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 052ea2eb99ab4c0af3d833b8c0c69ca9aebb076a39735e20dff40e0c4e90f45f
MD5 0009d4bd52199506926d6d5e7c52378e
BLAKE2b-256 15af58bd8b066f30d7afa33b841ac59638fe86bb2828de2d05e4626897b03359

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page