use alloc::boxed::Box; use alloc::vec::Vec; use core::ffi::c_void; extern "Rust" { fn miri_backtrace_size(flags: u64) -> usize; fn miri_get_backtrace(flags: u64, buf: *mut *mut ()); fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame; fn miri_resolve_frame_names(ptr: *mut (), flags: u64, name_buf: *mut u8, filename_buf: *mut u8); } #[repr(C)] pub struct MiriFrame { pub name_len: usize, pub filename_len: usize, pub lineno: u32, pub colno: u32, pub fn_ptr: *mut c_void, } #[derive(Clone, Debug)] pub struct FullMiriFrame { pub name: Box<[u8]>, pub filename: Box<[u8]>, pub lineno: u32, pub colno: u32, pub fn_ptr: *mut c_void, } #[derive(Debug, Clone)] pub struct Frame { pub addr: *mut c_void, pub inner: FullMiriFrame, } // SAFETY: Miri guarantees that the returned pointer // can be used from any thread. unsafe impl Send for Frame {} unsafe impl Sync for Frame {} impl Frame { pub fn ip(&self) -> *mut c_void { self.addr } pub fn sp(&self) -> *mut c_void { core::ptr::null_mut() } pub fn symbol_address(&self) -> *mut c_void { self.inner.fn_ptr } pub fn module_base_address(&self) -> Option<*mut c_void> { None } } pub fn trace bool>(cb: F) { // SAFETY: Miri guarantees that the backtrace API functions // can be called from any thread. unsafe { trace_unsynchronized(cb) }; } pub fn resolve_addr(ptr: *mut c_void) -> Frame { // SAFETY: Miri will stop execution with an error if this pointer // is invalid. let frame = unsafe { miri_resolve_frame(ptr as *mut (), 1) }; let mut name = Vec::with_capacity(frame.name_len); let mut filename = Vec::with_capacity(frame.filename_len); // SAFETY: name and filename have been allocated with the amount // of memory miri has asked for, and miri guarantees it will initialize it unsafe { miri_resolve_frame_names(ptr as *mut (), 0, name.as_mut_ptr(), filename.as_mut_ptr()); name.set_len(frame.name_len); filename.set_len(frame.filename_len); } Frame { addr: ptr, inner: FullMiriFrame { name: name.into(), filename: filename.into(), lineno: frame.lineno, colno: frame.colno, fn_ptr: frame.fn_ptr, }, } } pub unsafe fn trace_unsynchronized bool>(mut cb: F) { let len = miri_backtrace_size(0); let mut frames = Vec::with_capacity(len); miri_get_backtrace(1, frames.as_mut_ptr()); frames.set_len(len); for ptr in frames.iter() { let frame = resolve_addr(*ptr as *mut c_void); cb(&super::Frame { inner: frame }); } }