use boxlite::vmm::ExitInfo;
use std::path::PathBuf;
use std::sync::OnceLock;
const SIGNAL_EXIT_CODE_BASE: i32 = 128;
const PANIC_EXIT_CODE: i32 = 101;
static EXIT_FILE_PATH: OnceLock<PathBuf> = OnceLock::new();
pub struct CrashCapture;
impl CrashCapture {
pub fn install(exit_file: PathBuf) {
install_panic_hook(exit_file.clone());
install_signal_handlers(exit_file);
}
}
fn install_panic_hook(exit_file: PathBuf) {
let default_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |panic_info| {
let message = panic_info
.payload()
.downcast_ref::<&str>()
.map(|s| s.to_string())
.or_else(|| panic_info.payload().downcast_ref::<String>().cloned())
.unwrap_or_else(|| "Unknown panic".into());
let location = panic_info
.location()
.map(|l| format!("{}:{}:{}", l.file(), l.line(), l.column()))
.unwrap_or_else(|| "unknown".into());
tracing::error!(message = %message, location = %location, "PANIC");
let info = ExitInfo::Panic {
exit_code: PANIC_EXIT_CODE,
message,
location,
};
if let Ok(json) = serde_json::to_string(&info) {
let _ = std::fs::write(&exit_file, json);
}
default_hook(panic_info);
}));
}
fn install_signal_handlers(exit_file: PathBuf) {
let _ = EXIT_FILE_PATH.set(exit_file);
unsafe {
libc::signal(libc::SIGABRT, crash_signal_handler as *const () as usize);
libc::signal(libc::SIGSEGV, crash_signal_handler as *const () as usize);
libc::signal(libc::SIGBUS, crash_signal_handler as *const () as usize);
libc::signal(libc::SIGILL, crash_signal_handler as *const () as usize);
libc::signal(libc::SIGSYS, crash_signal_handler as *const () as usize);
}
}
extern "C" fn crash_signal_handler(sig: libc::c_int) {
let signal = match sig {
libc::SIGABRT => "SIGABRT",
libc::SIGSEGV => "SIGSEGV",
libc::SIGBUS => "SIGBUS",
libc::SIGILL => "SIGILL",
libc::SIGSYS => "SIGSYS",
_ => "UNKNOWN",
};
if let Some(exit_file) = EXIT_FILE_PATH.get() {
let info = ExitInfo::Signal {
exit_code: SIGNAL_EXIT_CODE_BASE + sig,
signal: signal.to_string(),
};
if let Ok(json) = serde_json::to_string(&info) {
let _ = std::fs::write(exit_file, json);
}
}
unsafe {
libc::signal(sig, libc::SIG_DFL);
libc::raise(sig);
}
}