#[macro_export]
macro_rules! fn_impl {
($ftype: ty) => {
impl $crate::AtomicFnPtr<$ftype> {
pub const fn new(shadow_name: Option<&'static std::ffi::CStr>) -> Self {
Self {
ptr: $crate::AtomicUsize::new(0),
shadow_name,
_t: std::marker::PhantomData,
}
}
pub fn try_load(&self) -> Option<$ftype> {
let ptr = self.ptr.load(std::sync::atomic::Ordering::Acquire) as *mut c_void;
if ptr.is_null() {
None
} else {
Some(unsafe { std::mem::transmute::<*mut c_void, $ftype>(ptr) })
}
}
#[allow(dead_code)]
fn load_or_shadow(&self) -> $ftype {
if let Some(f) = self.try_load() {
f
} else {
let ptr = unsafe {
libc::dlsym(
libc::RTLD_NEXT,
self.shadow_name.expect("Missing name").as_ptr(),
)
};
let ptr: $ftype = unsafe { std::mem::transmute(ptr) };
self.store(Some(ptr));
self.try_load().unwrap()
}
}
pub fn store(&self, val: Option<$ftype>) {
if let Some(val) = val {
let val = val as *const ();
self.ptr.store(
val as *const _ as usize,
std::sync::atomic::Ordering::Release,
)
} else {
self.ptr.store(0usize, std::sync::atomic::Ordering::Release);
}
}
}
};
}
#[macro_export]
macro_rules! shadow {
($name: ident ($($v:ident: $t:ty),+) -> $return: ty $block: block) => {
macro_rules! ftype {
() => { extern "C" fn ($($t),+) -> $return }
}
#[unsafe(no_mangle)]
#[allow(unused)]
pub unsafe extern "C" fn $name($($v: $t),+) -> $return {
static SHADOWED_ITEM: $crate::AtomicFnPtr<ftype!()> = $crate::AtomicFnPtr::<ftype!()>::new(Some($crate::c_stringify!(stringify!($name))));
let f: ftype!() = if let Some(f) = SHADOWED_ITEM.try_load() {
f
} else {
let ptr = unsafe { libc::dlsym(libc::RTLD_NEXT, SHADOWED_ITEM.shadow_name.expect("Missing name").as_ptr()) };
let ptr = unsafe { std::mem::transmute::<*mut c_void, ftype!()>(ptr) };
SHADOWED_ITEM.store(Some(ptr));
SHADOWED_ITEM.try_load().unwrap()
};
macro_rules! f {
() => {
(f as ftype!())
}
}
$block
}
};
}
#[macro_export]
macro_rules! get_frame {
($n: expr) => {{
unsafe extern "C" {
fn unw_backtrace(buffer: *mut *mut c_void, size: c_int) -> c_int;
}
use std::ffi::{c_int, c_void};
let mut buf = [std::ptr::null_mut() as *mut c_void; $n as usize];
let resolved = unsafe { unw_backtrace(buf.as_mut_ptr(), $n as i32) };
if resolved == $n {
buf.last().map(|v| *v as *mut c_void)
} else {
None
}
}};
}