summaryrefslogtreecommitdiffstats
path: root/library/backtrace/src/backtrace/miri.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/backtrace/src/backtrace/miri.rs')
-rw-r--r--library/backtrace/src/backtrace/miri.rs107
1 files changed, 107 insertions, 0 deletions
diff --git a/library/backtrace/src/backtrace/miri.rs b/library/backtrace/src/backtrace/miri.rs
new file mode 100644
index 000000000..9a5f65b80
--- /dev/null
+++ b/library/backtrace/src/backtrace/miri.rs
@@ -0,0 +1,107 @@
+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<F: FnMut(&super::Frame) -> 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<F: FnMut(&super::Frame) -> 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 });
+ }
+}