diff --git a/Cargo.lock b/Cargo.lock index b6784840c8c2b..b39d6b3c17bdc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -300,15 +300,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - [[package]] name = "bitflags" version = "2.10.0" @@ -2105,18 +2096,19 @@ dependencies = [ [[package]] name = "ipc-channel" -version = "0.20.2" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93600b5616c2d075f8af8dbd23c1d69278c5d24e4913d220cbc60b14c95c180" +checksum = "347ef783e380784658248bdb0b87ca1293e3e3df3fc7dee061e129aa5f013d61" dependencies = [ - "bincode", "crossbeam-channel", - "fnv", "libc", "mio", + "postcard", "rand 0.9.2", - "serde", + "rustc-hash 2.1.1", + "serde_core", "tempfile", + "thiserror 2.0.17", "uuid", "windows 0.61.3", ] diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index 00794371d50c6..ccc524c577dd4 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -80,15 +80,6 @@ dependencies = [ "windows-link 0.2.1", ] -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - [[package]] name = "bitflags" version = "2.11.1" @@ -262,6 +253,15 @@ dependencies = [ "cc", ] +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.18", +] + [[package]] name = "codespan-reporting" version = "0.13.1" @@ -460,6 +460,18 @@ dependencies = [ "syn", ] +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "encode_unicode" version = "1.0.0" @@ -504,12 +516,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "foldhash" version = "0.1.5" @@ -805,18 +811,19 @@ dependencies = [ [[package]] name = "ipc-channel" -version = "0.20.2" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93600b5616c2d075f8af8dbd23c1d69278c5d24e4913d220cbc60b14c95c180" +checksum = "347ef783e380784658248bdb0b87ca1293e3e3df3fc7dee061e129aa5f013d61" dependencies = [ - "bincode", "crossbeam-channel", - "fnv", "libc", "mio", + "postcard", "rand 0.9.4", - "serde", + "rustc-hash 2.1.2", + "serde_core", "tempfile", + "thiserror 2.0.18", "uuid", "windows", ] @@ -982,7 +989,7 @@ dependencies = [ "memmap2", "parking_lot", "perf-event-open-sys", - "rustc-hash", + "rustc-hash 1.1.0", "smallvec", ] @@ -1192,6 +1199,18 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + [[package]] name = "potential_utf" version = "0.1.5" @@ -1366,6 +1385,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + [[package]] name = "rustc_version" version = "0.4.1" diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index 7d7770eddcbe8..a08e9210028d6 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -38,7 +38,7 @@ serde = { version = "1.0.219", features = ["derive"], optional = true } [target.'cfg(target_os = "linux")'.dependencies] nix = { version = "0.30.1", features = ["mman", "ptrace", "signal"], optional = true } -ipc-channel = { version = "0.20.0", optional = true } +ipc-channel = { version = "0.22.0", optional = true } capstone = { version = "0.14", features = ["arch_x86", "full"], default-features = false, optional = true} [target.'cfg(all(target_os = "linux", target_pointer_width = "64", target_endian = "little"))'.dependencies] diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index 8a4d09b8348bf..f58cec827cf5d 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -342,7 +342,7 @@ pub fn phase_rustc(args: impl Iterator, phase: RustcPhase) { .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); let target_crate = is_target_crate(); - let store_json = |info: CrateRunInfo| { + let store_json = |info: &CrateRunInfo| { if get_arg_flag_value("--emit").unwrap_or_default().split(',').any(|e| e == "dep-info") { // Create a stub .d file to stop Cargo from "rebuilding" the crate: // https://github.com/rust-lang/miri/issues/1724#issuecomment-787115693 @@ -383,9 +383,9 @@ pub fn phase_rustc(args: impl Iterator, phase: RustcPhase) { // like we want them. // Instead of compiling, we write JSON into the output file with all the relevant command-line flags // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. - let env = CrateRunEnv::collect(args, inside_rustdoc); + let info = CrateRunInfo::collect(args, inside_rustdoc); - store_json(CrateRunInfo::RunWith(env.clone())); + store_json(&info); // Rustdoc expects us to exit with an error code if the test is marked as `compile_fail`, // just creating the JSON file is not enough: we need to detect syntax errors, @@ -395,7 +395,8 @@ pub fn phase_rustc(args: impl Iterator, phase: RustcPhase) { // Ensure --emit argument for a check-only build is present. if let Some(val) = - ArgFlagValueIter::from_str_iter(env.args.iter().map(|s| s as &str), "--emit").next() + ArgFlagValueIter::from_str_iter(info.args.iter().map(|s| s as &str), "--emit") + .next() { // For `no_run` tests, rustdoc passes a `--emit` flag; make sure it has the right shape. assert_eq!(val, "metadata"); @@ -405,7 +406,7 @@ pub fn phase_rustc(args: impl Iterator, phase: RustcPhase) { } // Alter the `-o` parameter so that it does not overwrite the JSON file we stored above. - let mut args = env.args; + let mut args = info.args; for i in 0..args.len() { if args[i] == "-o" { args[i + 1].push_str(".miri"); @@ -418,23 +419,22 @@ pub fn phase_rustc(args: impl Iterator, phase: RustcPhase) { if verbose > 0 { eprintln!( "[cargo-miri rustc inside rustdoc] captured input:\n{}", - std::str::from_utf8(&env.stdin).unwrap() + std::str::from_utf8(&info.stdin).unwrap() ); eprintln!("[cargo-miri rustc inside rustdoc] going to run:\n{cmd:?}"); } - exec_with_pipe(cmd, &env.stdin); + exec_with_pipe(cmd, &info.stdin); } return; } + // Unit tests for `proc-macro` crates are always built for the host so they cannot run in Miri. if runnable_crate && get_arg_flag_values("--extern").any(|krate| krate == "proc_macro") { - // This is a "runnable" `proc-macro` crate (unit tests). We do not support - // interpreting that under Miri now, so we write a JSON file to (display a - // helpful message and) skip it in the runner phase. - store_json(CrateRunInfo::SkipProcMacroTest); - return; + // Ideally we'd entirely skip them... but we have no good way of doing that here. + // So we run the tests natively on the host instead. + eprintln!("warning: unit tests of `proc-macro` crates are executed outside Miri"); } let mut cmd = miri(); @@ -537,18 +537,9 @@ pub fn phase_runner(mut binary_args: impl Iterator, phase: Runner let file = BufReader::new(file); let binary_args = binary_args.collect::>(); - let info = serde_json::from_reader(file).unwrap_or_else(|_| { + let info: CrateRunInfo = serde_json::from_reader(file).unwrap_or_else(|_| { show_error!("file {:?} contains outdated or invalid JSON; try `cargo clean`", binary) }); - let info = match info { - CrateRunInfo::RunWith(info) => info, - CrateRunInfo::SkipProcMacroTest => { - eprintln!( - "Running unit tests of `proc-macro` crates is not currently supported by Miri." - ); - return; - } - }; let mut cmd = miri(); @@ -631,10 +622,10 @@ pub fn phase_rustdoc(args: impl Iterator) { let mut cmd = Command::new(rustdoc); cmd.args(args); - // Doctests of `proc-macro` crates (and their dependencies) are always built for the host, - // so we are not able to run them in Miri. + // Documentation tests of `proc-macro` crates are always built for the host, so we are not able + // to run them in Miri. if get_arg_flag_values("--crate-type").any(|crate_type| crate_type == "proc-macro") { - eprintln!("Running doctests of `proc-macro` crates is not currently supported by Miri."); + eprintln!("warning: doc tests of `proc-macro` crates are not supported by Miri"); return; } diff --git a/src/tools/miri/cargo-miri/src/util.rs b/src/tools/miri/cargo-miri/src/util.rs index 1952435c59977..6d19830e71d44 100644 --- a/src/tools/miri/cargo-miri/src/util.rs +++ b/src/tools/miri/cargo-miri/src/util.rs @@ -22,9 +22,9 @@ macro_rules! show_error { } pub(crate) use show_error; -/// The information to run a crate with the given environment. -#[derive(Clone, Serialize, Deserialize)] -pub struct CrateRunEnv { +/// The information Miri needs to run a crate. Stored as JSON when the crate is "compiled". +#[derive(Serialize, Deserialize)] +pub struct CrateRunInfo { /// The command-line arguments. pub args: Vec, /// The environment. @@ -35,7 +35,7 @@ pub struct CrateRunEnv { pub stdin: Vec, } -impl CrateRunEnv { +impl CrateRunInfo { /// Gather all the information we need. pub fn collect(args: impl Iterator, capture_stdin: bool) -> Self { let args = args.collect(); @@ -47,20 +47,9 @@ impl CrateRunEnv { std::io::stdin().lock().read_to_end(&mut stdin).expect("cannot read stdin"); } - CrateRunEnv { args, env, current_dir, stdin } + CrateRunInfo { args, env, current_dir, stdin } } -} -/// The information Miri needs to run a crate. Stored as JSON when the crate is "compiled". -#[derive(Serialize, Deserialize)] -pub enum CrateRunInfo { - /// Run it with the given environment. - RunWith(CrateRunEnv), - /// Skip it as Miri does not support interpreting such kind of crates. - SkipProcMacroTest, -} - -impl CrateRunInfo { pub fn store(&self, filename: &Path) { let file = File::create(filename) .unwrap_or_else(|_| show_error!("cannot create `{}`", filename.display())); diff --git a/src/tools/miri/priroda/Cargo.lock b/src/tools/miri/priroda/Cargo.lock index 2eb63f8a16b3b..7d46f75d2fab7 100644 --- a/src/tools/miri/priroda/Cargo.lock +++ b/src/tools/miri/priroda/Cargo.lock @@ -80,15 +80,6 @@ dependencies = [ "windows-link 0.2.1", ] -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - [[package]] name = "bitflags" version = "2.11.1" @@ -225,6 +216,15 @@ dependencies = [ "inout", ] +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.18", +] + [[package]] name = "color-eyre" version = "0.6.5" @@ -339,6 +339,18 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "encode_unicode" version = "1.0.0" @@ -383,12 +395,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "foldhash" version = "0.1.5" @@ -540,18 +546,19 @@ dependencies = [ [[package]] name = "ipc-channel" -version = "0.20.2" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93600b5616c2d075f8af8dbd23c1d69278c5d24e4913d220cbc60b14c95c180" +checksum = "347ef783e380784658248bdb0b87ca1293e3e3df3fc7dee061e129aa5f013d61" dependencies = [ - "bincode", "crossbeam-channel", - "fnv", "libc", "mio", + "postcard", "rand 0.9.4", - "serde", + "rustc-hash 2.1.2", + "serde_core", "tempfile", + "thiserror 2.0.18", "uuid", "windows", ] @@ -667,7 +674,7 @@ dependencies = [ "memmap2", "parking_lot", "perf-event-open-sys", - "rustc-hash", + "rustc-hash 1.1.0", "smallvec", ] @@ -840,6 +847,18 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -1014,6 +1033,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + [[package]] name = "rustc_version" version = "0.4.1" diff --git a/src/tools/miri/priroda/README.md b/src/tools/miri/priroda/README.md index e0dafd2685504..b9d946e08e544 100644 --- a/src/tools/miri/priroda/README.md +++ b/src/tools/miri/priroda/README.md @@ -8,6 +8,7 @@ Current focus: - single-threaded stepping with Miri's interpreter - source-location output after stepping - source-location breakpoint prototype +- source-local listing prototype ## Setup @@ -59,9 +60,11 @@ RUSTC_BLESS=1 cargo test | Command | Description | |---|---| -| Enter, `s`, `step` | Execute one Miri interpreter step. | +| Enter, `si`, `stepi` | Execute one Miri interpreter step. | +| `s`, `step` | Step until the displayed source location changes. | | `c`, `continue` | Continue until the program finishes or reaches a breakpoint. | | `b :`, `break :` | Add a source-location breakpoint. | +| `l`, `locals` | List source-level locals in the current frame by name. | | `q`, `quit` | Exit Priroda. | EOF also exits Priroda cleanly. diff --git a/src/tools/miri/priroda/src/main.rs b/src/tools/miri/priroda/src/main.rs index 6ac0ce761dcb0..2739b041b0b48 100644 --- a/src/tools/miri/priroda/src/main.rs +++ b/src/tools/miri/priroda/src/main.rs @@ -71,7 +71,7 @@ impl rustc_driver::Callbacks for PrirodaCompilerCalls { let ecx = create_ecx(tcx); let mut session = PrirodaContext::new(ecx); - let cli = CLI {}; + let cli = Cli {}; let result = cli.run_cli_loop(&mut session); match result.report_err() { @@ -133,6 +133,10 @@ struct PrirodaContext<'tcx> { enum ResumeMode { /// Stop at the next visible MIR instruction. MirInstruction, + /// Stop at the next source line + /// + /// Take `Option` because some cases current state has no mapped to source code location + SourceLine(Option<(PathBuf, usize)>), /// Continue until reaching a breakpoint. Continue, } @@ -159,10 +163,31 @@ impl<'tcx> PrirodaContext<'tcx> { Self { ecx, breakpoints: HashMap::new(), current_location: None, last_location: None } } + fn local_path(&self, location: &SourceLocation) -> Option { + let source_map = self.ecx.tcx.sess.source_map(); + location.local_path(source_map) + } + + fn current_source_position(&self) -> Option<(PathBuf, usize)> { + let location = self.current_location.as_ref()?; + Some((self.local_path(location)?, location.line)) + } + + // Used to treat `continue` like a source-level step for breakpoint checks: + // several MIR locations can point at one source line, but they should only + // report that source breakpoint once. + fn last_source_position(&self) -> Option<(PathBuf, usize)> { + let location = self.last_location.as_ref()?; + Some((self.local_path(location)?, location.line)) + } + /// Step to the next visible MIR instruction. - fn step(&mut self) -> InterpResult<'tcx, StepResult> { + fn stepi(&mut self) -> InterpResult<'tcx, StepResult> { self.resume(ResumeMode::MirInstruction) } + fn step(&mut self) -> InterpResult<'tcx, StepResult> { + self.resume(ResumeMode::SourceLine(self.current_source_position())) + } /// Continue execution until reaching a breakpoint or propagating termination. fn continue_execution(&mut self) -> InterpResult<'tcx, StepResult> { @@ -202,6 +227,26 @@ impl<'tcx> PrirodaContext<'tcx> { { return interp_ok(StepResult::Step); } + + ResumeMode::SourceLine(ref prev_location) => { + match (prev_location, &self.current_location) { + // We started from an unmapped source location. Stop at the first mapped source location we can show to the user. + (None, Some(_)) => return interp_ok(StepResult::Step), + + (Some((prev_path, prev_line)), Some(current_location)) => { + if let Some(current_path) = self.local_path(current_location) { + // A source step stops when the visible source position changes to a different file or line. + if *prev_path != current_path || *prev_line != current_location.line + { + return interp_ok(StepResult::Step); + } + } + } + + _ => {} + } + } + ResumeMode::MirInstruction | ResumeMode::Continue => {} } } @@ -248,21 +293,20 @@ impl<'tcx> PrirodaContext<'tcx> { } fn is_at_breakpoint(&self) -> bool { - // FIXME: avoid repeated stops when one source line maps to multiple MIR statements. - let Some(location) = &self.current_location else { + let Some(bp) = self.current_breakpoint() else { return false; }; - let source_map = self.ecx.tcx.sess.source_map(); - let Some(path) = &location.local_path(source_map) else { - return false; - }; + // If the previous interpreter step had the same source position, this + // is another MIR location for the breakpoint we just reported. + self.last_source_position().as_ref() != Some(&bp) + } - let lines = match self.breakpoints.get(path) { - Some(lines) => lines, - None => return false, - }; - lines.contains(&location.line) + fn current_breakpoint(&self) -> Option<(PathBuf, usize)> { + let (path, line) = self.current_source_position()?; + let lines = self.breakpoints.get(&path)?; + + if lines.contains(&line) { Some((path, line)) } else { None } } fn resolve_current_location(&self) -> Option { @@ -276,26 +320,41 @@ impl<'tcx> PrirodaContext<'tcx> { let source_map = self.ecx.tcx.sess.source_map(); let loc = source_map.lookup_char_pos(span.lo()); - Some(SourceLocation { span: span, line: loc.line }) + Some(SourceLocation { span, line: loc.line }) } fn run_command(&mut self, command: DebuggerCommand) -> InterpResult<'tcx, CommandResult> { match command { + DebuggerCommand::StepI => self.stepi().map(CommandResult::ExecutionStopped), DebuggerCommand::Step => self.step().map(CommandResult::ExecutionStopped), DebuggerCommand::Continue => self.continue_execution().map(CommandResult::ExecutionStopped), DebuggerCommand::Breakpoint(path, line) => interp_ok(CommandResult::BreakpointResult(self.set_breakpoint(path, line))), + DebuggerCommand::ListLocals => interp_ok(CommandResult::Locals(self.list_locals())), DebuggerCommand::TerminateSession => interp_ok(CommandResult::TerminateSession), } } + + /// Returns the names of all user-visible locals in the innermost stack frame. + /// + /// Uses `var_debug_info` from the MIR body, which is the same source that + /// DWARF debug info is built from, so the names match what the user wrote. + fn list_locals(&self) -> Vec { + let Some(frame) = self.ecx.active_thread_stack().last() else { + return Vec::new(); + }; + frame.body().var_debug_info.iter().map(|info| info.name.to_string()).collect() + } } enum DebuggerCommand { + StepI, Step, TerminateSession, Continue, Breakpoint(PathBuf, usize), + ListLocals, } enum BreakpointSetResult { @@ -307,14 +366,15 @@ enum BreakpointSetResult { enum CommandResult { ExecutionStopped(StepResult), BreakpointResult(BreakpointSetResult), + Locals(Vec), // FIXME: distinguish terminating the debugger session from disconnecting a // frontend and terminating the interpreted program once multiple frontends exist. TerminateSession, } -struct CLI; +struct Cli; -impl CLI { +impl Cli { pub fn run_cli_loop<'tcx>(&self, session: &mut PrirodaContext<'tcx>) -> InterpResult<'tcx> { loop { print!("(priroda) "); @@ -334,7 +394,7 @@ impl CLI { if matches!(result, StepResult::Breakpoint) { println!("Hit breakpoint"); } - self.print_location(&session); + self.print_location(session); } CommandResult::BreakpointResult(res) => match res { @@ -343,6 +403,14 @@ impl CLI { BreakpointSetResult::Duplicate => println!("Duplicate breakpoint"), }, + CommandResult::Locals(names) => + if names.is_empty() { + println!("no locals"); + } else { + for name in &names { + println!("{name}"); + } + }, CommandResult::TerminateSession => { println!("quitting"); return interp_ok(()); @@ -367,21 +435,24 @@ impl CLI { let args = parts.next().unwrap_or("").trim(); match command { - "" | "s" | "step" => Some(DebuggerCommand::Step), + // FIXME: empty line should repats last command user typed not exeute specific command. + "" | "si" | "stepi" => Some(DebuggerCommand::StepI), + "s" | "step" => Some(DebuggerCommand::Step), "q" | "quit" => Some(DebuggerCommand::TerminateSession), "c" | "continue" => Some(DebuggerCommand::Continue), "b" | "break" => self.parse_breakpoint(args), + "l" | "locals" => Some(DebuggerCommand::ListLocals), _ => None, } } fn print_location(&self, session: &PrirodaContext) { - let source_map = session.ecx.tcx.sess.source_map(); match &session.current_location { Some(location) => - if let Some(path) = location.local_path(source_map) { + if let Some(path) = session.local_path(location) { println!("{}:{}", path.display(), location.line); } else { + let source_map = session.ecx.tcx.sess.source_map(); println!("{}", source_map.span_to_diagnostic_string(location.span)); }, None => println!("no-location"), diff --git a/src/tools/miri/priroda/tests/ui/locals_in_function.rs b/src/tools/miri/priroda/tests/ui/locals_in_function.rs new file mode 100644 index 0000000000000..755b649f42299 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/locals_in_function.rs @@ -0,0 +1,7 @@ +// Verifies that the `locals` command lists the names of user-declared variables +// in the current stack frame. After stepping into `main` we should see `x` and `y`. +fn main() { + let x = 1_i32; + let y = true; + let _ = (x, y); +} diff --git a/src/tools/miri/priroda/tests/ui/locals_in_function.stdin b/src/tools/miri/priroda/tests/ui/locals_in_function.stdin new file mode 100644 index 0000000000000..31bbdb051a6e8 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/locals_in_function.stdin @@ -0,0 +1,4 @@ +break tests/ui/locals_in_function.rs:5 +continue +locals +quit diff --git a/src/tools/miri/priroda/tests/ui/locals_in_function.stdout b/src/tools/miri/priroda/tests/ui/locals_in_function.stdout new file mode 100644 index 0000000000000..ed5889f5836e7 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/locals_in_function.stdout @@ -0,0 +1,6 @@ +(priroda) breakpoint added: {MANIFEST_DIR}/tests/ui/locals_in_function.rs:5 +(priroda) Hit breakpoint +{MANIFEST_DIR}/tests/ui/locals_in_function.rs:5 +(priroda) x +y +(priroda) quitting diff --git a/src/tools/miri/priroda/tests/ui/locals_no_frame.rs b/src/tools/miri/priroda/tests/ui/locals_no_frame.rs new file mode 100644 index 0000000000000..c868045ddaa9f --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/locals_no_frame.rs @@ -0,0 +1,4 @@ +// Verifies that the `locals` command reports "no locals" when invoked before +// any user stack frame is active (i.e. immediately at startup, while the std +// runtime preamble is running). +fn main() {} diff --git a/src/tools/miri/priroda/tests/ui/locals_no_frame.stdin b/src/tools/miri/priroda/tests/ui/locals_no_frame.stdin new file mode 100644 index 0000000000000..380b346c27d9e --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/locals_no_frame.stdin @@ -0,0 +1,2 @@ +locals +quit diff --git a/src/tools/miri/priroda/tests/ui/locals_no_frame.stdout b/src/tools/miri/priroda/tests/ui/locals_no_frame.stdout new file mode 100644 index 0000000000000..3a4c983f0bb60 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/locals_no_frame.stdout @@ -0,0 +1,2 @@ +(priroda) no locals +(priroda) quitting diff --git a/src/tools/miri/priroda/tests/ui/repeated_same_line_breakpoint.rs b/src/tools/miri/priroda/tests/ui/repeated_same_line_breakpoint.rs index 4a1247ab37b4a..494e7f209699b 100644 --- a/src/tools/miri/priroda/tests/ui/repeated_same_line_breakpoint.rs +++ b/src/tools/miri/priroda/tests/ui/repeated_same_line_breakpoint.rs @@ -1,7 +1,8 @@ -// Documents the current repeated-stop behavior when multiple MIR locations map -// to the same source breakpoint line. -// This may look trivial, but a bunch of code runs in std before -// `main` is called, so we are ensuring that that all works. +// Verifies duplicate MIR locations on one source breakpoint line are skipped. +// The following line gives the second `continue` a later real breakpoint. +// This keeps the test from passing merely because the program finished. +// Keep the breakpoint line numbers in the .stdin file in sync with this file. fn main() { - let _value = 0; + let _first = 0; + let _second = 1; } diff --git a/src/tools/miri/priroda/tests/ui/repeated_same_line_breakpoint.stdin b/src/tools/miri/priroda/tests/ui/repeated_same_line_breakpoint.stdin index a179d469cc2ba..aaaf7479f641a 100644 --- a/src/tools/miri/priroda/tests/ui/repeated_same_line_breakpoint.stdin +++ b/src/tools/miri/priroda/tests/ui/repeated_same_line_breakpoint.stdin @@ -1,4 +1,5 @@ break tests/ui/repeated_same_line_breakpoint.rs:6 +break tests/ui/repeated_same_line_breakpoint.rs:7 continue continue quit diff --git a/src/tools/miri/priroda/tests/ui/repeated_same_line_breakpoint.stdout b/src/tools/miri/priroda/tests/ui/repeated_same_line_breakpoint.stdout index 27ba93d504ed4..1ab080cbfa9b1 100644 --- a/src/tools/miri/priroda/tests/ui/repeated_same_line_breakpoint.stdout +++ b/src/tools/miri/priroda/tests/ui/repeated_same_line_breakpoint.stdout @@ -1,6 +1,7 @@ (priroda) breakpoint added: {MANIFEST_DIR}/tests/ui/repeated_same_line_breakpoint.rs:6 +(priroda) breakpoint added: {MANIFEST_DIR}/tests/ui/repeated_same_line_breakpoint.rs:7 (priroda) Hit breakpoint {MANIFEST_DIR}/tests/ui/repeated_same_line_breakpoint.rs:6 (priroda) Hit breakpoint -{MANIFEST_DIR}/tests/ui/repeated_same_line_breakpoint.rs:6 +{MANIFEST_DIR}/tests/ui/repeated_same_line_breakpoint.rs:7 (priroda) quitting diff --git a/src/tools/miri/priroda/tests/ui/source_step_changes_line.stdin b/src/tools/miri/priroda/tests/ui/source_step_changes_line.stdin index 955048258c669..dd255f4abf43e 100644 --- a/src/tools/miri/priroda/tests/ui/source_step_changes_line.stdin +++ b/src/tools/miri/priroda/tests/ui/source_step_changes_line.stdin @@ -1,3 +1,3 @@ +si s -step quit diff --git a/src/tools/miri/priroda/tests/ui/source_step_changes_line.stdout b/src/tools/miri/priroda/tests/ui/source_step_changes_line.stdout index bd2d2487d316b..10cc3a5cf980b 100644 --- a/src/tools/miri/priroda/tests/ui/source_step_changes_line.stdout +++ b/src/tools/miri/priroda/tests/ui/source_step_changes_line.stdout @@ -1,3 +1,3 @@ (priroda) {RUSTC_SYSROOT}/lib/rustlib/src/rust/library/std/src/rt.rs:206 -(priroda) {RUSTC_SYSROOT}/lib/rustlib/src/rust/library/std/src/rt.rs:206 +(priroda) {RUSTC_SYSROOT}/lib/rustlib/src/rust/library/std/src/rt.rs:207 (priroda) quitting diff --git a/src/tools/miri/priroda/tests/ui/step_aliases.stdin b/src/tools/miri/priroda/tests/ui/step_aliases.stdin index 923b000e78e7e..0ad1ca7ec1038 100644 --- a/src/tools/miri/priroda/tests/ui/step_aliases.stdin +++ b/src/tools/miri/priroda/tests/ui/step_aliases.stdin @@ -1,4 +1,4 @@ -s -step +si +stepi quit diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 387bd8edd2196..4a2bfdb2cd558 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -029c9e18dd1f4668e1d42bb187c1c263dfe20093 +01f54e80e888b66d6486a3a95d481b87353016df diff --git a/src/tools/miri/src/shims/native_lib/trace/child.rs b/src/tools/miri/src/shims/native_lib/trace/child.rs index d7d9a591911a0..406c2916eb13e 100644 --- a/src/tools/miri/src/shims/native_lib/trace/child.rs +++ b/src/tools/miri/src/shims/native_lib/trace/child.rs @@ -2,7 +2,7 @@ use std::cell::RefCell; use std::ptr::NonNull; use std::rc::Rc; -use ipc_channel::ipc; +use ipc_channel::{TryRecvError, ipc}; use nix::sys::{mman, ptrace, signal}; use nix::unistd; use rustc_const_eval::interpret::{InterpResult, interp_ok}; @@ -140,8 +140,8 @@ impl Supervisor { .try_recv_timeout(std::time::Duration::from_secs(5)) .map_err(|e| { match e { - ipc::TryRecvError::IpcError(_) => (), - ipc::TryRecvError::Empty => + TryRecvError::IpcError(_) => (), + TryRecvError::Empty => panic!("Waiting for accesses from supervisor timed out!"), } }) diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py index 6b3b6343b8258..cfbe3098e54ff 100755 --- a/src/tools/miri/test-cargo-miri/run-test.py +++ b/src/tools/miri/test-cargo-miri/run-test.py @@ -172,7 +172,7 @@ def test_cargo_miri_test(): ) test("`cargo miri test` (proc-macro crate)", cargo_miri("test") + ["-p", "proc_macro_crate"], - "test.empty.ref", "test.proc-macro.stderr.ref", + "test.proc-macro.stdout.ref", "test.proc-macro.stderr.ref", ) test("`cargo miri test` (custom target dir)", cargo_miri("test") + ["--target-dir=custom-test"], diff --git a/src/tools/miri/test-cargo-miri/test.proc-macro.stderr.ref b/src/tools/miri/test-cargo-miri/test.proc-macro.stderr.ref index b95474208b27a..e5ff59eff3c67 100644 --- a/src/tools/miri/test-cargo-miri/test.proc-macro.stderr.ref +++ b/src/tools/miri/test-cargo-miri/test.proc-macro.stderr.ref @@ -1,2 +1,2 @@ -Running unit tests of `proc-macro` crates is not currently supported by Miri. -Running doctests of `proc-macro` crates is not currently supported by Miri. +warning: unit tests of `proc-macro` crates are executed outside Miri +warning: doc tests of `proc-macro` crates are not supported by Miri diff --git a/src/tools/miri/test-cargo-miri/test.proc-macro.stdout.ref b/src/tools/miri/test-cargo-miri/test.proc-macro.stdout.ref new file mode 100644 index 0000000000000..7326c0a25a069 --- /dev/null +++ b/src/tools/miri/test-cargo-miri/test.proc-macro.stdout.ref @@ -0,0 +1,5 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/tools/miri/tests/pass/both_borrows/c_variadics.rs b/src/tools/miri/tests/pass/both_borrows/c_variadics.rs index c3ec5de350bad..626022788814d 100644 --- a/src/tools/miri/tests/pass/both_borrows/c_variadics.rs +++ b/src/tools/miri/tests/pass/both_borrows/c_variadics.rs @@ -4,14 +4,13 @@ #![feature(c_variadic)] fn main() { - unsafe extern "C" fn write_with_first_arg( - ptr_to_val: *mut i32, - _hidden_mut_ref_to_val: ... - ) { + unsafe extern "C" fn write_with_first_arg(ptr_to_val: *mut i32, _hidden_mut_ref_to_val: ...) { // Retagging needs to be disabled for arguments // within the VaList. Otherwise, this write access // will be undefined behavior. - unsafe { *ptr_to_val = 32; } + unsafe { + *ptr_to_val = 32; + } } let mut val: i32 = 0; diff --git a/src/tools/miri/tests/pass/tree_borrows/slice_get_mut_no_implicit_write.rs b/src/tools/miri/tests/pass/tree_borrows/slice_get_mut_no_implicit_write.rs index 789f0a8b88ce6..4a177677cd9ac 100644 --- a/src/tools/miri/tests/pass/tree_borrows/slice_get_mut_no_implicit_write.rs +++ b/src/tools/miri/tests/pass/tree_borrows/slice_get_mut_no_implicit_write.rs @@ -24,9 +24,7 @@ fn borrowed_buf() { let ptr = unsafe { buf.as_mut() }.as_mut_ptr(); let _ = buf.capacity(); - unsafe { - ptr.write(42); - } + unsafe { ptr.write(42) }; } // A variant of the above that uses `index_mut` notation.