Skip to content

Commit 08ed338

Browse files
committed
sess/cg: re-introduce split dwarf kind
In #79570, `-Z split-dwarf-kind={none,single,split}` was replaced by `-C split-debuginfo={off,packed,unpacked}`. `-C split-debuginfo`'s packed and unpacked aren't exact parallels to single and split, respectively. On Unix, `-C split-debuginfo=packed` will put debuginfo into object files and package debuginfo into a DWARF package file (`.dwp`) and `-C split-debuginfo=unpacked` will put debuginfo into dwarf object files and won't package it. In the initial implementation of Split DWARF, split mode wrote sections which did not require relocation into a DWARF object (`.dwo`) file which was ignored by the linker and then packaged those DWARF objects into DWARF packages (`.dwp`). In single mode, sections which did not require relocation were written into object files but ignored by the linker and were not packaged. However, both split and single modes could be packaged or not, the primary difference in behaviour was where the debuginfo sections that did not require link-time relocation were written (in a DWARF object or the object file). This commit re-introduces a `-Z split-dwarf-kind` flag, which can be used to pick between split and single modes when `-C split-debuginfo` is used to enable Split DWARF (either packed or unpacked). Signed-off-by: David Wood <[email protected]>
1 parent f1ce0e6 commit 08ed338

File tree

8 files changed

+184
-61
lines changed

8 files changed

+184
-61
lines changed

compiler/rustc_codegen_llvm/src/back/write.rs

+21-14
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use rustc_errors::{FatalError, Handler, Level};
2323
use rustc_fs_util::{link_or_copy, path_to_c_string};
2424
use rustc_middle::bug;
2525
use rustc_middle::ty::TyCtxt;
26-
use rustc_session::config::{self, Lto, OutputType, Passes, SwitchWithOptPath};
26+
use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath};
2727
use rustc_session::Session;
2828
use rustc_span::symbol::sym;
2929
use rustc_span::InnerSpan;
@@ -106,7 +106,11 @@ pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm:
106106

107107
pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine {
108108
let split_dwarf_file = if tcx.sess.target_can_use_split_dwarf() {
109-
tcx.output_filenames(()).split_dwarf_path(tcx.sess.split_debuginfo(), Some(mod_name))
109+
tcx.output_filenames(()).split_dwarf_path(
110+
tcx.sess.split_debuginfo(),
111+
tcx.sess.opts.debugging_opts.split_dwarf_kind,
112+
Some(mod_name),
113+
)
110114
} else {
111115
None
112116
};
@@ -892,17 +896,18 @@ pub(crate) unsafe fn codegen(
892896
.generic_activity_with_arg("LLVM_module_codegen_emit_obj", &*module.name);
893897

894898
let dwo_out = cgcx.output_filenames.temp_path_dwo(module_name);
895-
let dwo_out = match cgcx.split_debuginfo {
896-
// Don't change how DWARF is emitted in single mode (or when disabled).
897-
SplitDebuginfo::Off | SplitDebuginfo::Packed => None,
898-
// Emit (a subset of the) DWARF into a separate file in split mode.
899-
SplitDebuginfo::Unpacked => {
900-
if cgcx.target_can_use_split_dwarf {
901-
Some(dwo_out.as_path())
902-
} else {
903-
None
904-
}
905-
}
899+
let dwo_out = match (cgcx.split_debuginfo, cgcx.split_dwarf_kind) {
900+
// Don't change how DWARF is emitted when disabled.
901+
(SplitDebuginfo::Off, _) => None,
902+
// Don't provide a DWARF object path if split debuginfo is enabled but this is
903+
// a platform that doesn't support Split DWARF.
904+
_ if !cgcx.target_can_use_split_dwarf => None,
905+
// Don't provide a DWARF object path in single mode, sections will be written
906+
// into the object as normal but ignored by linker.
907+
(_, SplitDwarfKind::Single) => None,
908+
// Emit (a subset of the) DWARF into a separate dwarf object file in split
909+
// mode.
910+
(_, SplitDwarfKind::Split) => Some(dwo_out.as_path()),
906911
};
907912

908913
with_codegen(tm, llmod, config.no_builtins, |cpm| {
@@ -939,7 +944,9 @@ pub(crate) unsafe fn codegen(
939944

940945
Ok(module.into_compiled_module(
941946
config.emit_obj != EmitObj::None,
942-
cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked,
947+
cgcx.target_can_use_split_dwarf
948+
&& cgcx.split_debuginfo != SplitDebuginfo::Off
949+
&& cgcx.split_dwarf_kind == SplitDwarfKind::Split,
943950
config.emit_bc,
944951
&cgcx.output_filenames,
945952
))

compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1072,7 +1072,11 @@ pub fn compile_unit_metadata<'ll, 'tcx>(
10721072
let output_filenames = tcx.output_filenames(());
10731073
let split_name = if tcx.sess.target_can_use_split_dwarf() {
10741074
output_filenames
1075-
.split_dwarf_path(tcx.sess.split_debuginfo(), Some(codegen_unit_name))
1075+
.split_dwarf_path(
1076+
tcx.sess.split_debuginfo(),
1077+
tcx.sess.opts.debugging_opts.split_dwarf_kind,
1078+
Some(codegen_unit_name),
1079+
)
10761080
// We get a path relative to the working directory from split_dwarf_path
10771081
.map(|f| tcx.sess.source_map().path_mapping().map_prefix(f).0)
10781082
} else {

compiler/rustc_codegen_ssa/src/back/link.rs

+59-33
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_fs_util::fix_windows_verbatim_for_gcc;
55
use rustc_hir::def_id::CrateNum;
66
use rustc_middle::middle::dependency_format::Linkage;
77
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
8-
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest};
8+
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
99
use rustc_session::cstore::DllImport;
1010
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
1111
use rustc_session::search_paths::PathKind;
@@ -134,31 +134,47 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
134134
}
135135
}
136136

137-
// Remove the temporary object file and metadata if we aren't saving temps
137+
// Remove the temporary object file and metadata if we aren't saving temps.
138138
sess.time("link_binary_remove_temps", || {
139-
if !sess.opts.cg.save_temps {
140-
let remove_temps_from_module = |module: &CompiledModule| {
141-
if let Some(ref obj) = module.object {
142-
ensure_removed(sess.diagnostic(), obj);
143-
}
144-
145-
if let Some(ref obj) = module.dwarf_object {
146-
ensure_removed(sess.diagnostic(), obj);
147-
}
148-
};
139+
// If the user requests that temporaries are saved, don't delete any.
140+
if sess.opts.cg.save_temps {
141+
return;
142+
}
149143

150-
if sess.opts.output_types.should_link() && !preserve_objects_for_their_debuginfo(sess) {
151-
for module in &codegen_results.modules {
152-
remove_temps_from_module(module);
153-
}
144+
let remove_temps_from_module = |module: &CompiledModule| {
145+
if let Some(ref obj) = module.object {
146+
ensure_removed(sess.diagnostic(), obj);
154147
}
148+
};
155149

156-
if let Some(ref metadata_module) = codegen_results.metadata_module {
157-
remove_temps_from_module(metadata_module);
150+
// Otherwise, always remove the metadata and allocator module temporaries.
151+
if let Some(ref metadata_module) = codegen_results.metadata_module {
152+
remove_temps_from_module(metadata_module);
153+
}
154+
155+
if let Some(ref allocator_module) = codegen_results.allocator_module {
156+
remove_temps_from_module(allocator_module);
157+
}
158+
159+
// If no requested outputs require linking, then the object temporaries should
160+
// be kept.
161+
if !sess.opts.output_types.should_link() {
162+
return;
163+
}
164+
165+
// Potentially keep objects for their debuginfo.
166+
let (preserve_objects, preserve_dwarf_objects) = preserve_objects_for_their_debuginfo(sess);
167+
debug!(?preserve_objects, ?preserve_dwarf_objects);
168+
169+
for module in &codegen_results.modules {
170+
if !preserve_objects {
171+
remove_temps_from_module(module);
158172
}
159173

160-
if let Some(ref allocator_module) = codegen_results.allocator_module {
161-
remove_temps_from_module(allocator_module);
174+
if !preserve_dwarf_objects {
175+
if let Some(ref obj) = module.dwarf_object {
176+
ensure_removed(sess.diagnostic(), obj);
177+
}
162178
}
163179
}
164180
});
@@ -1138,26 +1154,36 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
11381154
bug!("Not enough information provided to determine how to invoke the linker");
11391155
}
11401156

1141-
/// Returns a boolean indicating whether we should preserve the object files on
1142-
/// the filesystem for their debug information. This is often useful with
1143-
/// split-dwarf like schemes.
1144-
fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
1157+
/// Returns a pair of boolean indicating whether we should preserve the object and
1158+
/// dwarf object files on the filesystem for their debug information. This is often
1159+
/// useful with split-dwarf like schemes.
1160+
fn preserve_objects_for_their_debuginfo(sess: &Session) -> (bool, bool) {
11451161
// If the objects don't have debuginfo there's nothing to preserve.
11461162
if sess.opts.debuginfo == config::DebugInfo::None {
1147-
return false;
1163+
return (false, false);
11481164
}
11491165

11501166
// If we're only producing artifacts that are archives, no need to preserve
11511167
// the objects as they're losslessly contained inside the archives.
1152-
let output_linked =
1153-
sess.crate_types().iter().any(|&x| x != CrateType::Rlib && x != CrateType::Staticlib);
1154-
if !output_linked {
1155-
return false;
1168+
if sess.crate_types().iter().all(|&x| x.is_archive()) {
1169+
return (false, false);
1170+
}
1171+
1172+
match (sess.split_debuginfo(), sess.opts.debugging_opts.split_dwarf_kind) {
1173+
// If there is no split debuginfo then do not preserve objects.
1174+
(SplitDebuginfo::Off, _) => (false, false),
1175+
// If there is packed split debuginfo, then the debuginfo in the objects
1176+
// has been packaged and the objects can be deleted.
1177+
(SplitDebuginfo::Packed, _) => (false, false),
1178+
// If there is unpacked split debuginfo and the current target can not use
1179+
// split dwarf, then keep objects.
1180+
(SplitDebuginfo::Unpacked, _) if !sess.target_can_use_split_dwarf() => (true, false),
1181+
// If there is unpacked split debuginfo and the target can use split dwarf, then
1182+
// keep the object containing that debuginfo (whether that is an object file or
1183+
// dwarf object file depends on the split dwarf kind).
1184+
(SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => (true, false),
1185+
(SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => (false, true),
11561186
}
1157-
1158-
// "unpacked" split debuginfo means that we leave object files as the
1159-
// debuginfo is found in the original object files themselves
1160-
sess.split_debuginfo() == SplitDebuginfo::Unpacked
11611187
}
11621188

11631189
fn archive_search_paths(sess: &Session) -> Vec<PathBuf> {

compiler/rustc_codegen_ssa/src/back/write.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,11 @@ impl TargetMachineFactoryConfig {
286286
module_name: &str,
287287
) -> TargetMachineFactoryConfig {
288288
let split_dwarf_file = if cgcx.target_can_use_split_dwarf {
289-
cgcx.output_filenames.split_dwarf_path(cgcx.split_debuginfo, Some(module_name))
289+
cgcx.output_filenames.split_dwarf_path(
290+
cgcx.split_debuginfo,
291+
cgcx.split_dwarf_kind,
292+
Some(module_name),
293+
)
290294
} else {
291295
None
292296
};
@@ -329,6 +333,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
329333
pub target_arch: String,
330334
pub debuginfo: config::DebugInfo,
331335
pub split_debuginfo: rustc_target::spec::SplitDebuginfo,
336+
pub split_dwarf_kind: rustc_session::config::SplitDwarfKind,
332337

333338
// Number of cgus excluding the allocator/metadata modules
334339
pub total_cgus: usize,
@@ -1060,6 +1065,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
10601065
target_arch: tcx.sess.target.arch.clone(),
10611066
debuginfo: tcx.sess.opts.debuginfo,
10621067
split_debuginfo: tcx.sess.split_debuginfo(),
1068+
split_dwarf_kind: tcx.sess.opts.debugging_opts.split_dwarf_kind,
10631069
};
10641070

10651071
// This is the "main loop" of parallel work happening for parallel codegen.

compiler/rustc_session/src/config.rs

+54-6
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,37 @@ pub enum DebugInfo {
231231
Full,
232232
}
233233

234+
/// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
235+
/// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
236+
/// uses DWARF for debug-information.
237+
///
238+
/// Some debug-information requires link-time relocation and some does not. LLVM can partition
239+
/// the debuginfo into sections depending on whether or not it requires link-time relocation. Split
240+
/// DWARF provides a mechanism which allows the linker to skip the sections which don't require
241+
/// link-time relocation - either by putting those sections in DWARF object files, or by keeping
242+
/// them in the object file in such a way that the linker will skip them.
243+
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
244+
pub enum SplitDwarfKind {
245+
/// Sections which do not require relocation are written into object file but ignored by the
246+
/// linker.
247+
Single,
248+
/// Sections which do not require relocation are written into a DWARF object (`.dwo`) file
249+
/// which is ignored by the linker.
250+
Split,
251+
}
252+
253+
impl FromStr for SplitDwarfKind {
254+
type Err = ();
255+
256+
fn from_str(s: &str) -> Result<Self, ()> {
257+
Ok(match s {
258+
"single" => SplitDwarfKind::Single,
259+
"split" => SplitDwarfKind::Split,
260+
_ => return Err(()),
261+
})
262+
}
263+
}
264+
234265
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
235266
#[derive(Encodable, Decodable)]
236267
pub enum OutputType {
@@ -378,7 +409,7 @@ impl OutputTypes {
378409
self.0.len()
379410
}
380411

381-
// Returns `true` if any of the output types require codegen or linking.
412+
/// Returns `true` if any of the output types require codegen or linking.
382413
pub fn should_codegen(&self) -> bool {
383414
self.0.keys().any(|k| match *k {
384415
OutputType::Bitcode
@@ -391,7 +422,7 @@ impl OutputTypes {
391422
})
392423
}
393424

394-
// Returns `true` if any of the output types require linking.
425+
/// Returns `true` if any of the output types require linking.
395426
pub fn should_link(&self) -> bool {
396427
self.0.keys().any(|k| match *k {
397428
OutputType::Bitcode
@@ -681,18 +712,23 @@ impl OutputFilenames {
681712
pub fn split_dwarf_path(
682713
&self,
683714
split_debuginfo_kind: SplitDebuginfo,
715+
split_dwarf_kind: SplitDwarfKind,
684716
cgu_name: Option<&str>,
685717
) -> Option<PathBuf> {
686718
let obj_out = self.temp_path(OutputType::Object, cgu_name);
687719
let dwo_out = self.temp_path_dwo(cgu_name);
688-
match split_debuginfo_kind {
689-
SplitDebuginfo::Off => None,
720+
match (split_debuginfo_kind, split_dwarf_kind) {
721+
(SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
690722
// Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
691723
// (pointing at the path which is being determined here). Use the path to the current
692724
// object file.
693-
SplitDebuginfo::Packed => Some(obj_out),
725+
(SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
726+
Some(obj_out)
727+
}
694728
// Split mode emits the DWARF into a different file, use that path.
695-
SplitDebuginfo::Unpacked => Some(dwo_out),
729+
(SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
730+
Some(dwo_out)
731+
}
696732
}
697733
}
698734
}
@@ -821,6 +857,18 @@ pub enum CrateType {
821857

822858
impl_stable_hash_via_hash!(CrateType);
823859

860+
impl CrateType {
861+
/// When generated, is this crate type an archive?
862+
pub fn is_archive(&self) -> bool {
863+
match *self {
864+
CrateType::Rlib | CrateType::Staticlib => true,
865+
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
866+
false
867+
}
868+
}
869+
}
870+
}
871+
824872
#[derive(Clone, Hash, Debug, PartialEq, Eq)]
825873
pub enum Passes {
826874
Some(Vec<String>),

compiler/rustc_session/src/options.rs

+18
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,8 @@ mod desc {
412412
pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
413413
pub const parse_split_debuginfo: &str =
414414
"one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
415+
pub const parse_split_dwarf_kind: &str =
416+
"one of supported split dwarf modes (`split` or `single`)";
415417
pub const parse_gcc_ld: &str = "one of: no value, `lld`";
416418
pub const parse_stack_protector: &str =
417419
"one of (`none` (default), `basic`, `strong`, or `all`)";
@@ -941,6 +943,14 @@ mod parse {
941943
true
942944
}
943945

946+
crate fn parse_split_dwarf_kind(slot: &mut SplitDwarfKind, v: Option<&str>) -> bool {
947+
match v.and_then(|s| SplitDwarfKind::from_str(s).ok()) {
948+
Some(e) => *slot = e,
949+
_ => return false,
950+
}
951+
true
952+
}
953+
944954
crate fn parse_gcc_ld(slot: &mut Option<LdImpl>, v: Option<&str>) -> bool {
945955
match v {
946956
None => *slot = None,
@@ -1403,6 +1413,14 @@ options! {
14031413
"control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"),
14041414
strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
14051415
"tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
1416+
split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [UNTRACKED],
1417+
"split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
1418+
(default: `split`)
1419+
1420+
`split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
1421+
file which is ignored by the linker
1422+
`single`: sections which do not require relocation are written into object file but ignored
1423+
by the linker"),
14061424
split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED],
14071425
"provide minimal debug info in the object/executable to facilitate online \
14081426
symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),

compiler/rustc_target/src/spec/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ pub enum SplitDebuginfo {
479479
///
480480
/// * Windows - not supported
481481
/// * macOS - supported, scattered object files
482-
/// * ELF - supported, scattered `*.dwo` files
482+
/// * ELF - supported, scattered `*.dwo` or `*.o` files (see `SplitDwarfKind`)
483483
Unpacked,
484484
}
485485

0 commit comments

Comments
 (0)