-
Notifications
You must be signed in to change notification settings - Fork 348
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR adds two new Miri-defined extern functions: `miri_get_backtrace` and `miri_resolve_frame`, which are documented in the README. Together, they allow obtaining a backtrace for the currently executing program. I've added a test showing how these APIs are used. I've also prepared a companion PR `backtrace-rs`, which will allow `backtrace::Backtrace::new()` to work automatically under Miri. Once these two PRs are merged, we will be able to print backtraces from the normal Rust panic hook (since libstd is now using backtrace-rs). A few notes: * Resolving the backtrace frames is *very* slow - you can actually see each line being printed out one at a time. Some local testing showed that this is not (primrary) caused by resolving a `Span` - it seems to be just Miri being slow. * For the first time, we now interact directly with a user-defined struct (instead of just executing the user-provided MIR that manipulates the struct). To allow for future changes, I've added a 'version' parameter (currently required to be 0). This should allow us to change the `MiriFrame` struct should the need ever arise. * I used the approach suggested by @oli-obk - a returned backtrace pointer consists of a base function allocation, with the 'offset' used to encode the `Span.lo`. This allows losslessly reconstructing the location information in `miri_resolve_frame`. * There are a few quirks on the `backtrace-rs` side: * `backtrace-rs` calls `getcwd()` by default to try to simplify the filename. This results in an isolation error by default, which could be annoying when printing a backtrace from libstd. * `backtrace-rs` tries to remove 'internal' frames (everything between the call to `Backtrace::new()` and the internal API call made by backtrace-rs) by comparing the returned frame pointer value to a Rust function pointer. This doesn't work due to the way we construct the frame pointers passed to the caller. We could attempt to support this kind of comparison, or just add a `#[cfg(miri)]` and ignore the frames ourselves.
- Loading branch information
Showing
7 changed files
with
178 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
extern "Rust" { | ||
fn miri_get_backtrace() -> Box<[*mut ()]>; | ||
fn miri_resolve_frame(version: u8, ptr: *mut ()); | ||
} | ||
|
||
fn main() { | ||
let frames = unsafe { miri_get_backtrace() }; | ||
for frame in frames.into_iter() { | ||
unsafe { | ||
miri_resolve_frame(0, *frame); //~ ERROR Undefined Behavior: Bad declaration of miri_resolve_frame - should return a struct with 4 fields | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
extern "Rust" { | ||
fn miri_resolve_frame(version: u8, ptr: *mut ()); | ||
} | ||
|
||
fn main() { | ||
unsafe { | ||
miri_resolve_frame(0, 0 as *mut _); //~ ERROR Undefined Behavior: Expected a pointer | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
extern "Rust" { | ||
fn miri_resolve_frame(version: u8, ptr: *mut ()); | ||
} | ||
|
||
fn main() { | ||
unsafe { | ||
miri_resolve_frame(1, 0 as *mut _); //~ ERROR Undefined Behavior: Unknown `miri_resolve_frame` version 1 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// normalize-stderr-test ".*rustlib" -> "RUSTLIB" | ||
|
||
extern "Rust" { | ||
fn miri_get_backtrace() -> Box<[*mut ()]>; | ||
fn miri_resolve_frame(version: u8, ptr: *mut ()) -> MiriFrame; | ||
} | ||
|
||
#[derive(Debug)] | ||
struct MiriFrame { | ||
name: Box<[u8]>, | ||
filename: Box<[u8]>, | ||
lineno: u32, | ||
colno: u32 | ||
} | ||
|
||
fn main() { | ||
let frames = unsafe { miri_get_backtrace() }; | ||
for frame in frames.into_iter() { | ||
let miri_frame = unsafe { miri_resolve_frame(0, *frame) }; | ||
let name = String::from_utf8(miri_frame.name.into()).unwrap(); | ||
let filename = String::from_utf8(miri_frame.filename.into()).unwrap(); | ||
eprintln!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
$DIR/backtrace-api.rs:17:27 (main) | ||
RUSTLIB/src/rust/library/core/src/ops/function.rs:227:5 (<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())) | ||
RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:137:18 (std::sys_common::backtrace::__rust_begin_short_backtrace::<fn(), ()>) | ||
RUSTLIB/src/rust/library/std/src/rt.rs:66:18 (std::rt::lang_start::<()>::{{closure}}#0) | ||
RUSTLIB/src/rust/library/core/src/ops/function.rs:259:13 (std::ops::function::impls::<impl std::ops::FnOnce<()> for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once) | ||
RUSTLIB/src/rust/library/std/src/panicking.rs:381:40 (std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) | ||
RUSTLIB/src/rust/library/std/src/panicking.rs:345:19 (std::panicking::r#try::<i32, &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>) | ||
RUSTLIB/src/rust/library/std/src/panic.rs:382:14 (std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) | ||
RUSTLIB/src/rust/library/std/src/rt.rs:51:25 (std::rt::lang_start_internal) | ||
RUSTLIB/src/rust/library/std/src/rt.rs:65:5 (std::rt::lang_start::<()>) |