1
Fork 0

Auto merge of #91779 - ridwanabdillahi:natvis, r=michaelwoerister

Add a new Rust attribute to support embedding debugger visualizers

Implemented [this RFC](https://github.com/rust-lang/rfcs/pull/3191) to add support for embedding debugger visualizers into a PDB.

Added a new attribute `#[debugger_visualizer]` and updated the `CrateMetadata` to store debugger visualizers for crate dependencies.

RFC: https://github.com/rust-lang/rfcs/pull/3191
This commit is contained in:
bors 2022-05-05 12:26:38 +00:00
commit a7d6768e3b
29 changed files with 554 additions and 76 deletions

View file

@ -5,7 +5,7 @@ use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::{ErrorGuaranteed, Handler};
use rustc_fs_util::fix_windows_verbatim_for_gcc;
use rustc_hir::def_id::CrateNum;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::SymbolExportKind;
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
@ -2099,8 +2099,14 @@ fn add_order_independent_options(
// Pass optimization flags down to the linker.
cmd.optimize();
let debugger_visualizer_paths = if sess.target.is_like_msvc {
collect_debugger_visualizers(tmpdir, sess, &codegen_results.crate_info)
} else {
Vec::new()
};
// Pass debuginfo and strip flags down to the linker.
cmd.debuginfo(strip_value(sess));
cmd.debuginfo(strip_value(sess), &debugger_visualizer_paths);
// We want to prevent the compiler from accidentally leaking in any system libraries,
// so by default we tell linkers not to link to any default libraries.
@ -2119,6 +2125,47 @@ fn add_order_independent_options(
add_rpath_args(cmd, sess, codegen_results, out_filename);
}
// Write the debugger visualizer files for each crate to the temp directory and gather the file paths.
fn collect_debugger_visualizers(
tmpdir: &Path,
sess: &Session,
crate_info: &CrateInfo,
) -> Vec<PathBuf> {
let mut visualizer_paths = Vec::new();
let debugger_visualizers = &crate_info.debugger_visualizers;
let mut index = 0;
for (&cnum, visualizers) in debugger_visualizers {
let crate_name = if cnum == LOCAL_CRATE {
crate_info.local_crate_name.as_str()
} else {
crate_info.crate_name[&cnum].as_str()
};
for visualizer in visualizers {
let visualizer_out_file = tmpdir.join(format!("{}-{}.natvis", crate_name, index));
match fs::write(&visualizer_out_file, &visualizer.src) {
Ok(()) => {
visualizer_paths.push(visualizer_out_file.clone());
index += 1;
}
Err(error) => {
sess.warn(
format!(
"Unable to write debugger visualizer file `{}`: {} ",
visualizer_out_file.display(),
error
)
.as_str(),
);
}
};
}
}
visualizer_paths
}
/// # Native library linking
///
/// User-supplied library search paths (-L on the command line). These are the same paths used to

View file

@ -183,7 +183,7 @@ pub trait Linker {
fn optimize(&mut self);
fn pgo_gen(&mut self);
fn control_flow_guard(&mut self);
fn debuginfo(&mut self, strip: Strip);
fn debuginfo(&mut self, strip: Strip, debugger_visualizers: &[PathBuf]);
fn no_crt_objects(&mut self);
fn no_default_libraries(&mut self);
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]);
@ -611,7 +611,7 @@ impl<'a> Linker for GccLinker<'a> {
fn control_flow_guard(&mut self) {}
fn debuginfo(&mut self, strip: Strip) {
fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
// MacOS linker doesn't support stripping symbols directly anymore.
if self.sess.target.is_like_osx {
return;
@ -915,7 +915,7 @@ impl<'a> Linker for MsvcLinker<'a> {
self.cmd.arg("/guard:cf");
}
fn debuginfo(&mut self, strip: Strip) {
fn debuginfo(&mut self, strip: Strip, debugger_visualizers: &[PathBuf]) {
match strip {
Strip::None => {
// This will cause the Microsoft linker to generate a PDB file
@ -942,6 +942,13 @@ impl<'a> Linker for MsvcLinker<'a> {
}
}
}
// This will cause the Microsoft linker to embed .natvis info for all crates into the PDB file
for path in debugger_visualizers {
let mut arg = OsString::from("/NATVIS:");
arg.push(path);
self.cmd.arg(arg);
}
}
Strip::Debuginfo | Strip::Symbols => {
self.cmd.arg("/DEBUG:NONE");
@ -1124,7 +1131,7 @@ impl<'a> Linker for EmLinker<'a> {
fn control_flow_guard(&mut self) {}
fn debuginfo(&mut self, _strip: Strip) {
fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
// Preserve names or generate source maps depending on debug info
self.cmd.arg(match self.sess.opts.debuginfo {
DebugInfo::None => "-g0",
@ -1315,7 +1322,7 @@ impl<'a> Linker for WasmLd<'a> {
fn pgo_gen(&mut self) {}
fn debuginfo(&mut self, strip: Strip) {
fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
match strip {
Strip::None => {}
Strip::Debuginfo => {
@ -1450,7 +1457,7 @@ impl<'a> Linker for L4Bender<'a> {
fn pgo_gen(&mut self) {}
fn debuginfo(&mut self, strip: Strip) {
fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
match strip {
Strip::None => {}
Strip::Debuginfo => {
@ -1600,7 +1607,7 @@ impl<'a> Linker for PtxLinker<'a> {
self.cmd.arg("-L").arg(path);
}
fn debuginfo(&mut self, _strip: Strip) {
fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
self.cmd.arg("--debug");
}
@ -1699,7 +1706,7 @@ impl<'a> Linker for BpfLinker<'a> {
self.cmd.arg("-L").arg(path);
}
fn debuginfo(&mut self, _strip: Strip) {
fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
self.cmd.arg("--debug");
}

View file

@ -847,7 +847,13 @@ impl CrateInfo {
missing_lang_items: Default::default(),
dependency_formats: tcx.dependency_formats(()).clone(),
windows_subsystem,
debugger_visualizers: Default::default(),
};
let debugger_visualizers = tcx.debugger_visualizers(LOCAL_CRATE).clone();
if !debugger_visualizers.is_empty() {
info.debugger_visualizers.insert(LOCAL_CRATE, debugger_visualizers);
}
let lang_items = tcx.lang_items();
let crates = tcx.crates(());
@ -862,7 +868,9 @@ impl CrateInfo {
info.native_libraries
.insert(cnum, tcx.native_libraries(cnum).iter().map(Into::into).collect());
info.crate_name.insert(cnum, tcx.crate_name(cnum));
info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum).clone());
let used_crate_source = tcx.used_crate_source(cnum);
info.used_crate_source.insert(cnum, used_crate_source.clone());
if tcx.is_compiler_builtins(cnum) {
info.compiler_builtins = Some(cnum);
}
@ -883,6 +891,14 @@ impl CrateInfo {
let missing =
missing.iter().cloned().filter(|&l| lang_items::required(tcx, l)).collect();
info.missing_lang_items.insert(cnum, missing);
// Only include debugger visualizer files from crates that will be statically linked.
if used_crate_source.rlib.is_some() || used_crate_source.rmeta.is_some() {
let debugger_visualizers = tcx.debugger_visualizers(cnum).clone();
if !debugger_visualizers.is_empty() {
info.debugger_visualizers.insert(cnum, debugger_visualizers);
}
}
}
info

View file

@ -35,6 +35,7 @@ use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT
use rustc_session::cstore::{self, CrateSource};
use rustc_session::utils::NativeLibKind;
use rustc_span::symbol::Symbol;
use rustc_span::DebuggerVisualizerFile;
use std::path::{Path, PathBuf};
pub mod back;
@ -156,6 +157,7 @@ pub struct CrateInfo {
pub missing_lang_items: FxHashMap<CrateNum, Vec<LangItem>>,
pub dependency_formats: Lrc<Dependencies>,
pub windows_subsystem: Option<String>,
pub debugger_visualizers: FxHashMap<CrateNum, Vec<DebuggerVisualizerFile>>,
}
#[derive(Encodable, Decodable)]