Skip to content

Commit 085ee70

Browse files
committed
Add support for Miri backtraces
Companion to rust-lang/miri#1559
1 parent 37ec940 commit 085ee70

File tree

4 files changed

+140
-7
lines changed

4 files changed

+140
-7
lines changed

src/backtrace/miri.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
use std::ffi::c_void;
2+
use std::string::String;
3+
use std::vec::Vec;
4+
use std::boxed::Box;
5+
6+
extern "Rust" {
7+
fn miri_get_backtrace() -> Box<[*mut ()]>;
8+
fn miri_resolve_frame(version: u8, ptr: *mut ()) -> MiriFrame;
9+
}
10+
11+
#[derive(Debug)]
12+
struct MiriData {
13+
frames: Vec<*mut c_void>
14+
}
15+
16+
#[derive(Debug, Clone)]
17+
pub struct MiriFrame {
18+
pub name: Box<[u8]>,
19+
pub filename: Box<[u8]>,
20+
pub lineno: u32,
21+
pub colno: u32,
22+
}
23+
24+
#[derive(Debug, Clone)]
25+
pub struct Frame {
26+
pub addr: *mut c_void,
27+
pub inner: MiriFrame
28+
}
29+
30+
// Miri is single threaded, and the raw
31+
// pointer isn't really a pointer (it's a magic value
32+
// returned by Miri)
33+
unsafe impl Send for Frame {}
34+
unsafe impl Sync for Frame {}
35+
36+
impl Frame {
37+
pub fn ip(&self) -> *mut c_void {
38+
self.addr
39+
}
40+
41+
pub fn sp(&self) -> *mut c_void {
42+
std::ptr::null_mut()
43+
}
44+
45+
pub fn symbol_address(&self) -> *mut c_void {
46+
self.addr
47+
}
48+
49+
pub fn module_base_address(&self) -> Option<*mut c_void> {
50+
None
51+
}
52+
}
53+
54+
pub fn trace<F: FnMut(&super::Frame) -> bool>(cb: F) {
55+
// Miri is single threaded
56+
unsafe { trace_unsynchronized(cb) };
57+
}
58+
59+
60+
pub fn resolve_addr(ptr: *mut c_void) -> Frame {
61+
let frame: MiriFrame = unsafe { miri_resolve_frame(0, ptr as *mut ()) };
62+
Frame {
63+
addr: ptr,
64+
inner: frame
65+
}
66+
}
67+
68+
pub unsafe fn trace_unsynchronized<F: FnMut(&super::Frame) -> bool>(mut cb: F) {
69+
let frames = miri_get_backtrace();
70+
for ptr in frames.iter() {
71+
let frame = resolve_addr(*ptr as *mut c_void);
72+
cb(&super::Frame {
73+
inner: frame
74+
});
75+
}
76+
}

src/backtrace/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,12 @@ impl fmt::Debug for Frame {
126126
}
127127

128128
cfg_if::cfg_if! {
129+
// This needs to come first, to ensure that
130+
// Miri takes priority over the host platform
129131
if #[cfg(miri)] {
130-
mod noop;
131-
use self::noop::trace as trace_imp;
132-
pub(crate) use self::noop::Frame as FrameImp;
132+
pub(crate) mod miri;
133+
use self::miri::trace as trace_imp;
134+
pub(crate) use self::miri::Frame as FrameImp;
133135
} else if #[cfg(
134136
any(
135137
all(

src/symbolize/miri.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use core::marker::PhantomData;
2+
use core::ffi::c_void;
3+
4+
use crate::symbolize::{ResolveWhat, SymbolName};
5+
use crate::backtrace::miri::{resolve_addr, Frame};
6+
use crate::types::BytesOrWideString;
7+
8+
9+
pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) {
10+
let sym = match what {
11+
ResolveWhat::Address(addr) => Symbol {
12+
inner: resolve_addr(addr),
13+
_unused: PhantomData
14+
},
15+
ResolveWhat::Frame(frame) => {
16+
Symbol {
17+
inner: frame.inner.clone(),
18+
_unused: PhantomData
19+
}
20+
}
21+
};
22+
cb(&super::Symbol { inner: sym })
23+
}
24+
25+
26+
pub struct Symbol<'a> {
27+
inner: Frame,
28+
_unused: PhantomData<&'a ()>
29+
}
30+
31+
impl<'a> Symbol<'a> {
32+
pub fn name(&self) -> Option<SymbolName> {
33+
Some(SymbolName::new(&self.inner.inner.name))
34+
}
35+
36+
pub fn addr(&self) -> Option<*mut c_void> {
37+
Some(self.inner.addr)
38+
}
39+
40+
pub fn filename_raw(&self) -> Option<BytesOrWideString> {
41+
Some(BytesOrWideString::Bytes(&self.inner.inner.filename))
42+
}
43+
44+
pub fn lineno(&self) -> Option<u32> {
45+
Some(self.inner.inner.lineno)
46+
}
47+
48+
pub fn colno(&self) -> Option<u32> {
49+
Some(self.inner.inner.colno)
50+
}
51+
52+
pub fn filename(&self) -> Option<&::std::path::Path> {
53+
use std::path::Path;
54+
Some(Path::new(std::str::from_utf8(&self.inner.inner.filename).unwrap()))
55+
}
56+
}

src/symbolize/mod.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -465,10 +465,9 @@ pub fn clear_symbol_cache() {
465465

466466
cfg_if::cfg_if! {
467467
if #[cfg(miri)] {
468-
mod noop;
469-
use self::noop::resolve as resolve_imp;
470-
use self::noop::Symbol as SymbolImp;
471-
#[allow(unused)]
468+
mod miri;
469+
use self::miri::resolve as resolve_imp;
470+
use self::miri::Symbol as SymbolImp;
472471
unsafe fn clear_symbol_cache_imp() {}
473472
} else if #[cfg(all(windows, target_env = "msvc", not(target_vendor = "uwp")))] {
474473
mod dbghelp;

0 commit comments

Comments
 (0)