use crate::relocator::ForwardingTable;
use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
static TRAP_HANDLER_INSTALLED: AtomicBool = AtomicBool::new(false);
static ACTIVE_FORWARDING: AtomicPtr<ForwardingTable> = AtomicPtr::new(std::ptr::null_mut());
static PROTECTED_RANGES: std::sync::Mutex<Vec<(usize, usize)>> = std::sync::Mutex::new(Vec::new());
pub unsafe fn install_trap_handler() -> Result<(), &'static str> {
if TRAP_HANDLER_INSTALLED.swap(true, Ordering::SeqCst) {
return Ok(()); }
unsafe {
let mut sa: libc::sigaction = std::mem::zeroed();
sa.sa_sigaction = trap_handler as usize;
sa.sa_flags = libc::SA_SIGINFO | libc::SA_RESTART;
libc::sigemptyset(&mut sa.sa_mask);
let ret = libc::sigaction(libc::SIGSEGV, &sa, std::ptr::null_mut());
if ret != 0 {
TRAP_HANDLER_INSTALLED.store(false, Ordering::SeqCst);
return Err("Failed to install SIGSEGV handler");
}
}
Ok(())
}
pub fn register_protected_range(base: usize, size: usize) {
let mut ranges = PROTECTED_RANGES.lock().unwrap();
ranges.push((base, base + size));
}
pub fn unregister_protected_range(base: usize) {
let mut ranges = PROTECTED_RANGES.lock().unwrap();
ranges.retain(|&(b, _)| b != base);
}
pub unsafe fn set_active_forwarding(table: *mut ForwardingTable) {
ACTIVE_FORWARDING.store(table, Ordering::SeqCst);
}
pub fn clear_active_forwarding() {
ACTIVE_FORWARDING.store(std::ptr::null_mut(), Ordering::SeqCst);
}
extern "C" fn trap_handler(
sig: libc::c_int,
info: *mut libc::siginfo_t,
_context: *mut libc::c_void,
) {
if sig != libc::SIGSEGV || info.is_null() {
unsafe {
libc::signal(libc::SIGSEGV, libc::SIG_DFL);
libc::raise(libc::SIGSEGV);
}
return;
}
let fault_addr = unsafe { (*info).si_addr() } as usize;
let in_protected = {
if let Ok(ranges) = PROTECTED_RANGES.try_lock() {
ranges
.iter()
.any(|&(base, end)| fault_addr >= base && fault_addr < end)
} else {
false
}
};
if !in_protected {
unsafe {
libc::signal(libc::SIGSEGV, libc::SIG_DFL);
libc::raise(libc::SIGSEGV);
}
return;
}
let _forwarding = ACTIVE_FORWARDING.load(Ordering::SeqCst);
}
pub fn is_trap_handler_installed() -> bool {
TRAP_HANDLER_INSTALLED.load(Ordering::SeqCst)
}