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

debuginfo: add compiler option to allow compressed debuginfo sections #115358

Merged
merged 6 commits into from
Sep 9, 2023
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
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_llvm/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ codegen_llvm_unknown_ctarget_feature_prefix =
unknown feature specified for `-Ctarget-feature`: `{$feature}`
.note = features must begin with a `+` to enable or `-` to disable it
codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo
codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
codegen_llvm_write_ir = failed to write LLVM IR to {$path}
Expand Down
30 changes: 26 additions & 4 deletions compiler/rustc_codegen_llvm/src/back/lto.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::back::write::{self, save_temp_bitcode, CodegenDiagnosticsStage, DiagnosticHandlers};
use crate::back::write::{
self, bitcode_section_name, save_temp_bitcode, CodegenDiagnosticsStage, DiagnosticHandlers,
};
use crate::errors::{
DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib,
};
Expand Down Expand Up @@ -120,6 +122,7 @@ fn prepare_lto(
info!("adding bitcode from {}", name);
match get_bitcode_slice_from_object_data(
child.data(&*archive_data).expect("corrupt rlib"),
cgcx,
) {
Ok(data) => {
let module = SerializedModule::FromRlib(data.to_vec());
Expand All @@ -141,10 +144,29 @@ fn prepare_lto(
Ok((symbols_below_threshold, upstream_modules))
}

fn get_bitcode_slice_from_object_data(obj: &[u8]) -> Result<&[u8], LtoBitcodeFromRlib> {
fn get_bitcode_slice_from_object_data<'a>(
obj: &'a [u8],
cgcx: &CodegenContext<LlvmCodegenBackend>,
) -> Result<&'a [u8], LtoBitcodeFromRlib> {
// We're about to assume the data here is an object file with sections, but if it's raw LLVM IR that
// won't work. Fortunately, if that's what we have we can just return the object directly, so we sniff
// the relevant magic strings here and return.
if obj.starts_with(b"\xDE\xC0\x17\x0B") || obj.starts_with(b"BC\xC0\xDE") {
return Ok(obj);
}
// We drop the "__LLVM," prefix here because on Apple platforms there's a notion of "segment name"
// which in the public API for sections gets treated as part of the section name, but internally
// in MachOObjectFile.cpp gets treated separately.
let section_name = bitcode_section_name(cgcx).trim_start_matches("__LLVM,");
let mut len = 0;
let data =
unsafe { llvm::LLVMRustGetBitcodeSliceFromObjectData(obj.as_ptr(), obj.len(), &mut len) };
let data = unsafe {
llvm::LLVMRustGetSliceFromObjectDataByName(
obj.as_ptr(),
obj.len(),
section_name.as_ptr(),
&mut len,
)
};
if !data.is_null() {
assert!(len != 0);
let bc = unsafe { slice::from_raw_parts(data, len) };
Expand Down
59 changes: 46 additions & 13 deletions compiler/rustc_codegen_llvm/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ use crate::back::profiling::{
use crate::base;
use crate::common;
use crate::errors::{
CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, WithLlvmError, WriteBytecode,
CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, UnknownCompression,
WithLlvmError, WriteBytecode,
};
use crate::llvm::{self, DiagnosticInfo, PassManager};
use crate::llvm_util;
use crate::type_::Type;
use crate::LlvmCodegenBackend;
use crate::ModuleLlvm;
use llvm::{
LLVMRustLLVMHasZlibCompressionForDebugSymbols, LLVMRustLLVMHasZstdCompressionForDebugSymbols,
};
use rustc_codegen_ssa::back::link::ensure_removed;
use rustc_codegen_ssa::back::write::{
BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig,
Expand Down Expand Up @@ -234,6 +238,22 @@ pub fn target_machine_factory(
args_cstr_buff
};

let debuginfo_compression = sess.opts.debuginfo_compression.to_string();
match sess.opts.debuginfo_compression {
rustc_session::config::DebugInfoCompression::Zlib => {
if !unsafe { LLVMRustLLVMHasZlibCompressionForDebugSymbols() } {
sess.emit_warning(UnknownCompression { algorithm: "zlib" });
}
}
rustc_session::config::DebugInfoCompression::Zstd => {
if !unsafe { LLVMRustLLVMHasZstdCompressionForDebugSymbols() } {
sess.emit_warning(UnknownCompression { algorithm: "zstd" });
}
}
rustc_session::config::DebugInfoCompression::None => {}
};
let debuginfo_compression = SmallCStr::new(&debuginfo_compression);

Arc::new(move |config: TargetMachineFactoryConfig| {
let split_dwarf_file =
path_mapping.map_prefix(config.split_dwarf_file.unwrap_or_default()).0;
Expand All @@ -259,6 +279,7 @@ pub fn target_machine_factory(
relax_elf_relocations,
use_init_array,
split_dwarf_file.as_ptr(),
debuginfo_compression.as_ptr(),
force_emulated_tls,
args_cstr_buff.as_ptr() as *const c_char,
args_cstr_buff.len(),
Expand Down Expand Up @@ -873,6 +894,27 @@ fn create_section_with_flags_asm(section_name: &str, section_flags: &str, data:
asm
}

fn target_is_apple(cgcx: &CodegenContext<LlvmCodegenBackend>) -> bool {
cgcx.opts.target_triple.triple().contains("-ios")
|| cgcx.opts.target_triple.triple().contains("-darwin")
|| cgcx.opts.target_triple.triple().contains("-tvos")
|| cgcx.opts.target_triple.triple().contains("-watchos")
}

fn target_is_aix(cgcx: &CodegenContext<LlvmCodegenBackend>) -> bool {
cgcx.opts.target_triple.triple().contains("-aix")
}

pub(crate) fn bitcode_section_name(cgcx: &CodegenContext<LlvmCodegenBackend>) -> &'static str {
if target_is_apple(cgcx) {
"__LLVM,__bitcode\0"
} else if target_is_aix(cgcx) {
".ipa\0"
} else {
".llvmbc\0"
}
}

/// Embed the bitcode of an LLVM module in the LLVM module itself.
///
/// This is done primarily for iOS where it appears to be standard to compile C
Expand Down Expand Up @@ -933,11 +975,8 @@ unsafe fn embed_bitcode(
// Unfortunately, LLVM provides no way to set custom section flags. For ELF
// and COFF we emit the sections using module level inline assembly for that
// reason (see issue #90326 for historical background).
let is_aix = cgcx.opts.target_triple.triple().contains("-aix");
let is_apple = cgcx.opts.target_triple.triple().contains("-ios")
|| cgcx.opts.target_triple.triple().contains("-darwin")
|| cgcx.opts.target_triple.triple().contains("-tvos")
|| cgcx.opts.target_triple.triple().contains("-watchos");
let is_aix = target_is_aix(cgcx);
let is_apple = target_is_apple(cgcx);
if is_apple
|| is_aix
|| cgcx.opts.target_triple.triple().starts_with("wasm")
Expand All @@ -952,13 +991,7 @@ unsafe fn embed_bitcode(
);
llvm::LLVMSetInitializer(llglobal, llconst);

let section = if is_apple {
"__LLVM,__bitcode\0"
} else if is_aix {
".ipa\0"
} else {
".llvmbc\0"
};
let section = bitcode_section_name(cgcx);
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_codegen_llvm/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,9 @@ pub(crate) struct WriteBytecode<'a> {
pub(crate) struct CopyBitcode {
pub err: std::io::Error,
}

#[derive(Diagnostic)]
#[diag(codegen_llvm_unknown_debuginfo_compression)]
pub struct UnknownCompression {
pub algorithm: &'static str,
}
11 changes: 11 additions & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2131,6 +2131,7 @@ extern "C" {
RelaxELFRelocations: bool,
UseInitArray: bool,
SplitDwarfFile: *const c_char,
DebugInfoCompression: *const c_char,
ForceEmulatedTls: bool,
ArgsCstrBuff: *const c_char,
ArgsCstrBuffLen: usize,
Expand Down Expand Up @@ -2322,6 +2323,12 @@ extern "C" {
len: usize,
out_len: &mut usize,
) -> *const u8;
pub fn LLVMRustGetSliceFromObjectDataByName(
data: *const u8,
len: usize,
name: *const u8,
out_len: &mut usize,
) -> *const u8;

pub fn LLVMRustLinkerNew(M: &Module) -> &mut Linker<'_>;
pub fn LLVMRustLinkerAdd(
Expand Down Expand Up @@ -2360,6 +2367,10 @@ extern "C" {

pub fn LLVMRustIsBitcode(ptr: *const u8, len: usize) -> bool;

pub fn LLVMRustLLVMHasZlibCompressionForDebugSymbols() -> bool;

pub fn LLVMRustLLVMHasZstdCompressionForDebugSymbols() -> bool;

pub fn LLVMRustGetSymbols(
buf_ptr: *const u8,
buf_len: usize,
Expand Down
44 changes: 44 additions & 0 deletions compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <stdio.h>

#include <cstddef>
#include <iomanip>
#include <vector>
#include <set>
Expand Down Expand Up @@ -406,6 +407,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
bool RelaxELFRelocations,
bool UseInitArray,
const char *SplitDwarfFile,
const char *DebugInfoCompression,
bool ForceEmulatedTls,
const char *ArgsCstrBuff, size_t ArgsCstrBuffLen) {

Expand Down Expand Up @@ -437,6 +439,16 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
if (SplitDwarfFile) {
Options.MCOptions.SplitDwarfFile = SplitDwarfFile;
}
#if LLVM_VERSION_GE(16, 0)
if (!strcmp("zlib", DebugInfoCompression) && llvm::compression::zlib::isAvailable()) {
Options.CompressDebugSections = DebugCompressionType::Zlib;
} else if (!strcmp("zstd", DebugInfoCompression) && llvm::compression::zstd::isAvailable()) {
Options.CompressDebugSections = DebugCompressionType::Zstd;
} else if (!strcmp("none", DebugInfoCompression)) {
Options.CompressDebugSections = DebugCompressionType::None;
}
#endif

Options.RelaxELFRelocations = RelaxELFRelocations;
Options.UseInitArray = UseInitArray;

Expand Down Expand Up @@ -1555,6 +1567,38 @@ LLVMRustGetBitcodeSliceFromObjectData(const char *data,
return BitcodeOrError->getBufferStart();
}

// Find a section of an object file by name. Fail if the section is missing or
// empty.
extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data,
size_t len,
const char *name,
size_t *out_len) {
*out_len = 0;
StringRef Data(data, len);
MemoryBufferRef Buffer(Data, ""); // The id is unused.
file_magic Type = identify_magic(Buffer.getBuffer());
Expected<std::unique_ptr<object::ObjectFile>> ObjFileOrError =
object::ObjectFile::createObjectFile(Buffer, Type);
if (!ObjFileOrError) {
LLVMRustSetLastError(toString(ObjFileOrError.takeError()).c_str());
return nullptr;
}
for (const object::SectionRef &Sec : (*ObjFileOrError)->sections()) {
Expected<StringRef> Name = Sec.getName();
if (Name && *Name == name) {
Expected<StringRef> SectionOrError = Sec.getContents();
if (!SectionOrError) {
LLVMRustSetLastError(toString(SectionOrError.takeError()).c_str());
return nullptr;
}
*out_len = SectionOrError->size();
return SectionOrError->data();
}
}
LLVMRustSetLastError("could not find requested section");
return nullptr;
}

// Computes the LTO cache key for the provided 'ModId' in the given 'Data',
// storing the result in 'KeyOut'.
// Currently, this cache key is a SHA-1 hash of anything that could affect
Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2044,3 +2044,19 @@ extern "C" bool LLVMRustIsNonGVFunctionPointerTy(LLVMValueRef V) {
}
return false;
}

extern "C" bool LLVMRustLLVMHasZlibCompressionForDebugSymbols() {
#if LLVM_VERSION_GE(16, 0)
return llvm::compression::zlib::isAvailable();
#else
return false;
#endif
}

extern "C" bool LLVMRustLLVMHasZstdCompressionForDebugSymbols() {
#if LLVM_VERSION_GE(16, 0)
return llvm::compression::zstd::isAvailable();
#else
return false;
#endif
}
40 changes: 35 additions & 5 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,24 @@ pub enum DebugInfo {
Full,
}

#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub enum DebugInfoCompression {
None,
Zlib,
Zstd,
}

impl ToString for DebugInfoCompression {
fn to_string(&self) -> String {
match self {
DebugInfoCompression::None => "none",
DebugInfoCompression::Zlib => "zlib",
DebugInfoCompression::Zstd => "zstd",
}
.to_owned()
}
}

/// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
/// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
/// uses DWARF for debug-information.
Expand Down Expand Up @@ -1015,6 +1033,7 @@ impl Default for Options {
crate_types: Vec::new(),
optimize: OptLevel::No,
debuginfo: DebugInfo::None,
debuginfo_compression: DebugInfoCompression::None,
lint_opts: Vec::new(),
lint_cap: None,
describe_lints: false,
Expand Down Expand Up @@ -2277,6 +2296,13 @@ fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInf
if max_g > max_c { DebugInfo::Full } else { cg.debuginfo }
}

fn select_debuginfo_compression(
_handler: &EarlyErrorHandler,
unstable_opts: &UnstableOptions,
) -> DebugInfoCompression {
unstable_opts.debuginfo_compression
}

pub(crate) fn parse_assert_incr_state(
handler: &EarlyErrorHandler,
opt_assertion: &Option<String>,
Expand Down Expand Up @@ -2752,6 +2778,8 @@ pub fn build_session_options(
// for more details.
let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
let debuginfo = select_debuginfo(matches, &cg);
let debuginfo_compression: DebugInfoCompression =
select_debuginfo_compression(handler, &unstable_opts);

let mut search_paths = vec![];
for s in &matches.opt_strs("L") {
Expand Down Expand Up @@ -2828,6 +2856,7 @@ pub fn build_session_options(
crate_types,
optimize: opt_level,
debuginfo,
debuginfo_compression,
lint_opts,
lint_cap,
describe_lints,
Expand Down Expand Up @@ -3113,11 +3142,11 @@ impl PpMode {
/// how the hash should be calculated when adding a new command-line argument.
pub(crate) mod dep_tracking {
use super::{
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto, LocationDetail, LtoCli,
OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Passes, ResolveDocLinks,
SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion,
TraitSolver, TrimmedDefPaths,
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression,
ErrorOutputType, InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto,
LocationDetail, LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes,
Passes, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath,
SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
};
use crate::lint;
use crate::options::WasiExecModel;
Expand Down Expand Up @@ -3195,6 +3224,7 @@ pub(crate) mod dep_tracking {
OptLevel,
LtoCli,
DebugInfo,
DebugInfoCompression,
UnstableFeatures,
NativeLib,
NativeLibKind,
Expand Down
Loading