diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0103a099..b3201166 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -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 @@ -55,6 +61,12 @@ jobs: shell: bash if: contains(matrix.rust, 'i686') + # 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') + - name: Enable collapse_debuginfo based on version run: echo RUSTFLAGS="--cfg dbginfo=\"collapsible\" $RUSTFLAGS" >> $GITHUB_ENV shell: bash @@ -80,6 +92,10 @@ jobs: if: contains(matrix.os, 'ubuntu') env: RUSTFLAGS: "-C link-arg=-Wl,--compress-debug-sections=zlib" + - run: cargo test + if: contains(matrix.os, 'ubuntu-24.04') || contains(matrix.rust, 'nightly') + env: + RUSTFLAGS: "-C link-arg=-Wl,--compress-debug-sections=zstd" # Test that, on macOS, packed/unpacked debuginfo both work - run: cargo clean && cargo test diff --git a/Cargo.lock b/Cargo.lock index 8f4388b0..ea6b625f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,6 +27,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", + "ruzstd", "windows-targets", ] @@ -43,6 +44,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", + "ruzstd", "serde", "windows-targets", ] @@ -150,6 +152,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "ruzstd" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99c3938e133aac070997ddc684d4b393777d293ba170f2988c8fd5ea2ad4ce21" + [[package]] name = "serde" version = "1.0.203" diff --git a/Cargo.toml b/Cargo.toml index 00e9b246..46ee959a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ windows-targets = "0.52.6" [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies] miniz_oxide = { version = "0.8", default-features = false } +ruzstd = { version = "0.7.2", default-features = false } addr2line = { version = "0.24.0", default-features = false } libc = { version = "0.2.156", default-features = false } diff --git a/crates/as-if-std/Cargo.toml b/crates/as-if-std/Cargo.toml index a9c29cec..092905fe 100644 --- a/crates/as-if-std/Cargo.toml +++ b/crates/as-if-std/Cargo.toml @@ -18,6 +18,7 @@ libc = { version = "0.2.156", default-features = false } [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies] miniz_oxide = { version = "0.8", optional = true, default-features = false } +ruzstd = { version = "0.7.2", optional = true, default-features = false } addr2line = { version = "0.24.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies.object] @@ -31,7 +32,7 @@ windows-targets = "0.52.6" [features] default = ['backtrace'] -backtrace = ['addr2line', 'miniz_oxide', 'object'] +backtrace = ['addr2line', 'miniz_oxide', 'object', 'ruzstd'] std = [] [lints.rust] diff --git a/src/symbolize/gimli/elf.rs b/src/symbolize/gimli/elf.rs index 82c53df0..f920a6fe 100644 --- a/src/symbolize/gimli/elf.rs +++ b/src/symbolize/gimli/elf.rs @@ -9,7 +9,9 @@ use super::{gimli, Context, Endian, EndianSlice, Mapping, Stash, Vec}; use alloc::sync::Arc; use core::convert::{TryFrom, TryInto}; use core::str; -use object::elf::{ELFCOMPRESS_ZLIB, ELF_NOTE_GNU, NT_GNU_BUILD_ID, SHF_COMPRESSED}; +use object::elf::{ + ELFCOMPRESS_ZLIB, ELFCOMPRESS_ZSTD, ELF_NOTE_GNU, NT_GNU_BUILD_ID, SHF_COMPRESSED, +}; use object::read::elf::{CompressionHeader, FileHeader, SectionHeader, SectionTable, Sym}; use object::read::StringTable; use object::{BigEndian, Bytes, NativeEndian}; @@ -213,7 +215,8 @@ 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. @@ -221,14 +224,21 @@ impl<'a> Object<'a> { } let header = data.read::<::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); + } + 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 @@ -347,6 +357,13 @@ fn decompress_zlib(input: &[u8], output: &mut [u8]) -> Option<()> { } } +fn decompress_zstd(input: &[u8], output: &mut [u8]) -> Option<()> { + use ruzstd::io::Read; + + let mut decoder = ruzstd::StreamingDecoder::new(input).ok()?; + decoder.read_exact(output).ok() +} + const DEBUG_PATH: &[u8] = b"/usr/lib/debug"; fn debug_path_exists() -> bool {