Skip to content

Commit 0fb1e12

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". 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.
1 parent 7f2065a commit 0fb1e12

File tree

10 files changed

+71
-109
lines changed

10 files changed

+71
-109
lines changed

compiler/rustc_codegen_gcc/src/debuginfo.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,6 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
3636
_variable_alloca.set_location(_dbg_loc);
3737
}
3838

39-
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
40-
// TODO(antoyo): insert reference to gdb debug scripts section global.
41-
}
42-
4339
/// FIXME(tempdragon): Currently, this function is not yet implemented. It seems that the
4440
/// debug name and the mangled name should both be included in the LValues.
4541
/// Besides, a function to get the rvalue type(m_is_lvalue) should also be included.
@@ -254,7 +250,8 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
254250
// TODO(antoyo): implement.
255251
}
256252

257-
fn debuginfo_finalize(&self) {
253+
fn debuginfo_finalize(&mut self) {
254+
// TODO: emit section `.debug_gdb_scripts`.
258255
self.context.set_debug_info(true)
259256
}
260257

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: 19 additions & 30 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_attr_data_structures::{AttributeKind, find_attr};
46
use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
57
use rustc_codegen_ssa::traits::*;
@@ -8,31 +10,21 @@ use rustc_middle::bug;
810
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerType;
911
use rustc_session::config::{CrateType, DebugInfo};
1012

11-
use crate::builder::Builder;
1213
use crate::common::CodegenCx;
1314
use crate::llvm;
1415
use crate::value::Value;
1516

16-
/// Inserts a side-effect free instruction sequence that makes sure that the
17-
/// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.
18-
pub(crate) fn insert_reference_to_gdb_debug_scripts_section_global(bx: &mut Builder<'_, '_, '_>) {
19-
if needs_gdb_debug_scripts_section(bx) {
20-
let gdb_debug_scripts_section = get_or_insert_gdb_debug_scripts_section_global(bx);
21-
// Load just the first byte as that's all that's necessary to force
22-
// LLVM to keep around the reference to the global.
23-
let volatile_load_instruction = bx.volatile_load(bx.type_i8(), gdb_debug_scripts_section);
24-
unsafe {
25-
llvm::LLVMSetAlignment(volatile_load_instruction, 1);
26-
}
27-
}
28-
}
29-
3017
/// Allocates the global variable responsible for the .debug_gdb_scripts binary
3118
/// section.
3219
pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>(
33-
cx: &CodegenCx<'ll, '_>,
20+
cx: &mut CodegenCx<'ll, '_>,
3421
) -> &'ll Value {
35-
let c_section_var_name = c"__rustc_debug_gdb_scripts_section__";
22+
let c_section_var_name = CString::new(format!(
23+
"__rustc_debug_gdb_scripts_section_{}_{:08x}",
24+
cx.tcx.crate_name(LOCAL_CRATE),
25+
cx.tcx.stable_crate_id(LOCAL_CRATE),
26+
))
27+
.unwrap();
3628
let section_var_name = c_section_var_name.to_str().unwrap();
3729

3830
let section_var = unsafe { llvm::LLVMGetNamedGlobal(cx.llmod, c_section_var_name.as_ptr()) };
@@ -79,6 +71,8 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>(
7971
// This should make sure that the whole section is not larger than
8072
// the string it contains. Otherwise we get a warning from GDB.
8173
llvm::LLVMSetAlignment(section_var, 1);
74+
// Make sure that the linker doesn't optimize the global away.
75+
cx.add_used_global(section_var);
8276
section_var
8377
}
8478
})
@@ -88,17 +82,10 @@ pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
8882
let omit_gdb_pretty_printer_section =
8983
find_attr!(cx.tcx.hir_krate_attrs(), AttributeKind::OmitGdbPrettyPrinterSection);
9084

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

compiler/rustc_codegen_llvm/src/debuginfo/mod.rs

Lines changed: 16 additions & 18 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,22 @@ 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+
gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
147147
}
148+
149+
debug_context(cx).finalize(cx.sess());
148150
}
149151

150152
impl<'ll> Builder<'_, 'll, '_> {
@@ -215,10 +217,6 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
215217
}
216218
}
217219

218-
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
219-
gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
220-
}
221-
222220
fn set_var_name(&mut self, value: &'ll Value, name: &str) {
223221
// Avoid wasting time if LLVM value names aren't even enabled.
224222
if self.sess().fewer_names() {
@@ -614,7 +612,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
614612
metadata::extend_scope_to_file(self, scope_metadata, file)
615613
}
616614

617-
fn debuginfo_finalize(&self) {
615+
fn debuginfo_finalize(&mut self) {
618616
finalize(self)
619617
}
620618

compiler/rustc_codegen_ssa/src/base.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -528,8 +528,6 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
528528
let llbb = Bx::append_block(cx, llfn, "top");
529529
let mut bx = Bx::build(cx, llbb);
530530

531-
bx.insert_reference_to_gdb_debug_scripts_section_global();
532-
533531
let isize_ty = cx.type_isize();
534532
let ptr_ty = cx.type_ptr();
535533
let (arg_argc, arg_argv) = get_argc_argv(&mut bx);
@@ -609,15 +607,7 @@ pub fn collect_debugger_visualizers_transitive(
609607
) -> BTreeSet<DebuggerVisualizerFile> {
610608
tcx.debugger_visualizers(LOCAL_CRATE)
611609
.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-
)
610+
.chain(tcx.crates(()).iter().flat_map(|&cnum| tcx.debugger_visualizers(cnum)))
621611
.filter(|visualizer| visualizer.visualizer_type == visualizer_type)
622612
.cloned()
623613
.collect::<BTreeSet<_>>()

compiler/rustc_codegen_ssa/src/traits/debuginfo.rs

Lines changed: 1 addition & 2 deletions
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.).
@@ -81,6 +81,5 @@ pub trait DebugInfoBuilderMethods: BackendTypes {
8181
);
8282
fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation);
8383
fn clear_dbg_loc(&mut self);
84-
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self);
8584
fn set_var_name(&mut self, value: Self::Value, name: &str);
8685
}

src/tools/compiletest/src/directives.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
831831
"ignore-gnu",
832832
"ignore-haiku",
833833
"ignore-horizon",
834+
"ignore-i586-unknown-linux-gnu",
834835
"ignore-i686-pc-windows-gnu",
835836
"ignore-i686-pc-windows-msvc",
836837
"ignore-illumos",

tests/codegen/gdb_debug_script_load.rs

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,14 @@
44
//@ ignore-wasm
55
//@ ignore-emscripten
66

7-
//@ compile-flags: -g -C no-prepopulate-passes -Cpanic=abort
7+
//@ compile-flags: -g -Cpanic=abort
88

9-
#![feature(lang_items)]
109
#![no_std]
10+
#![no_main]
1111

1212
#[panic_handler]
1313
fn panic_handler(_: &core::panic::PanicInfo) -> ! {
1414
loop {}
1515
}
1616

17-
#[no_mangle]
18-
extern "C" fn rust_eh_personality() {
19-
loop {}
20-
}
21-
22-
// Needs rustc to generate `main` as that's where the magic load is inserted.
23-
// IOW, we cannot write this test with `#![no_main]`.
24-
// CHECK-LABEL: @main
25-
// CHECK: load volatile i8, {{.+}} @__rustc_debug_gdb_scripts_section__
26-
27-
#[lang = "start"]
28-
fn lang_start<T: 'static>(
29-
_main: fn() -> T,
30-
_argc: isize,
31-
_argv: *const *const u8,
32-
_sigpipe: u8,
33-
) -> isize {
34-
return 0;
35-
}
36-
37-
fn main() {}
17+
// CHECK: @llvm.used = {{.+}} @__rustc_debug_gdb_scripts_section

tests/debuginfo/embedded-visualizer.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//@ compile-flags:-g
22
//@ ignore-lldb
33
//@ ignore-windows-gnu: #128981
4+
//@ ignore-i586-unknown-linux-gnu: linker too old in CI
45

56
// === CDB TESTS ==================================================================================
67

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)