grok-build-upstream-mirror/crates/codegen/xai-crash-handler
Repository files (latest commit first)
Filename Latest commit message Latest commit date
grokkybara[bot] c68e39f604 Publish harness and TUI open-source
initial sync from the monorepo
2026-07-16 06:46:02 +01:00
..
src Publish harness and TUI open-source 2026-07-16 06:46:02 +01:00
tests Publish harness and TUI open-source 2026-07-16 06:46:02 +01:00
Cargo.toml Publish harness and TUI open-source 2026-07-16 06:46:02 +01:00
README.md Publish harness and TUI open-source 2026-07-16 06:46:02 +01:00

xai-crash-handler

Crash handler for SIGBUS/SIGSEGV with best-effort backtrace capture.

How it works

install() registers a sigaction handler. On crash it writes a binary blob (GCRX format) to crash_dir/last-crash.bin and restores the terminal via pre-computed escape sequences. The handler uses only async-signal-safe operations for file I/O, terminal restore, and re-raise.

On next launch, check_previous_crash() reads the blob, resolves IPs to symbols via backtrace, writes last-crash-report.txt, and archives it (keeping the last 5 reports).

No-ops on non-unix platforms. On musl-based Linux (release builds), the handler still records signal/address/version but skips frame capture since musl does not provide backtrace().

Limitations

Frame capture is best-effort

Frame capture uses two fully async-signal-safe techniques:

  1. The crash instruction pointer is extracted directly from the ucontext_t passed by the kernel.
  2. Additional frames are captured by walking the frame-pointer chain (RBP on x86_64, x29 on aarch64) with raw pointer reads.

In release builds without -C force-frame-pointers, the frame-pointer chain may be incomplete or empty (the compiler omits frame pointers by default for optimization). The crash PC is always captured. In debug/dev builds, frame pointers are retained by default, producing fuller call stacks.

sigaltstack is per-thread

The alternate signal stack is installed only on the thread that calls install(). Tokio worker threads do not inherit it. Stack overflows on worker threads will still trigger the handler (sigaction is process-wide), but without altstack protection the handler itself may fault on the overflowed stack.

Usage

use std::path::PathBuf;

let crash_dir = PathBuf::from("/home/user/.myapp/crash");

// check_previous_crash MUST be called before install(), because
// install() opens last-crash.bin with O_TRUNC.
if let Some(r) = xai_crash_handler::check_previous_crash(&crash_dir) {
    eprintln!("Crashed last session: {}", r.signal_name);
    eprintln!("Report: {}", r.report_path.display());
}

// install() before any threads or async runtime — sigaltstack is per-thread.
// Creates crash_dir if it does not exist.
xai_crash_handler::install(xai_crash_handler::CrashHandlerConfig {
    app_version: env!("CARGO_PKG_VERSION").to_string(),
    crash_dir,
});