From 085ee70402259ddd638b50563729f10c26613f4a Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 2 Dec 2019 19:35:54 -0500 Subject: [PATCH] Add support for Miri backtraces Companion to https://github.com/rust-lang/miri/pull/1559 --- src/backtrace/miri.rs | 76 +++++++++++++++++++++++++++++++++++++++++++ src/backtrace/mod.rs | 8 +++-- src/symbolize/miri.rs | 56 +++++++++++++++++++++++++++++++ src/symbolize/mod.rs | 7 ++-- 4 files changed, 140 insertions(+), 7 deletions(-) create mode 100644 src/backtrace/miri.rs create mode 100644 src/symbolize/miri.rs diff --git a/src/backtrace/miri.rs b/src/backtrace/miri.rs new file mode 100644 index 00000000..036d39b4 --- /dev/null +++ b/src/backtrace/miri.rs @@ -0,0 +1,76 @@ +use std::ffi::c_void; +use std::string::String; +use std::vec::Vec; +use std::boxed::Box; + +extern "Rust" { + fn miri_get_backtrace() -> Box<[*mut ()]>; + fn miri_resolve_frame(version: u8, ptr: *mut ()) -> MiriFrame; +} + +#[derive(Debug)] +struct MiriData { + frames: Vec<*mut c_void> +} + +#[derive(Debug, Clone)] +pub struct MiriFrame { + pub name: Box<[u8]>, + pub filename: Box<[u8]>, + pub lineno: u32, + pub colno: u32, +} + +#[derive(Debug, Clone)] +pub struct Frame { + pub addr: *mut c_void, + pub inner: MiriFrame +} + +// Miri is single threaded, and the raw +// pointer isn't really a pointer (it's a magic value +// returned by Miri) +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 { + std::ptr::null_mut() + } + + pub fn symbol_address(&self) -> *mut c_void { + self.addr + } + + pub fn module_base_address(&self) -> Option<*mut c_void> { + None + } +} + +pub fn trace bool>(cb: F) { + // Miri is single threaded + unsafe { trace_unsynchronized(cb) }; +} + + +pub fn resolve_addr(ptr: *mut c_void) -> Frame { + let frame: MiriFrame = unsafe { miri_resolve_frame(0, ptr as *mut ()) }; + Frame { + addr: ptr, + inner: frame + } +} + +pub unsafe fn trace_unsynchronized bool>(mut cb: F) { + let frames = miri_get_backtrace(); + for ptr in frames.iter() { + let frame = resolve_addr(*ptr as *mut c_void); + cb(&super::Frame { + inner: frame + }); + } +} diff --git a/src/backtrace/mod.rs b/src/backtrace/mod.rs index 17136c73..2d1b88c2 100644 --- a/src/backtrace/mod.rs +++ b/src/backtrace/mod.rs @@ -126,10 +126,12 @@ impl fmt::Debug for Frame { } cfg_if::cfg_if! { + // This needs to come first, to ensure that + // Miri takes priority over the host platform if #[cfg(miri)] { - mod noop; - use self::noop::trace as trace_imp; - pub(crate) use self::noop::Frame as FrameImp; + pub(crate) mod miri; + use self::miri::trace as trace_imp; + pub(crate) use self::miri::Frame as FrameImp; } else if #[cfg( any( all( diff --git a/src/symbolize/miri.rs b/src/symbolize/miri.rs new file mode 100644 index 00000000..46b575d4 --- /dev/null +++ b/src/symbolize/miri.rs @@ -0,0 +1,56 @@ +use core::marker::PhantomData; +use core::ffi::c_void; + +use crate::symbolize::{ResolveWhat, SymbolName}; +use crate::backtrace::miri::{resolve_addr, Frame}; +use crate::types::BytesOrWideString; + + +pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) { + let sym = match what { + ResolveWhat::Address(addr) => Symbol { + inner: resolve_addr(addr), + _unused: PhantomData + }, + ResolveWhat::Frame(frame) => { + Symbol { + inner: frame.inner.clone(), + _unused: PhantomData + } + } + }; + cb(&super::Symbol { inner: sym }) +} + + +pub struct Symbol<'a> { + inner: Frame, + _unused: PhantomData<&'a ()> +} + +impl<'a> Symbol<'a> { + pub fn name(&self) -> Option { + Some(SymbolName::new(&self.inner.inner.name)) + } + + pub fn addr(&self) -> Option<*mut c_void> { + Some(self.inner.addr) + } + + pub fn filename_raw(&self) -> Option { + Some(BytesOrWideString::Bytes(&self.inner.inner.filename)) + } + + pub fn lineno(&self) -> Option { + Some(self.inner.inner.lineno) + } + + pub fn colno(&self) -> Option { + Some(self.inner.inner.colno) + } + + pub fn filename(&self) -> Option<&::std::path::Path> { + use std::path::Path; + Some(Path::new(std::str::from_utf8(&self.inner.inner.filename).unwrap())) + } +} diff --git a/src/symbolize/mod.rs b/src/symbolize/mod.rs index 507f6204..c051ec8f 100644 --- a/src/symbolize/mod.rs +++ b/src/symbolize/mod.rs @@ -465,10 +465,9 @@ pub fn clear_symbol_cache() { cfg_if::cfg_if! { if #[cfg(miri)] { - mod noop; - use self::noop::resolve as resolve_imp; - use self::noop::Symbol as SymbolImp; - #[allow(unused)] + mod miri; + use self::miri::resolve as resolve_imp; + use self::miri::Symbol as SymbolImp; unsafe fn clear_symbol_cache_imp() {} } else if #[cfg(all(windows, target_env = "msvc", not(target_vendor = "uwp")))] { mod dbghelp;