From: Aaron Hill Date: Sat, 10 Oct 2020 17:07:57 +0000 (-0400) Subject: Add an `fn_ptr` field to `MiriFrame` X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=be51e6bd07c10ff350350fe05f2888c4ce3a08a0;p=rust.git Add an `fn_ptr` field to `MiriFrame` The `backtrace-rs` crate can use this to implement `Frame::symbol_address`, which is used to skip frames above the call to `Backtrace::capture` on the stack. The function pointer will not be useable for comparison purposes if the function is generic, as CTFE creates a new function pointer for each cast of a (monomorphized) generic function. However, this already affects code running under Miri, and isn't a problem for `backtrace-rs` (which only casts a non-generic function). I've added logic to allow `MiriFrame` to have either 4 or 5 fields - if a 5th field is present, we write the function pointer to it. --- diff --git a/README.md b/README.md index ceaf993924e..747afb9c4e9 100644 --- a/README.md +++ b/README.md @@ -286,6 +286,10 @@ extern "Rust" { /// lineno: u32, /// // The column number currently being executed in `filename`, starting from '1'. /// colno: u32, + /// // The function pointer to the function currently being executed. + /// // This can be compared against function pointers obtained by + /// // casting a function (e.g. `my_fn as *mut ()`) + /// fn_ptr: *mut () /// } /// ``` /// diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index bd36587116a..9b396c71849 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -92,8 +92,18 @@ fn handle_miri_resolve_frame( throw_ub_format!("expected function pointer, found {:?}", ptr); }; - if dest.layout.layout.fields.count() != 4 { - throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 4 fields"); + // Reconstruct the original function pointer, + // which we pass to user code. + let mut fn_ptr = ptr; + fn_ptr.offset = Size::from_bytes(0); + let fn_ptr = Scalar::Ptr(fn_ptr); + + let num_fields = dest.layout.layout.fields.count(); + + if num_fields != 4 && num_fields != 5 { + // Always mention 5 fields, since the 4-field struct is only supported + // for backwards compatiblity. New code should declare 5 fields + throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 5 fields"); } let pos = BytePos(ptr.offset.bytes().try_into().unwrap()); @@ -122,6 +132,11 @@ fn handle_miri_resolve_frame( this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?; this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?; this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?; + + if num_fields == 5 { + this.write_scalar(fn_ptr, this.mplace_field(dest, 4)?.into())?; + } + Ok(()) } } diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.rs b/tests/compile-fail/backtrace/bad-backtrace-decl.rs index b9f1c779ae2..23379992d5e 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-decl.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-decl.rs @@ -7,7 +7,7 @@ fn main() { let frames = unsafe { miri_get_backtrace(0) }; for frame in frames.into_iter() { unsafe { - miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 4 fields + miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 5 fields } } } diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index eaf29abfd9f..19169060038 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -2,20 +2,6 @@ // normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " // normalize-stderr-test "::<.*>" -> "" -extern "Rust" { - fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; - fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame; -} - -#[derive(Debug)] -#[repr(C)] -struct MiriFrame { - name: Box<[u8]>, - filename: Box<[u8]>, - lineno: u32, - colno: u32 -} - #[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::() } #[inline(never)] fn func_b() -> Box<[*mut ()]> { func_c() } @@ -34,6 +20,10 @@ fn main() { let name = String::from_utf8(miri_frame.name.into()).unwrap(); let filename = String::from_utf8(miri_frame.filename.into()).unwrap(); + if name == "func_a" { + assert_eq!(func_a as *mut (), miri_frame.fn_ptr); + } + // Print every frame to stderr. let out = format!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name); eprintln!("{}", out); @@ -45,3 +35,22 @@ fn main() { } } } + +// This goes at the bottom of the file so that we can change it +// without disturbing line numbers of the functions in the backtrace. + +extern "Rust" { + fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; + fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame; +} + +#[derive(Debug)] +#[repr(C)] +struct MiriFrame { + name: Box<[u8]>, + filename: Box<[u8]>, + lineno: u32, + colno: u32, + fn_ptr: *mut (), +} + diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index 02e7a7e1eaf..a5208221da4 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -1,8 +1,8 @@ -$DIR/backtrace-api.rs:27:59 (func_d) -$DIR/backtrace-api.rs:26:50 (func_c) -$DIR/backtrace-api.rs:20:53 (func_b) -$DIR/backtrace-api.rs:19:50 (func_a) -$DIR/backtrace-api.rs:31:18 (main) +$DIR/backtrace-api.rs:13:59 (func_d) +$DIR/backtrace-api.rs:12:50 (func_c) +$DIR/backtrace-api.rs:6:53 (func_b) +$DIR/backtrace-api.rs:5:50 (func_a) +$DIR/backtrace-api.rs:17:18 (main) RUSTLIB/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) RUSTLIB/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) diff --git a/tests/run-pass/backtrace-api.stdout b/tests/run-pass/backtrace-api.stdout index 90ab4bb96e6..175ff3b8294 100644 --- a/tests/run-pass/backtrace-api.stdout +++ b/tests/run-pass/backtrace-api.stdout @@ -1,5 +1,5 @@ -$DIR/backtrace-api.rs:27:59 (func_d) -$DIR/backtrace-api.rs:26:50 (func_c) -$DIR/backtrace-api.rs:20:53 (func_b::) -$DIR/backtrace-api.rs:19:50 (func_a) -$DIR/backtrace-api.rs:31:18 (main) +$DIR/backtrace-api.rs:13:59 (func_d) +$DIR/backtrace-api.rs:12:50 (func_c) +$DIR/backtrace-api.rs:6:53 (func_b::) +$DIR/backtrace-api.rs:5:50 (func_a) +$DIR/backtrace-api.rs:17:18 (main)