#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
mod libunwind_x86_64;
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
mod libunwind_aarch64;
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
pub use libunwind_aarch64::*;
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
pub use libunwind_x86_64::*;
#[cfg(all(test, target_os = "linux"))]
mod tests {
use super::*;
#[test]
#[cfg_attr(miri, ignore)] fn test_basic_unwind() {
unsafe {
let mut context: UnwContext = std::mem::zeroed();
let mut cursor: UnwCursor = std::mem::zeroed();
let ret = getcontext(&mut context);
assert_eq!(ret, 0, "getcontext failed");
let ret = unw_init_local2(&mut cursor, &mut context, 0);
assert_eq!(ret, 0, "unw_init_local2 failed");
let mut frames = 0;
loop {
let ret = unw_step(&mut cursor);
if ret <= 0 {
break;
}
frames += 1;
if frames > 100 {
break;
}
}
assert!(frames > 0, "Expected at least one stack frame");
}
}
#[test]
#[cfg_attr(miri, ignore)] fn test_get_register() {
unsafe {
let mut context: UnwContext = std::mem::zeroed();
let mut cursor: UnwCursor = std::mem::zeroed();
assert_eq!(getcontext(&mut context), 0);
assert_eq!(unw_init_local2(&mut cursor, &mut context, 0), 0);
let mut ip: UnwWord = 0;
let ret = unw_get_reg(&mut cursor, UNW_REG_IP, &mut ip);
assert_eq!(ret, 0, "Failed to get IP register");
assert_ne!(ip, 0, "IP should not be zero");
let mut sp: UnwWord = 0;
let ret = unw_get_reg(&mut cursor, UNW_REG_SP, &mut sp);
assert_eq!(ret, 0, "Failed to get SP register");
assert_ne!(sp, 0, "SP should not be zero");
}
}
#[test]
#[cfg_attr(miri, ignore)] fn test_backtrace2() {
unsafe {
let mut context: UnwContext = std::mem::zeroed();
assert_eq!(getcontext(&mut context), 0);
let mut frames: [*mut ::std::os::raw::c_void; 100] = [std::ptr::null_mut(); 100];
let ret = unw_backtrace2(frames.as_mut_ptr(), 100, &mut context, 0);
assert!(ret >= 0, "unw_backtrace2 failed with error: {}", ret);
let frame_count = ret as usize;
assert!(frame_count > 0, "Expected at least one frame");
for (i, &frame) in frames.iter().enumerate().take(frame_count) {
let frame_ptr = frame as usize;
println!("Frame {}: 0x{:016x}", i, frame_ptr);
}
}
}
#[test]
#[cfg_attr(miri, ignore)] fn test_get_proc_name() {
unsafe {
let mut context: UnwContext = std::mem::zeroed();
let mut cursor: UnwCursor = std::mem::zeroed();
assert_eq!(getcontext(&mut context), 0);
assert_eq!(
unw_init_local2(&mut cursor, &mut context, UNW_INIT_LOCAL_ONLY_IP),
0
);
let mut name: [libc::c_char; 100] = [0; 100];
let ret = unw_get_proc_name(&mut cursor, name.as_mut_ptr(), 100, std::ptr::null_mut());
assert_eq!(ret, 0, "unw_get_proc_name failed");
let fn_name = std::ffi::CStr::from_ptr(name.as_ptr()).to_string_lossy();
assert!(!fn_name.is_empty(), "Name should not be empty");
assert!(
fn_name.contains("test_get_proc_name"),
"Name should contain 'test_get_proc_name'"
);
}
}
}