Skip to content

Commit 26f05dc

Browse files
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". The volatile load in the main shim is retained because "llvm.used", which translates to SHF_GNU_RETAIN on ELF targets, requires a reasonably recent linker; emitting the volatile load ensures compatibility with older linkers, at least when libstd is used. 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.
1 parent e3ee7f7 commit 26f05dc

File tree

8 files changed

+72
-60
lines changed

8 files changed

+72
-60
lines changed

compiler/rustc_codegen_gcc/src/debuginfo.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,8 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
254254
// TODO(antoyo): implement.
255255
}
256256

257-
fn debuginfo_finalize(&self) {
257+
fn debuginfo_finalize(&mut self) {
258+
// TODO: emit section `.debug_gdb_scripts`.
258259
self.context.set_debug_info(true)
259260
}
260261

compiler/rustc_codegen_llvm/src/base.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,16 @@ pub(crate) fn compile_codegen_unit(
109109
}
110110

111111
// Finalize code coverage by injecting the coverage map. Note, the coverage map will
112-
// also be added to the `llvm.compiler.used` variable, created next.
112+
// also be added to the `llvm.compiler.used` variable, created below.
113113
if cx.sess().instrument_coverage() {
114114
cx.coverageinfo_finalize();
115115
}
116116

117+
// Finalize debuginfo. This adds to `llvm.used`, created below.
118+
if cx.sess().opts.debuginfo != DebugInfo::None {
119+
cx.debuginfo_finalize();
120+
}
121+
117122
// Create the llvm.used and llvm.compiler.used variables.
118123
if !cx.used_statics.is_empty() {
119124
cx.create_used_variable_impl(c"llvm.used", &cx.used_statics);
@@ -130,11 +135,6 @@ pub(crate) fn compile_codegen_unit(
130135
llvm::LLVMDeleteGlobal(old_g);
131136
}
132137
}
133-
134-
// Finalize debuginfo
135-
if cx.sess().opts.debuginfo != DebugInfo::None {
136-
cx.debuginfo_finalize();
137-
}
138138
}
139139

140140
ModuleCodegen::new_regular(cgu_name.to_string(), llvm_module)

compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// .debug_gdb_scripts binary section.
22

3+
use std::ffi::CString;
4+
35
use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
46
use rustc_codegen_ssa::traits::*;
57
use rustc_hir::attrs::AttributeKind;
@@ -33,7 +35,12 @@ pub(crate) fn insert_reference_to_gdb_debug_scripts_section_global(bx: &mut Buil
3335
pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>(
3436
cx: &CodegenCx<'ll, '_>,
3537
) -> &'ll Value {
36-
let c_section_var_name = c"__rustc_debug_gdb_scripts_section__";
38+
let c_section_var_name = CString::new(format!(
39+
"__rustc_debug_gdb_scripts_section_{}_{:08x}",
40+
cx.tcx.crate_name(LOCAL_CRATE),
41+
cx.tcx.stable_crate_id(LOCAL_CRATE),
42+
))
43+
.unwrap();
3744
let section_var_name = c_section_var_name.to_str().unwrap();
3845

3946
let section_var = unsafe { llvm::LLVMGetNamedGlobal(cx.llmod, c_section_var_name.as_ptr()) };
@@ -89,17 +96,10 @@ pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
8996
let omit_gdb_pretty_printer_section =
9097
find_attr!(cx.tcx.hir_krate_attrs(), AttributeKind::OmitGdbPrettyPrinterSection);
9198

92-
// To ensure the section `__rustc_debug_gdb_scripts_section__` will not create
93-
// ODR violations at link time, this section will not be emitted for rlibs since
94-
// each rlib could produce a different set of visualizers that would be embedded
95-
// in the `.debug_gdb_scripts` section. For that reason, we make sure that the
96-
// section is only emitted for leaf crates.
99+
// We collect pretty printers transitively for all crates, so we make sure
100+
// that the section is only emitted for leaf crates.
97101
let embed_visualizers = cx.tcx.crate_types().iter().any(|&crate_type| match crate_type {
98-
CrateType::Executable
99-
| CrateType::Dylib
100-
| CrateType::Cdylib
101-
| CrateType::Staticlib
102-
| CrateType::Sdylib => {
102+
CrateType::Executable | CrateType::Cdylib | CrateType::Staticlib | CrateType::Sdylib => {
103103
// These are crate types for which we will embed pretty printers since they
104104
// are treated as leaf crates.
105105
true
@@ -110,9 +110,11 @@ pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
110110
// want to slow down the common case.
111111
false
112112
}
113-
CrateType::Rlib => {
114-
// As per the above description, embedding pretty printers for rlibs could
115-
// lead to ODR violations so we skip this crate type as well.
113+
CrateType::Rlib | CrateType::Dylib => {
114+
// Don't embed pretty printers for these crate types; the compiler
115+
// can see the `#[debug_visualizer]` attributes when using the
116+
// library, and emitting `.debug_gdb_scripts` regardless would
117+
// break `#![omit_gdb_pretty_printer_section]`.
116118
false
117119
}
118120
});

compiler/rustc_codegen_llvm/src/debuginfo/mod.rs

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use tracing::debug;
3030

3131
use self::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER, file_metadata, type_di_node};
3232
use self::namespace::mangled_name_of_instance;
33-
use self::utils::{DIB, create_DIArray, is_node_local_to_unit};
33+
use self::utils::{DIB, create_DIArray, debug_context, is_node_local_to_unit};
3434
use crate::builder::Builder;
3535
use crate::common::{AsCCharPtr, CodegenCx};
3636
use crate::llvm;
@@ -131,20 +131,28 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
131131
}
132132

133133
/// Creates any deferred debug metadata nodes
134-
pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
135-
if let Some(dbg_cx) = &cx.dbg_cx {
136-
debug!("finalize");
137-
138-
if gdb::needs_gdb_debug_scripts_section(cx) {
139-
// Add a .debug_gdb_scripts section to this compile-unit. This will
140-
// cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
141-
// which activates the Rust pretty printers for binary this section is
142-
// contained in.
143-
gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
144-
}
134+
pub(crate) fn finalize(cx: &mut CodegenCx<'_, '_>) {
135+
if cx.dbg_cx.is_none() {
136+
return;
137+
}
138+
139+
debug!("finalize");
145140

146-
dbg_cx.finalize(cx.sess());
141+
if gdb::needs_gdb_debug_scripts_section(cx) {
142+
// Add a .debug_gdb_scripts section to this compile-unit. This will
143+
// cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
144+
// which activates the Rust pretty printers for binary this section is
145+
// contained in.
146+
let section_var = gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
147+
148+
// Make sure that the linker doesn't optimize the global away. Adding
149+
// it to `llvm.used` has the advantage that it works even in no_std
150+
// binaries, where we don't have a main shim and thus don't emit a
151+
// volatile load to preserve the global.
152+
cx.add_used_global(section_var);
147153
}
154+
155+
debug_context(cx).finalize(cx.sess());
148156
}
149157

150158
impl<'ll> Builder<'_, 'll, '_> {
@@ -614,7 +622,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
614622
metadata::extend_scope_to_file(self, scope_metadata, file)
615623
}
616624

617-
fn debuginfo_finalize(&self) {
625+
fn debuginfo_finalize(&mut self) {
618626
finalize(self)
619627
}
620628

compiler/rustc_codegen_ssa/src/base.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -609,15 +609,7 @@ pub fn collect_debugger_visualizers_transitive(
609609
) -> BTreeSet<DebuggerVisualizerFile> {
610610
tcx.debugger_visualizers(LOCAL_CRATE)
611611
.iter()
612-
.chain(
613-
tcx.crates(())
614-
.iter()
615-
.filter(|&cnum| {
616-
let used_crate_source = tcx.used_crate_source(*cnum);
617-
used_crate_source.rlib.is_some() || used_crate_source.rmeta.is_some()
618-
})
619-
.flat_map(|&cnum| tcx.debugger_visualizers(cnum)),
620-
)
612+
.chain(tcx.crates(()).iter().flat_map(|&cnum| tcx.debugger_visualizers(cnum)))
621613
.filter(|visualizer| visualizer.visualizer_type == visualizer_type)
622614
.cloned()
623615
.collect::<BTreeSet<_>>()

compiler/rustc_codegen_ssa/src/traits/debuginfo.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ pub trait DebugInfoCodegenMethods<'tcx>: BackendTypes {
5050
scope_metadata: Self::DIScope,
5151
file: &SourceFile,
5252
) -> Self::DIScope;
53-
fn debuginfo_finalize(&self);
53+
fn debuginfo_finalize(&mut self);
5454

5555
// FIXME(eddyb) find a common convention for all of the debuginfo-related
5656
// names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).

tests/codegen-llvm/gdb_debug_script_load.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#![feature(lang_items)]
1010
#![no_std]
1111

12+
// CHECK: @llvm.used = {{.+}} @__rustc_debug_gdb_scripts_section
13+
1214
#[panic_handler]
1315
fn panic_handler(_: &core::panic::PanicInfo) -> ! {
1416
loop {}
@@ -22,7 +24,7 @@ extern "C" fn rust_eh_personality() {
2224
// Needs rustc to generate `main` as that's where the magic load is inserted.
2325
// IOW, we cannot write this test with `#![no_main]`.
2426
// CHECK-LABEL: @main
25-
// CHECK: load volatile i8, {{.+}} @__rustc_debug_gdb_scripts_section__
27+
// CHECK: load volatile i8, {{.+}} @__rustc_debug_gdb_scripts_section
2628

2729
#[lang = "start"]
2830
fn lang_start<T: 'static>(

tests/run-make/symbols-all-mangled/rmake.rs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,7 @@ fn symbols_check_archive(path: &str) {
3535
continue; // All compiler-builtins symbols must remain unmangled
3636
}
3737

38-
if name.contains("rust_eh_personality") {
39-
continue; // Unfortunately LLVM doesn't allow us to mangle this symbol
40-
}
41-
42-
if name.contains(".llvm.") {
43-
// Starting in LLVM 21 we get various implementation-detail functions which
44-
// contain .llvm. that are not a problem.
38+
if symbol_ok_everywhere(name) {
4539
continue;
4640
}
4741

@@ -71,13 +65,7 @@ fn symbols_check(path: &str) {
7165
continue;
7266
}
7367

74-
if name.contains("rust_eh_personality") {
75-
continue; // Unfortunately LLVM doesn't allow us to mangle this symbol
76-
}
77-
78-
if name.contains(".llvm.") {
79-
// Starting in LLVM 21 we get various implementation-detail functions which
80-
// contain .llvm. that are not a problem.
68+
if symbol_ok_everywhere(name) {
8169
continue;
8270
}
8371

@@ -88,3 +76,22 @@ fn symbols_check(path: &str) {
8876
fn strip_underscore_if_apple(symbol: &str) -> &str {
8977
if cfg!(target_vendor = "apple") { symbol.strip_prefix("_").unwrap() } else { symbol }
9078
}
79+
80+
fn symbol_ok_everywhere(name: &str) -> bool {
81+
if name.contains("rust_eh_personality") {
82+
return true; // Unfortunately LLVM doesn't allow us to mangle this symbol
83+
}
84+
85+
if name.contains(".llvm.") {
86+
// Starting in LLVM 21 we get various implementation-detail functions which
87+
// contain .llvm. that are not a problem.
88+
return true;
89+
}
90+
91+
if name.starts_with("__rustc_debug_gdb_scripts_section") {
92+
// These symbols are fine; they're made unique by the crate ID.
93+
return true;
94+
}
95+
96+
return false;
97+
}

0 commit comments

Comments
 (0)