Add support for embedding pretty printers via the #[debugger_visualizer]
attribute. Add tests for embedding pretty printers and update documentation.
Ensure all error checking for `#[debugger_visualizer]` is done up front and not when the `debugger_visualizer` query is run. Clean up potential ODR violations when embedding pretty printers into the `__rustc_debug_gdb_scripts_section__` section. Respond to PR comments and update documentation.
This commit is contained in:
parent
ee9726cb10
commit
60458b97e7
27 changed files with 455 additions and 200 deletions
|
@ -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, LOCAL_CRATE};
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
use rustc_middle::middle::dependency_format::Linkage;
|
||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
|
||||
|
@ -18,6 +18,7 @@ use rustc_session::utils::NativeLibKind;
|
|||
/// need out of the shared crate context before we get rid of it.
|
||||
use rustc_session::{filesearch, Session};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::DebuggerVisualizerFile;
|
||||
use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
|
||||
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
|
||||
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target};
|
||||
|
@ -37,6 +38,7 @@ use regex::Regex;
|
|||
use tempfile::Builder as TempFileBuilder;
|
||||
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::BTreeSet;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{BufWriter, Write};
|
||||
|
@ -2099,14 +2101,16 @@ 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()
|
||||
};
|
||||
// Gather the set of NatVis files, if any, and write them out to a temp directory.
|
||||
let natvis_visualizers = collect_natvis_visualizers(
|
||||
tmpdir,
|
||||
sess,
|
||||
&codegen_results.crate_info.local_crate_name,
|
||||
&codegen_results.crate_info.natvis_debugger_visualizers,
|
||||
);
|
||||
|
||||
// Pass debuginfo and strip flags down to the linker.
|
||||
cmd.debuginfo(strip_value(sess), &debugger_visualizer_paths);
|
||||
// Pass debuginfo, NatVis debugger visualizers and strip flags down to the linker.
|
||||
cmd.debuginfo(strip_value(sess), &natvis_visualizers);
|
||||
|
||||
// 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.
|
||||
|
@ -2125,43 +2129,33 @@ 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(
|
||||
// Write the NatVis debugger visualizer files for each crate to the temp directory and gather the file paths.
|
||||
fn collect_natvis_visualizers(
|
||||
tmpdir: &Path,
|
||||
sess: &Session,
|
||||
crate_info: &CrateInfo,
|
||||
crate_name: &Symbol,
|
||||
natvis_debugger_visualizers: &BTreeSet<DebuggerVisualizerFile>,
|
||||
) -> Vec<PathBuf> {
|
||||
let mut visualizer_paths = Vec::new();
|
||||
let debugger_visualizers = &crate_info.debugger_visualizers;
|
||||
let mut index = 0;
|
||||
let mut visualizer_paths = Vec::with_capacity(natvis_debugger_visualizers.len());
|
||||
|
||||
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 (index, visualizer) in natvis_debugger_visualizers.iter().enumerate() {
|
||||
let visualizer_out_file = tmpdir.join(format!("{}-{}.natvis", crate_name.as_str(), index));
|
||||
|
||||
match fs::write(&visualizer_out_file, &visualizer.src) {
|
||||
Ok(()) => {
|
||||
visualizer_paths.push(visualizer_out_file);
|
||||
}
|
||||
Err(error) => {
|
||||
sess.warn(
|
||||
format!(
|
||||
"Unable to write debugger visualizer file `{}`: {} ",
|
||||
visualizer_out_file.display(),
|
||||
error
|
||||
)
|
||||
.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
|
||||
}
|
||||
|
|
|
@ -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, debugger_visualizers: &[PathBuf]);
|
||||
fn debuginfo(&mut self, strip: Strip, natvis_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]);
|
||||
|
@ -915,7 +915,7 @@ impl<'a> Linker for MsvcLinker<'a> {
|
|||
self.cmd.arg("/guard:cf");
|
||||
}
|
||||
|
||||
fn debuginfo(&mut self, strip: Strip, debugger_visualizers: &[PathBuf]) {
|
||||
fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]) {
|
||||
match strip {
|
||||
Strip::None => {
|
||||
// This will cause the Microsoft linker to generate a PDB file
|
||||
|
@ -944,7 +944,7 @@ 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 {
|
||||
for path in natvis_debugger_visualizers {
|
||||
let mut arg = OsString::from("/NATVIS:");
|
||||
arg.push(path);
|
||||
self.cmd.arg(arg);
|
||||
|
|
|
@ -31,11 +31,13 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
|
|||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||
use rustc_session::cgu_reuse_tracker::CguReuse;
|
||||
use rustc_session::config::{self, EntryFnType, OutputType};
|
||||
use rustc_session::config::{self, CrateType, EntryFnType, OutputType};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType};
|
||||
use rustc_target::abi::{Align, VariantIdx};
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::convert::TryFrom;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::time::{Duration, Instant};
|
||||
|
@ -487,6 +489,29 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
}
|
||||
}
|
||||
|
||||
/// This function returns all of the debugger visualizers specified for the
|
||||
/// current crate as well as all upstream crates transitively that match the
|
||||
/// `visualizer_type` specified.
|
||||
pub fn collect_debugger_visualizers_transitive(
|
||||
tcx: TyCtxt<'_>,
|
||||
visualizer_type: DebuggerVisualizerType,
|
||||
) -> BTreeSet<DebuggerVisualizerFile> {
|
||||
tcx.debugger_visualizers(LOCAL_CRATE)
|
||||
.iter()
|
||||
.chain(
|
||||
tcx.crates(())
|
||||
.iter()
|
||||
.filter(|&cnum| {
|
||||
let used_crate_source = tcx.used_crate_source(*cnum);
|
||||
used_crate_source.rlib.is_some() || used_crate_source.rmeta.is_some()
|
||||
})
|
||||
.flat_map(|&cnum| tcx.debugger_visualizers(cnum)),
|
||||
)
|
||||
.filter(|visualizer| visualizer.visualizer_type == visualizer_type)
|
||||
.cloned()
|
||||
.collect::<BTreeSet<_>>()
|
||||
}
|
||||
|
||||
pub fn codegen_crate<B: ExtraBackendMethods>(
|
||||
backend: B,
|
||||
tcx: TyCtxt<'_>,
|
||||
|
@ -838,13 +863,8 @@ impl CrateInfo {
|
|||
missing_lang_items: Default::default(),
|
||||
dependency_formats: tcx.dependency_formats(()).clone(),
|
||||
windows_subsystem,
|
||||
debugger_visualizers: Default::default(),
|
||||
natvis_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(());
|
||||
|
@ -882,14 +902,29 @@ 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);
|
||||
}
|
||||
let embed_visualizers = tcx.sess.crate_types().iter().any(|&crate_type| match crate_type {
|
||||
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib => {
|
||||
// These are crate types for which we invoke the linker and can embed
|
||||
// NatVis visualizers.
|
||||
true
|
||||
}
|
||||
CrateType::ProcMacro => {
|
||||
// We could embed NatVis for proc macro crates too (to improve the debugging
|
||||
// experience for them) but it does not seem like a good default, since
|
||||
// this is a rare use case and we don't want to slow down the common case.
|
||||
false
|
||||
}
|
||||
CrateType::Staticlib | CrateType::Rlib => {
|
||||
// We don't invoke the linker for these, so we don't need to collect the NatVis for them.
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
if tcx.sess.target.is_like_msvc && embed_visualizers {
|
||||
info.natvis_debugger_visualizers =
|
||||
collect_debugger_visualizers_transitive(tcx, DebuggerVisualizerType::Natvis);
|
||||
}
|
||||
|
||||
info
|
||||
|
|
|
@ -36,6 +36,7 @@ use rustc_session::cstore::{self, CrateSource};
|
|||
use rustc_session::utils::NativeLibKind;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::DebuggerVisualizerFile;
|
||||
use std::collections::BTreeSet;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub mod back;
|
||||
|
@ -157,7 +158,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>>,
|
||||
pub natvis_debugger_visualizers: BTreeSet<DebuggerVisualizerFile>,
|
||||
}
|
||||
|
||||
#[derive(Encodable, Decodable)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue