about summary refs log tree commit diff
path: root/compiler/rustc_codegen_llvm/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-08-06 13:02:36 +0000
committerbors <bors@rust-lang.org>2025-08-06 13:02:36 +0000
commit8fb40f798a23adf608182ce5f4eb151fdc8e0da5 (patch)
tree9ffc89ae51d0d74fc63f7163b6567dd65f5d0054 /compiler/rustc_codegen_llvm/src
parentdc0bae1db725fbba8524f195f74f680995fd549e (diff)
parentb4d923cea0509933b1fb859930cb20784251f9be (diff)
downloadrust-8fb40f798a23adf608182ce5f4eb151fdc8e0da5.tar.gz
rust-8fb40f798a23adf608182ce5f4eb151fdc8e0da5.zip
Auto merge of #143679 - sebastianpoeplau:preserve-debug-gdb-scripts-section, r=bjorn3
Preserve the .debug_gdb_scripts section

Make sure that compiler and linker don't optimize the section's contents
away by adding the global holding the data to `llvm.used`. This
eliminates the need for a volatile load in the main shim; since the LLVM
codegen backend is the only implementer of the corresponding trait
function, remove it entirely.

Pretty printers in dylib dependencies are now emitted by the main crate
instead of the dylib; apart from matching how rlibs are handled, this
approach has the advantage that `omit_gdb_pretty_printer_section` keeps
working with dylib dependencies.

r? `@bjorn3`
Diffstat (limited to 'compiler/rustc_codegen_llvm/src')
-rw-r--r--compiler/rustc_codegen_llvm/src/base.rs12
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs57
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs36
3 files changed, 47 insertions, 58 deletions
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index 5dda836988c..d7da03bf490 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -109,11 +109,16 @@ pub(crate) fn compile_codegen_unit(
             }
 
             // Finalize code coverage by injecting the coverage map. Note, the coverage map will
-            // also be added to the `llvm.compiler.used` variable, created next.
+            // also be added to the `llvm.compiler.used` variable, created below.
             if cx.sess().instrument_coverage() {
                 cx.coverageinfo_finalize();
             }
 
+            // Finalize debuginfo. This adds to `llvm.used`, created below.
+            if cx.sess().opts.debuginfo != DebugInfo::None {
+                cx.debuginfo_finalize();
+            }
+
             // Create the llvm.used and llvm.compiler.used variables.
             if !cx.used_statics.is_empty() {
                 cx.create_used_variable_impl(c"llvm.used", &cx.used_statics);
@@ -130,11 +135,6 @@ pub(crate) fn compile_codegen_unit(
                     llvm::LLVMDeleteGlobal(old_g);
                 }
             }
-
-            // Finalize debuginfo
-            if cx.sess().opts.debuginfo != DebugInfo::None {
-                cx.debuginfo_finalize();
-            }
         }
 
         ModuleCodegen::new_regular(cgu_name.to_string(), llvm_module)
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index 6eb7042da61..fccd32dec95 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -1,11 +1,13 @@
 // .debug_gdb_scripts binary section.
 
-use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
+use std::collections::BTreeSet;
+use std::ffi::CString;
+
 use rustc_codegen_ssa::traits::*;
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::bug;
 use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerType;
-use rustc_session::config::{CrateType, DebugInfo};
+use rustc_session::config::DebugInfo;
 
 use crate::builder::Builder;
 use crate::common::CodegenCx;
@@ -31,7 +33,12 @@ pub(crate) fn insert_reference_to_gdb_debug_scripts_section_global(bx: &mut Buil
 pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>(
     cx: &CodegenCx<'ll, '_>,
 ) -> &'ll Value {
-    let c_section_var_name = c"__rustc_debug_gdb_scripts_section__";
+    let c_section_var_name = CString::new(format!(
+        "__rustc_debug_gdb_scripts_section_{}_{:08x}",
+        cx.tcx.crate_name(LOCAL_CRATE),
+        cx.tcx.stable_crate_id(LOCAL_CRATE),
+    ))
+    .unwrap();
     let section_var_name = c_section_var_name.to_str().unwrap();
 
     let section_var = unsafe { llvm::LLVMGetNamedGlobal(cx.llmod, c_section_var_name.as_ptr()) };
@@ -44,10 +51,14 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>(
 
         // Next, add the pretty printers that were specified via the `#[debugger_visualizer]`
         // attribute.
-        let visualizers = collect_debugger_visualizers_transitive(
-            cx.tcx,
-            DebuggerVisualizerType::GdbPrettyPrinter,
-        );
+        let visualizers = cx
+            .tcx
+            .debugger_visualizers(LOCAL_CRATE)
+            .iter()
+            .filter(|visualizer| {
+                visualizer.visualizer_type == DebuggerVisualizerType::GdbPrettyPrinter
+            })
+            .collect::<BTreeSet<_>>();
         let crate_name = cx.tcx.crate_name(LOCAL_CRATE);
         for (index, visualizer) in visualizers.iter().enumerate() {
             // The initial byte `4` instructs GDB that the following pretty printer
@@ -84,35 +95,5 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>(
 }
 
 pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
-    // To ensure the section `__rustc_debug_gdb_scripts_section__` will not create
-    // ODR violations at link time, this section will not be emitted for rlibs since
-    // each rlib could produce a different set of visualizers that would be embedded
-    // in the `.debug_gdb_scripts` section. For that reason, we make sure that the
-    // section is only emitted for leaf crates.
-    let embed_visualizers = cx.tcx.crate_types().iter().any(|&crate_type| match crate_type {
-        CrateType::Executable
-        | CrateType::Dylib
-        | CrateType::Cdylib
-        | CrateType::Staticlib
-        | CrateType::Sdylib => {
-            // These are crate types for which we will embed pretty printers since they
-            // are treated as leaf crates.
-            true
-        }
-        CrateType::ProcMacro => {
-            // We could embed pretty printers for proc macro crates too 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::Rlib => {
-            // As per the above description, embedding pretty printers for rlibs could
-            // lead to ODR violations so we skip this crate type as well.
-            false
-        }
-    });
-
-    cx.sess().opts.debuginfo != DebugInfo::None
-        && cx.sess().target.emit_debug_gdb_scripts
-        && embed_visualizers
+    cx.sess().opts.debuginfo != DebugInfo::None && cx.sess().target.emit_debug_gdb_scripts
 }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 6cbf2dbf7d3..c911435967c 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -30,7 +30,7 @@ use tracing::debug;
 
 use self::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER, file_metadata, type_di_node};
 use self::namespace::mangled_name_of_instance;
-use self::utils::{DIB, create_DIArray, is_node_local_to_unit};
+use self::utils::{DIB, create_DIArray, debug_context, is_node_local_to_unit};
 use crate::builder::Builder;
 use crate::common::{AsCCharPtr, CodegenCx};
 use crate::llvm;
@@ -131,20 +131,28 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
 }
 
 /// Creates any deferred debug metadata nodes
-pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
-    if let Some(dbg_cx) = &cx.dbg_cx {
-        debug!("finalize");
-
-        if gdb::needs_gdb_debug_scripts_section(cx) {
-            // Add a .debug_gdb_scripts section to this compile-unit. This will
-            // cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
-            // which activates the Rust pretty printers for binary this section is
-            // contained in.
-            gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
-        }
+pub(crate) fn finalize(cx: &mut CodegenCx<'_, '_>) {
+    if cx.dbg_cx.is_none() {
+        return;
+    }
+
+    debug!("finalize");
 
-        dbg_cx.finalize(cx.sess());
+    if gdb::needs_gdb_debug_scripts_section(cx) {
+        // Add a .debug_gdb_scripts section to this compile-unit. This will
+        // cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
+        // which activates the Rust pretty printers for binary this section is
+        // contained in.
+        let section_var = gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
+
+        // Make sure that the linker doesn't optimize the global away. Adding
+        // it to `llvm.used` has the advantage that it works even in no_std
+        // binaries, where we don't have a main shim and thus don't emit a
+        // volatile load to preserve the global.
+        cx.add_used_global(section_var);
     }
+
+    debug_context(cx).finalize(cx.sess());
 }
 
 impl<'ll> Builder<'_, 'll, '_> {
@@ -614,7 +622,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         metadata::extend_scope_to_file(self, scope_metadata, file)
     }
 
-    fn debuginfo_finalize(&self) {
+    fn debuginfo_finalize(&mut self) {
         finalize(self)
     }