From e8dbc0c2c3bb5e5ecbc3dcb6db28e290f4c00dc7 Mon Sep 17 00:00:00 2001 From: David Lattimore Date: Wed, 20 Sep 2023 11:05:28 +1000 Subject: [PATCH] Use sysroot so that we can display rust sources in backtraces --- src/checker.rs | 4 ++++ src/location.rs | 13 +++++++++++++ src/main.rs | 22 ++++++++++++++++++---- src/symbol_graph.rs | 2 +- src/symbol_graph/backtrace.rs | 16 ++++++++++++++-- 5 files changed, 50 insertions(+), 7 deletions(-) diff --git a/src/checker.rs b/src/checker.rs index 03fc3cd..215d6b0 100644 --- a/src/checker.rs +++ b/src/checker.rs @@ -51,6 +51,7 @@ pub(crate) struct Checker { tmpdir: Arc, pub(crate) args: Arc, pub(crate) crate_index: Arc, + pub(crate) sysroot: Arc, /// Mapping from Rust source paths to the packages that contains them. Generally a source path /// will map to a single package, but in rare cases multiple packages could reference the same @@ -105,6 +106,7 @@ impl Checker { tmpdir: Arc, target_dir: PathBuf, args: Arc, + sysroot: Arc, crate_index: Arc, config_path: PathBuf, ) -> Self { @@ -122,6 +124,7 @@ impl Checker { timings, backtracers: Default::default(), outstanding_linker_invocations: Default::default(), + sysroot, } } @@ -577,6 +580,7 @@ mod tests { Arc::new(TempDir::new(None).unwrap()), PathBuf::default(), Arc::new(Args::default()), + Arc::from(Path::new("")), Arc::new(CrateIndex::default()), PathBuf::default(), ) diff --git a/src/location.rs b/src/location.rs index 0bb4ddd..5954331 100644 --- a/src/location.rs +++ b/src/location.rs @@ -31,6 +31,19 @@ impl SourceLocation { pub(crate) fn column(&self) -> Option { self.column } + + pub(crate) fn with_sysroot(&self, sysroot: &Path) -> Self { + if !self.filename.starts_with("/rustc/") { + return self.clone(); + } + let mut filename = sysroot.join("lib/rustlib/src/rust"); + filename.extend(self.filename.iter().skip(3)); + Self { + filename: Arc::from(filename.as_path()), + line: self.line, + column: self.column, + } + } } impl Display for SourceLocation { diff --git a/src/main.rs b/src/main.rs index 9ffa798..3e19ad7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,12 +34,12 @@ mod tmpdir; mod ui; mod unsafe_checker; +use crate::proxy::subprocess::PROXY_BIN_ARG; use anyhow::anyhow; use anyhow::bail; use anyhow::Context; use anyhow::Result; use checker::Checker; -use clap::builder::OsStr; use clap::Parser; use clap::Subcommand; use crate_index::CrateIndex; @@ -61,8 +61,6 @@ use std::sync::Mutex; use std::thread::JoinHandle; use summary::SummaryOptions; use symbol_graph::ScanOutputs; - -use crate::proxy::subprocess::PROXY_BIN_ARG; use tmpdir::TempDir; #[derive(Parser, Debug, Clone, Default)] @@ -163,7 +161,11 @@ pub(crate) struct ProxyBinOptions { fn main() -> Result<()> { proxy::subprocess::handle_wrapped_binaries()?; - if std::env::args_os().nth(1).as_deref() == Some(&OsStr::from(PROXY_BIN_ARG)) { + if std::env::args_os() + .nth(1) + .map(|arg| arg == PROXY_BIN_ARG) + .unwrap_or(false) + { // If we get here and the call to handle_wrapped_binaries above didn't diverge, then either // a user invoked a bin wrapper directly, or we've been invoked when we're already inside a // cackle sandbox. In either case, we just run the original binary directly. @@ -219,6 +221,7 @@ impl Cackle { tmpdir.clone(), target_dir.clone(), args.clone(), + determine_sysroot(&root_path)?, crate_index.clone(), config_path.clone(), ))); @@ -447,6 +450,17 @@ impl Cackle { } } +fn determine_sysroot(root_path: &PathBuf) -> Result> { + let output = std::process::Command::new("rustc") + .current_dir(root_path) + .arg("--print") + .arg("sysroot") + .output() + .context("Failed to run `rustc --print sysroot`")?; + let stdout = std::str::from_utf8(&output.stdout).context("rust sysroot isn't UTF-8")?; + Ok(Arc::from(Path::new(stdout.trim()))) +} + #[derive(Default)] struct CheckState { graph_outputs: Option, diff --git a/src/symbol_graph.rs b/src/symbol_graph.rs index 4f0fffc..eeda5b9 100644 --- a/src/symbol_graph.rs +++ b/src/symbol_graph.rs @@ -139,7 +139,7 @@ pub(crate) fn scan_objects( .with_context(|| format!("Failed to read `{}`", link_info.output_file.display()))?; checker.timings.add_timing(start, "Read bin file"); - let mut backtracer = Backtracer::default(); + let mut backtracer = Backtracer::new(checker.sysroot.clone()); let outputs = scan_object_with_bin_bytes(&file_bytes, checker, &mut backtracer, link_info, paths)?; diff --git a/src/symbol_graph/backtrace.rs b/src/symbol_graph/backtrace.rs index b4e4cfa..ffca248 100644 --- a/src/symbol_graph/backtrace.rs +++ b/src/symbol_graph/backtrace.rs @@ -6,13 +6,16 @@ use fxhash::FxHashMap; use fxhash::FxHashSet; use gimli::Dwarf; use std::fmt::Display; +use std::path::Path; +use std::sync::Arc; -#[derive(Default)] pub(crate) struct Backtracer { /// A map from symbol addresses in the binary to a list of relocations pointing to that address. back_references: FxHashMap>, bin_bytes: Vec, + + sysroot: Arc, } #[derive(Debug, PartialEq, Eq)] @@ -23,6 +26,14 @@ pub(crate) struct Frame { } impl Backtracer { + pub(crate) fn new(sysroot: Arc) -> Self { + Self { + sysroot, + back_references: Default::default(), + bin_bytes: Default::default(), + } + } + /// Declare a reference from `bin_location` to `target_address`. pub(crate) fn add_reference(&mut self, bin_location: BinLocation, target_address: u64) { self.back_references @@ -68,7 +79,8 @@ impl Backtracer { .unwrap_or_else(|| "??".to_owned()); let source_location = frame .location - .and_then(|location| SourceLocation::try_from(&location).ok()); + .and_then(|location| SourceLocation::try_from(&location).ok()) + .map(|location| location.with_sysroot(&self.sysroot)); if first { first = false; } else {