#[cfg(all(unix, not(target_arch = "arm")))]
#[inline(never)]
pub fn capture(frames: &mut [usize], skip: usize) -> usize {
use core::ffi::{c_int, c_void};
const NO_REASON: c_int = 0;
const END_OF_STACK: c_int = 5;
unsafe extern "C" {
fn _Unwind_Backtrace(
trace: extern "C" fn(*mut c_void, *mut c_void) -> c_int,
arg: *mut c_void,
) -> c_int;
fn _Unwind_GetIP(ctx: *mut c_void) -> usize;
}
struct State<'a> {
frames: &'a mut [usize],
len: usize,
skip: usize,
}
extern "C" fn step(ctx: *mut c_void, arg: *mut c_void) -> c_int {
let st = unsafe { &mut *(arg as *mut State) };
let ip = unsafe { _Unwind_GetIP(ctx) };
if ip == 0 {
return END_OF_STACK;
}
if st.skip > 0 {
st.skip -= 1;
return NO_REASON;
}
st.frames[st.len] = ip - 1;
st.len += 1;
if st.len == st.frames.len() {
END_OF_STACK
} else {
NO_REASON
}
}
let mut st = State {
frames,
len: 0,
skip: skip + 1,
};
unsafe { _Unwind_Backtrace(step, &raw mut st as *mut c_void) };
st.len
}
#[cfg(windows)]
#[inline(never)]
pub fn capture(frames: &mut [usize], skip: usize) -> usize {
use windows_sys::Win32::System::Diagnostics::Debug::RtlCaptureStackBackTrace;
let max = frames.len().min(u16::MAX as usize) as u32;
let n = unsafe {
RtlCaptureStackBackTrace(
(skip + 1) as u32,
max,
frames.as_mut_ptr() as *mut *mut core::ffi::c_void,
core::ptr::null_mut(),
)
} as usize;
for f in &mut frames[..n] {
*f -= 1;
}
n
}
#[cfg(not(any(all(unix, not(target_arch = "arm")), windows)))]
pub fn capture(_frames: &mut [usize], _skip: usize) -> usize {
0
}