Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

session: stabilize split debuginfo on linux #98051

Merged
merged 1 commit into from
Aug 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2423,13 +2423,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {

let pretty = parse_pretty(&unstable_opts, error_format);

if !unstable_opts.unstable_options
&& !target_triple.triple().contains("apple")
&& cg.split_debuginfo.is_some()
{
early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
}

// Try to find a directory containing the Rust `src`, for more details see
// the doc comment on the `real_rust_source_base_dir` field.
let tmp_buf;
Expand Down
14 changes: 12 additions & 2 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
use rustc_target::asm::InlineAsmArch;
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
use rustc_target::spec::{
SanitizerSet, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel,
DebuginfoKind, SanitizerSet, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel,
};

use std::cell::{self, RefCell};
Expand Down Expand Up @@ -661,8 +661,9 @@ impl Session {
)
}

/// Returns `true` if the target can use the current split debuginfo configuration.
pub fn target_can_use_split_dwarf(&self) -> bool {
!self.target.is_like_windows && !self.target.is_like_osx
self.target.debuginfo_kind == DebuginfoKind::Dwarf
}

pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String {
Expand Down Expand Up @@ -1543,6 +1544,15 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
sess.err(&format!("requested DWARF version {} is greater than 5", dwarf_version));
}
}

if !sess.target.options.supported_split_debuginfo.contains(&sess.split_debuginfo())
&& !sess.opts.unstable_opts.unstable_options
{
sess.err(&format!(
"`-Csplit-debuginfo={}` is unstable on this platform",
sess.split_debuginfo()
));
}
}

/// Holds data on the current incremental compilation session, if there is one.
Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_target/src/spec/apple_base.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{borrow::Cow, env};

use crate::spec::{cvs, FramePointer, SplitDebuginfo, TargetOptions};
use crate::spec::{cvs, DebuginfoKind, FramePointer, SplitDebuginfo, TargetOptions};
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor};

fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> LinkArgs {
Expand Down Expand Up @@ -76,9 +76,15 @@ pub fn opts(os: &'static str, arch: &'static str, abi: &'static str) -> TargetOp
eh_frame_header: false,
lld_flavor: LldFlavor::Ld64,

debuginfo_kind: DebuginfoKind::DwarfDsym,
// The historical default for macOS targets is to run `dsymutil` which
// generates a packed version of debuginfo split from the main file.
split_debuginfo: SplitDebuginfo::Packed,
supported_split_debuginfo: Cow::Borrowed(&[
SplitDebuginfo::Packed,
SplitDebuginfo::Unpacked,
SplitDebuginfo::Off,
]),

// This environment variable is pretty magical but is intended for
// producing deterministic builds. This was first discovered to be used
Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_target/src/spec/linux_base.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::spec::{cvs, RelroLevel, TargetOptions};
use crate::spec::{cvs, RelroLevel, SplitDebuginfo, TargetOptions};
use std::borrow::Cow;

pub fn opts() -> TargetOptions {
TargetOptions {
Expand All @@ -10,6 +11,11 @@ pub fn opts() -> TargetOptions {
relro_level: RelroLevel::Full,
has_thread_local: true,
crt_static_respected: true,
supported_split_debuginfo: Cow::Borrowed(&[
SplitDebuginfo::Packed,
SplitDebuginfo::Unpacked,
SplitDebuginfo::Off,
]),
..Default::default()
}
}
104 changes: 99 additions & 5 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,23 +468,74 @@ impl fmt::Display for LinkOutputKind {

pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<StaticCow<str>>>;

#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)]
/// Which kind of debuginfo does the target use?
///
/// Useful in determining whether a target supports Split DWARF (a target with
/// `DebuginfoKind::Dwarf` and supporting `SplitDebuginfo::Unpacked` for example).
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
pub enum DebuginfoKind {
/// DWARF debuginfo (such as that used on `x86_64_unknown_linux_gnu`).
#[default]
Dwarf,
/// DWARF debuginfo in dSYM files (such as on Apple platforms).
DwarfDsym,
/// Program database files (such as on Windows).
Pdb,
}
wesleywiser marked this conversation as resolved.
Show resolved Hide resolved

impl DebuginfoKind {
fn as_str(&self) -> &'static str {
match self {
DebuginfoKind::Dwarf => "dwarf",
DebuginfoKind::DwarfDsym => "dwarf-dsym",
DebuginfoKind::Pdb => "pdb",
}
}
}

impl FromStr for DebuginfoKind {
type Err = ();

fn from_str(s: &str) -> Result<Self, ()> {
Ok(match s {
"dwarf" => DebuginfoKind::Dwarf,
"dwarf-dsym" => DebuginfoKind::DwarfDsym,
"pdb" => DebuginfoKind::Pdb,
_ => return Err(()),
})
}
}

impl ToJson for DebuginfoKind {
fn to_json(&self) -> Json {
self.as_str().to_json()
}
}

impl fmt::Display for DebuginfoKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}

#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
pub enum SplitDebuginfo {
/// Split debug-information is disabled, meaning that on supported platforms
/// you can find all debug information in the executable itself. This is
/// only supported for ELF effectively.
///
/// * Windows - not supported
/// * macOS - don't run `dsymutil`
/// * ELF - `.dwarf_*` sections
/// * ELF - `.debug_*` sections
#[default]
Off,

/// Split debug-information can be found in a "packed" location separate
/// from the final artifact. This is supported on all platforms.
///
/// * Windows - `*.pdb`
/// * macOS - `*.dSYM` (run `dsymutil`)
/// * ELF - `*.dwp` (run `rust-llvm-dwp`)
/// * ELF - `*.dwp` (run `thorin`)
Packed,

/// Split debug-information can be found in individual object files on the
Expand All @@ -509,7 +560,7 @@ impl SplitDebuginfo {
impl FromStr for SplitDebuginfo {
type Err = ();

fn from_str(s: &str) -> Result<SplitDebuginfo, ()> {
fn from_str(s: &str) -> Result<Self, ()> {
Ok(match s {
"off" => SplitDebuginfo::Off,
"unpacked" => SplitDebuginfo::Unpacked,
Expand Down Expand Up @@ -1435,9 +1486,13 @@ pub struct TargetOptions {
/// thumb and arm interworking.
pub has_thumb_interworking: bool,

/// Which kind of debuginfo is used by this target?
pub debuginfo_kind: DebuginfoKind,
/// How to handle split debug information, if at all. Specifying `None` has
/// target-specific meaning.
pub split_debuginfo: SplitDebuginfo,
/// Which kinds of split debuginfo are supported by the target?
pub supported_split_debuginfo: StaticCow<[SplitDebuginfo]>,

/// The sanitizers supported by this target
///
Expand Down Expand Up @@ -1595,7 +1650,10 @@ impl Default for TargetOptions {
use_ctors_section: false,
eh_frame_header: true,
has_thumb_interworking: false,
split_debuginfo: SplitDebuginfo::Off,
debuginfo_kind: Default::default(),
split_debuginfo: Default::default(),
// `Off` is supported by default, but targets can remove this manually, e.g. Windows.
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
supported_sanitizers: SanitizerSet::empty(),
default_adjusted_cabi: None,
c_enum_min_bits: 32,
Expand Down Expand Up @@ -1868,6 +1926,19 @@ impl Target {
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, DebuginfoKind) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<DebuginfoKind>() {
Ok(level) => base.$key_name = level,
_ => return Some(Err(
format!("'{s}' is not a valid value for debuginfo-kind. Use 'dwarf', \
'dwarf-dsym' or 'pdb'.")
)),
}
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, SplitDebuginfo) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
Expand Down Expand Up @@ -1904,6 +1975,25 @@ impl Target {
}
}
} );
($key_name:ident, falliable_list) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.remove(&name).and_then(|j| {
if let Some(v) = j.as_array() {
match v.iter().map(|a| FromStr::from_str(a.as_str().unwrap())).collect() {
Ok(l) => { base.$key_name = l },
// FIXME: `falliable_list` can't re-use the `key!` macro for list
// elements and the error messages from that macro, so it has a bad
// generic message instead
Err(_) => return Some(Err(
format!("`{:?}` is not a valid value for `{}`", j, name)
)),
}
} else {
incorrect_type.push(name)
}
Some(Ok(()))
}).unwrap_or(Ok(()))
} );
($key_name:ident, optional) => ( {
let name = (stringify!($key_name)).replace("_", "-");
if let Some(o) = obj.remove(&name) {
Expand Down Expand Up @@ -2190,7 +2280,9 @@ impl Target {
key!(use_ctors_section, bool);
key!(eh_frame_header, bool);
key!(has_thumb_interworking, bool);
key!(debuginfo_kind, DebuginfoKind)?;
key!(split_debuginfo, SplitDebuginfo)?;
key!(supported_split_debuginfo, falliable_list)?;
key!(supported_sanitizers, SanitizerSet)?;
key!(default_adjusted_cabi, Option<Abi>)?;
key!(c_enum_min_bits, u64);
Expand Down Expand Up @@ -2434,7 +2526,9 @@ impl ToJson for Target {
target_option_val!(use_ctors_section);
target_option_val!(eh_frame_header);
target_option_val!(has_thumb_interworking);
target_option_val!(debuginfo_kind);
target_option_val!(split_debuginfo);
target_option_val!(supported_split_debuginfo);
target_option_val!(supported_sanitizers);
target_option_val!(c_enum_min_bits);
target_option_val!(generate_arange_section);
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_target/src/spec/msvc_base.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::spec::{LinkerFlavor, LldFlavor, SplitDebuginfo, TargetOptions};
use std::borrow::Cow;

pub fn opts() -> TargetOptions {
// Suppress the verbose logo and authorship debugging output, which would needlessly
Expand All @@ -18,6 +19,7 @@ pub fn opts() -> TargetOptions {
// Currently this is the only supported method of debuginfo on MSVC
// where `*.pdb` files show up next to the final artifact.
split_debuginfo: SplitDebuginfo::Packed,
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Packed]),

..Default::default()
}
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_target/src/spec/windows_gnu_base.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::spec::crt_objects::{self, LinkSelfContainedDefault};
use crate::spec::{cvs, LinkerFlavor, TargetOptions};
use crate::spec::{cvs, DebuginfoKind, LinkerFlavor, SplitDebuginfo, TargetOptions};
use std::borrow::Cow;

pub fn opts() -> TargetOptions {
let mut pre_link_args = TargetOptions::link_args(
Expand Down Expand Up @@ -86,6 +87,10 @@ pub fn opts() -> TargetOptions {
emit_debug_gdb_scripts: false,
requires_uwtable: true,
eh_frame_header: false,
// FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to
// output DWO, despite using DWARF, doesn't use ELF..
debuginfo_kind: DebuginfoKind::Pdb,
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wesleywiser is this correct? We spoke about Split DWARF technically being possible on Windows GNU before, but I find that if I say debuginfo_kind: DebuginfoKind::Dwarf then LLVM complains that the target can't output a DWO because it doesn't use ELF.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not super familiar with *-windows-gnu but from what I can see, it looks like rustc generates a single output file (ie, there is no .dwo or .pdb) and that output file contains embedded DWARF debuginfo.

Eg:

$ rustc --target x86_64-pc-windows-gnu -g --crate-name hello_world_gnu hello_world.rs
$ ls | grep hello_world_gnu
hello_world_gnu.exe
$ objdump -W hello_world_gnu.exe 
hello_world_gnu.exe:     file format pei-x86-64

...
Contents of the .debug_info section:

...
  Compilation Unit @ offset 0x2948:
   Length:        0xad (32-bit)
   Version:       4
   Abbrev Offset: 0x5a2
   Pointer Size:  8
 <0><2953>: Abbrev Number: 1 (DW_TAG_compile_unit)
    <2954>   DW_AT_producer    : (indirect string, offset: 0x21f): clang LLVM (rustc version 1.65.0-nightly (0b79f758c 2022-08-18))
    <2958>   DW_AT_language    : 28     (Rust)
    <295a>   DW_AT_name        : (indirect string, offset: 0x260): hello_world.rs\@\hello_world_gnu.2deb01f1-cgu.0
    <295e>   DW_AT_stmt_list   : 0x486
    <2962>   DW_AT_comp_dir    : (indirect string, offset: 0x290): D:\code\temp
    <2966>   DW_AT_GNU_pubnames: 1
    <2966>   DW_AT_low_pc      : 0x140001530
    <296e>   DW_AT_high_pc     : 0x5
...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, when I set DebuginfoKind::Dwarf for that target, then we got this error..

LLVM ERROR: dwo only supported with ELF and Wasm

..which makes sense when your output shows..

hello_world_gnu.exe:     file format pei-x86-64

..so it looks like Split DWARF would technically be possible on Windows GNU, but LLVM would need to support DWARF objects on PEI first, and then I would need to extend thorin to package DWARF in PEI. But what all of that does mean, is that despite windows-gnu using DWARF, I can't set it to DebuginfoKind::Dwarf (there's probably still something up because DebuginfoKind::Dwarf and supported_split_debuginfo: &[SplitDebuginfo::Off] shouldn't make LLVM do anything).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading Appendix F in the DWARF 5 spec, I don't see why an ELF binary would be required. It seems like the appropriate sections could be placed in the PE file the same way the DWARF is but I could be missing something.

Copy link
Member Author

@davidtwco davidtwco Aug 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading Appendix F in the DWARF 5 spec, I don't see why an ELF binary would be required. It seems like the appropriate sections could be placed in the PE file the same way the DWARF is but I could be missing something.

Yeah, I don't think it is required by DWARF, just seems like a LLVM limitation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On an unrelated note, I think we could probably support SplitDebuginfo::Unpacked on *-windows-mscv via the /DEBUG:FASTLINK option which sounds pretty much like the equivalent split DWARF behavior. I'll put that on my todo list to look into.

..Default::default()
}
}
3 changes: 2 additions & 1 deletion compiler/rustc_target/src/spec/windows_msvc_base.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::spec::{cvs, TargetOptions};
use crate::spec::{cvs, DebuginfoKind, TargetOptions};

pub fn opts() -> TargetOptions {
let base = super::msvc_base::opts();
Expand Down Expand Up @@ -28,6 +28,7 @@ pub fn opts() -> TargetOptions {
// not ever be possible for us to pass this flag.
no_default_libraries: false,
has_thread_local: true,
debuginfo_kind: DebuginfoKind::Pdb,

..base
}
Expand Down
30 changes: 14 additions & 16 deletions src/bootstrap/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1759,23 +1759,21 @@ impl<'a> Builder<'a> {
},
);

if !target.contains("windows") {
let needs_unstable_opts = target.contains("linux")
|| target.contains("solaris")
|| target.contains("windows")
|| target.contains("bsd")
|| target.contains("dragonfly")
|| target.contains("illumos");

if needs_unstable_opts {
rustflags.arg("-Zunstable-options");
}
match self.config.rust_split_debuginfo {
SplitDebuginfo::Packed => rustflags.arg("-Csplit-debuginfo=packed"),
SplitDebuginfo::Unpacked => rustflags.arg("-Csplit-debuginfo=unpacked"),
SplitDebuginfo::Off => rustflags.arg("-Csplit-debuginfo=off"),
};
let split_debuginfo_is_stable = target.contains("linux")
|| target.contains("apple")
|| (target.contains("msvc")
&& self.config.rust_split_debuginfo == SplitDebuginfo::Packed)
|| (target.contains("windows")
&& self.config.rust_split_debuginfo == SplitDebuginfo::Off);

if !split_debuginfo_is_stable {
rustflags.arg("-Zunstable-options");
}
match self.config.rust_split_debuginfo {
SplitDebuginfo::Packed => rustflags.arg("-Csplit-debuginfo=packed"),
SplitDebuginfo::Unpacked => rustflags.arg("-Csplit-debuginfo=unpacked"),
SplitDebuginfo::Off => rustflags.arg("-Csplit-debuginfo=off"),
};

if self.config.cmd.bless() {
// Bless `expect!` tests.
Expand Down
4 changes: 2 additions & 2 deletions src/test/incremental/split_debuginfo_cached.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
// only-x86_64-unknown-linux-gnu
// revisions:rpass1 rpass2

// [rpass1]compile-flags: -g -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split
// [rpass2]compile-flags: -g -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split
// [rpass1]compile-flags: -g -Zquery-dep-graph -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split
// [rpass2]compile-flags: -g -Zquery-dep-graph -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split

#![feature(rustc_attrs)]
// For `rpass2`, nothing has changed so everything should re-used.
Expand Down
8 changes: 4 additions & 4 deletions src/test/incremental/split_debuginfo_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
// only-x86_64-unknown-linux-gnu
// revisions:rpass1 rpass2 rpass3 rpass4

// [rpass1]compile-flags: -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=unpacked -Zsplit-dwarf-kind=single -Zsplit-dwarf-inlining=on
// [rpass2]compile-flags: -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=single -Zsplit-dwarf-inlining=on
// [rpass3]compile-flags: -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split -Zsplit-dwarf-inlining=on
// [rpass4]compile-flags: -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split -Zsplit-dwarf-inlining=off
// [rpass1]compile-flags: -Zquery-dep-graph -Csplit-debuginfo=unpacked -Zsplit-dwarf-kind=single -Zsplit-dwarf-inlining=on
// [rpass2]compile-flags: -Zquery-dep-graph -Csplit-debuginfo=packed -Zsplit-dwarf-kind=single -Zsplit-dwarf-inlining=on
// [rpass3]compile-flags: -Zquery-dep-graph -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split -Zsplit-dwarf-inlining=on
// [rpass4]compile-flags: -Zquery-dep-graph -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split -Zsplit-dwarf-inlining=off

#![feature(rustc_attrs)]
// For rpass2 we change -Csplit-debuginfo and thus expect every CGU to be recompiled
Expand Down
Loading