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

Support zstd-compressed ELF sections. #625

Closed
wants to merge 2 commits into from
Closed
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
16 changes: 16 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ jobs:
rust: beta
- os: ubuntu-20.04
rust: nightly
- os: ubuntu-24.04
rust: stable
- os: ubuntu-24.04
rust: beta
- os: ubuntu-24.04
rust: nightly
- os: macos-latest
rust: stable
- os: macos-latest
Expand All @@ -48,6 +54,12 @@ jobs:
- run: echo RUSTFLAGS=-Dwarnings >> $GITHUB_ENV
shell: bash

# Starting with Ubuntu 22.04 libc6-dbg is needed.
- name: Install libc debug info
run: sudo apt-get install -y libc6-dbg
shell: bash
if: contains(matrix.os, 'ubuntu-24.04')

# full fidelity of backtraces on 32-bit msvc requires frame pointers, so
# enable that for our tests
- name: Force frame pointers
Expand Down Expand Up @@ -85,6 +97,10 @@ jobs:
if: contains(matrix.os, 'ubuntu')
env:
RUSTFLAGS: "-C link-arg=-Wl,--compress-debug-sections=zlib-gnu"
- run: cargo test
if: contains(matrix.os, 'ubuntu-24.04')
env:
RUSTFLAGS: "-C link-arg=-Wl,--compress-debug-sections=zstd"

# Test that, on macOS, packed/unpacked debuginfo both work
- run: cargo clean && cargo test
Expand Down
49 changes: 49 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 12 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,21 @@ cpp_demangle = { default-features = false, version = "0.4.0", optional = true, f
"alloc",
] }

[target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies]
miniz_oxide = { version = "0.7.0", default-features = false }
# MSVC uses PDB, not DWARF. But UWP doesn't allow for APIs gimli (via addr2line) uses,
# so skip that too.
[target.'cfg(not(any(target_env = "msvc", target_vendor = "uwp")))'.dependencies]
addr2line = { version = "0.22.0", default-features = false }
libc = { version = "0.2.146", default-features = false }

[target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies.object]
# Windows uses PE, not ELF, so libraries for ELF compression are unnecessary.
[target.'cfg(not(windows))'.dependencies]
miniz_oxide = { version = "0.7.0", default-features = false }

# Also used for ELF compression, but doesn't build on illumos in CI.
[target.'cfg(not(any(windows, target_os = "illumos")))'.dependencies]
zstd = { version = "= 0.13.0", default-features = false }
Copy link
Member

@bjorn3 bjorn3 May 24, 2024

Choose a reason for hiding this comment

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

Using the C implementation of zstd makes cross-compilation harder, especially for miri which currently is able to test for any supported target without installing any toolchain for the target.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I discussed that in the commit message. I could disable this for miri too.


[target.'cfg(not(any(target_env = "msvc", target_vendor = "uwp")))'.dependencies.object]
version = "0.35.0"
default-features = false
features = ['read_core', 'elf', 'macho', 'pe', 'xcoff', 'unaligned', 'archive']
Expand Down
1 change: 1 addition & 0 deletions ci/docker/arm-linux-androideabi/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ ENV PATH=$PATH:/android-toolchain/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin

# TODO: run tests in an emulator eventually
ENV CARGO_TARGET_ARM_LINUX_ANDROIDEABI_LINKER=armv7a-linux-androideabi19-clang \
CC=armv7a-linux-androideabi19-clang \
CARGO_TARGET_ARM_LINUX_ANDROIDEABI_RUNNER=echo
1 change: 1 addition & 0 deletions ci/docker/armv7-linux-androideabi/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ ENV PATH=$PATH:/android-toolchain/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin

# TODO: run tests in an emulator eventually
ENV CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER=armv7a-linux-androideabi19-clang \
CC=armv7a-linux-androideabi19-clang \
CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_RUNNER=echo
1 change: 1 addition & 0 deletions ci/docker/i686-linux-android/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ ENV PATH=$PATH:/android-toolchain/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin

# TODO: run tests in an emulator eventually
ENV CARGO_TARGET_I686_LINUX_ANDROID_LINKER=i686-linux-android19-clang \
CC=i686-linux-android19-clang \
CARGO_TARGET_I686_LINUX_ANDROID_RUNNER=echo
13 changes: 9 additions & 4 deletions crates/as-if-std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@ bench = false
[dependencies]
cfg-if = "1.0"
rustc-demangle = "0.1.21"

[target.'cfg(not(any(target_env = "msvc", target_vendor = "uwp")))'.dependencies]
libc = { version = "0.2.146", default-features = false }
addr2line = { version = "0.22.0", optional = true, default-features = false }

[target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies]
[target.'cfg(not(windows))'.dependencies]
miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
addr2line = { version = "0.22.0", optional = true, default-features = false }

[target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies.object]
[target.'cfg(not(any(windows, target_os = "illumos")))'.dependencies]
zstd = { version = "= 0.13.0", optional = true, default-features = false }

[target.'cfg(not(any(target_env = "msvc", target_vendor = "uwp")))'.dependencies.object]
version = "0.35.0"
default-features = false
optional = true
Expand All @@ -32,7 +37,7 @@ cc = "1.0.90"

[features]
default = ['backtrace']
backtrace = ['addr2line', 'miniz_oxide', 'object']
backtrace = ['addr2line', 'miniz_oxide', 'object', 'zstd']
std = []

[lints.rust]
Expand Down
32 changes: 24 additions & 8 deletions src/symbolize/gimli/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use super::{gimli, Context, Endian, EndianSlice, Mapping, Stash, Vec};
use alloc::sync::Arc;
use core::convert::{TryFrom, TryInto};
use core::str;
#[cfg(not(target_os = "illumos"))]
use object::elf::ELFCOMPRESS_ZSTD;
use object::elf::{ELFCOMPRESS_ZLIB, ELF_NOTE_GNU, NT_GNU_BUILD_ID, SHF_COMPRESSED};
use object::read::elf::{CompressionHeader, FileHeader, SectionHeader, SectionTable, Sym};
use object::read::StringTable;
Expand Down Expand Up @@ -170,22 +172,31 @@ impl<'a> Object<'a> {
let mut data = Bytes(section.data(self.endian, self.data).ok()?);

// Check for DWARF-standard (gABI) compression, i.e., as generated
// by ld's `--compress-debug-sections=zlib-gabi` flag.
// by ld's `--compress-debug-sections=zlib-gabi` and
// `--compress-debug-sections=zstd` flags.
let flags: u64 = section.sh_flags(self.endian).into();
if (flags & u64::from(SHF_COMPRESSED)) == 0 {
// Not compressed.
return Some(data.0);
}

let header = data.read::<<Elf as FileHeader>::CompressionHeader>().ok()?;
if header.ch_type(self.endian) != ELFCOMPRESS_ZLIB {
// Zlib compression is the only known type.
return None;
match header.ch_type(self.endian) {
ELFCOMPRESS_ZLIB => {
let size = usize::try_from(header.ch_size(self.endian)).ok()?;
let buf = stash.allocate(size);
decompress_zlib(data.0, buf)?;
return Some(buf);
}
#[cfg(not(target_os = "illumos"))]
ELFCOMPRESS_ZSTD => {
let size = usize::try_from(header.ch_size(self.endian)).ok()?;
let buf = stash.allocate(size);
decompress_zstd(data.0, buf)?;
return Some(buf);
}
_ => return None, // Unknown compression type.
}
let size = usize::try_from(header.ch_size(self.endian)).ok()?;
let buf = stash.allocate(size);
decompress_zlib(data.0, buf)?;
return Some(buf);
}

// Check for the nonstandard GNU compression format, i.e., as generated
Expand Down Expand Up @@ -304,6 +315,11 @@ fn decompress_zlib(input: &[u8], output: &mut [u8]) -> Option<()> {
}
}

#[cfg(not(target_os = "illumos"))]
fn decompress_zstd(input: &[u8], output: &mut [u8]) -> Option<()> {
zstd::stream::copy_decode(input, output).ok()
}

const DEBUG_PATH: &[u8] = b"/usr/lib/debug";

fn debug_path_exists() -> bool {
Expand Down
Loading