diff --git a/README.md b/README.md index ceaf993924..747afb9c4e 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 bd36587116..8cf7ac2075 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -92,8 +92,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 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 !(4..=5).contains(&num_fields) { + // Always mention 5 fields, since the 4-field struct + // is deprecated and slated for removal. + 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,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 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())?; + + // Support a 4-field struct for now - this is deprecated + // and slated for removal. + 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 b9f1c779ae..23379992d5 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 eaf29abfd9..1916906003 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 02e7a7e1ea..a5208221da 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 90ab4bb96e..175ff3b829 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)