Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Miri backtraces #372

Merged
merged 1 commit into from
Sep 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions src/backtrace/miri.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use std::boxed::Box;
use std::ffi::c_void;

extern "Rust" {
fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>;
fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame;
}

#[derive(Clone, Debug)]
#[repr(C)]
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,
}

// 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 {
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<F: FnMut(&super::Frame) -> bool>(cb: F) {
// SAFETY: Miri guarnatees 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: MiriFrame = unsafe { miri_resolve_frame(ptr as *mut (), 0) };
Frame {
addr: ptr,
inner: frame,
}
}

pub unsafe fn trace_unsynchronized<F: FnMut(&super::Frame) -> bool>(mut cb: F) {
let frames = miri_get_backtrace(0);
for ptr in frames.iter() {
let frame = resolve_addr(*ptr as *mut c_void);
cb(&super::Frame { inner: frame });
}
}
8 changes: 5 additions & 3 deletions src/backtrace/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
54 changes: 54 additions & 0 deletions src/symbolize/miri.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use core::ffi::c_void;
use core::marker::PhantomData;

use crate::backtrace::miri::{resolve_addr, Frame};
use crate::symbolize::{ResolveWhat, SymbolName};
use crate::types::BytesOrWideString;

pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn 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<SymbolName<'_>> {
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<BytesOrWideString<'_>> {
Some(BytesOrWideString::Bytes(&self.inner.inner.filename))
}

pub fn lineno(&self) -> Option<u32> {
Some(self.inner.inner.lineno)
}

pub fn colno(&self) -> Option<u32> {
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(),
))
}
}
7 changes: 3 additions & 4 deletions src/symbolize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down