diff --git a/CHANGELOG.md b/CHANGELOG.md index 393906860..0c565c5e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,24 +2,22 @@ ## Unreleased -**Internal** +**Features** -- Update tokio to latest version ([#833](https://github.com/getsentry/symbolic/pull/833)) -- Fix infinite recursion caused by indirect self-references when resolving function names ([#836](https://github.com/getsentry/symbolic/pull/836)) -- Switch to workspace dependencies ([#841](https://github.com/getsentry/symbolic/pull/841)) +- Add support for reading `zstd` compressed ELF debug section ([#843](https://github.com/getsentry/symbolic/pull/843)) **Fixes** - sourcebundles: Only valid UTF-8 files can be written into sourcebundles ([#816](https://github.com/getsentry/symbolic/pull/816)) - Fix an issue when extracting the name of the debug file from a PE object ([#825](https://github.com/getsentry/symbolic/pull/825)) -**Features** - -## 12.8.0 - **Internal** -**Fixes** +- Update tokio to latest version ([#833](https://github.com/getsentry/symbolic/pull/833)) +- Fix infinite recursion caused by indirect self-references when resolving function names ([#836](https://github.com/getsentry/symbolic/pull/836)) +- Switch to workspace dependencies ([#841](https://github.com/getsentry/symbolic/pull/841)) + +## 12.8.0 **Features** diff --git a/Cargo.lock b/Cargo.lock index c5a000b23..97319fd1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,11 +14,11 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ - "gimli 0.28.1", + "gimli 0.29.0", ] [[package]] @@ -190,11 +190,11 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" dependencies = [ - "addr2line 0.21.0", + "addr2line 0.22.0", "cc", "cfg-if", "libc", @@ -306,6 +306,11 @@ name = "cc" version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +dependencies = [ + "jobserver", + "libc", + "once_cell", +] [[package]] name = "cfg-if" @@ -752,15 +757,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "gimli" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "e2e1d97fbe9722ba9bbd0c97051c2956e726562b61f86a25a4360398a40edfc9" dependencies = [ "fallible-iterator 0.3.0", "stable_deref_trait", @@ -940,6 +945,15 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jobserver" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +dependencies = [ + "libc", +] + [[package]] name = "joinery" version = "2.1.0" @@ -1262,9 +1276,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" dependencies = [ "memchr", ] @@ -1303,9 +1317,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -1386,6 +1400,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + [[package]] name = "plain" version = "0.2.3" @@ -1440,9 +1460,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.83" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] @@ -1718,18 +1738,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", @@ -2163,7 +2183,7 @@ dependencies = [ "elsa", "fallible-iterator 0.3.0", "flate2", - "gimli 0.29.0", + "gimli 0.30.0", "goblin", "insta", "lazy_static", @@ -2185,6 +2205,7 @@ dependencies = [ "thiserror", "wasmparser", "zip", + "zstd", ] [[package]] @@ -2290,9 +2311,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.65" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -2399,9 +2420,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "pin-project-lite", @@ -2410,9 +2431,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", @@ -2483,9 +2504,9 @@ dependencies = [ [[package]] name = "triomphe" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" +checksum = "1b2cb4fbb9995eeb36ac86fadf24031ccd58f99d6b4b2d7b911db70bddb80d90" dependencies = [ "serde", "stable_deref_trait", @@ -2660,9 +2681,9 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasmparser" -version = "0.208.1" +version = "0.209.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd921789c9dcc495f589cb37d200155dee65b4a4beeb853323b5e24e0a5f9c58" +checksum = "07035cc9a9b41e62d3bb3a3815a66ab87c993c06fe1cf6b2a3f2a18499d937db" dependencies = [ "ahash", "bitflags 2.5.0", @@ -2918,9 +2939,9 @@ dependencies = [ [[package]] name = "zip" -version = "1.3.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b7a5a9285bd4ee13bdeb3f8a4917eb46557e53f270c783849db8bef37b0ad00" +checksum = "098d5d7737fb0b70814faa73c17df84f047d38dd31d13bbf2ec3fb354b5abf45" dependencies = [ "arbitrary", "crc32fast", @@ -2928,6 +2949,7 @@ dependencies = [ "displaydoc", "flate2", "indexmap", + "memchr", "thiserror", "zopfli", ] @@ -2945,3 +2967,31 @@ dependencies = [ "once_cell", "simd-adler32", ] + +[[package]] +name = "zstd" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.10+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index 5bff7f515..0b8a5c7be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,6 @@ [workspace] resolver = "2" -members = [ - "symbolic*", - "examples/*", -] +members = ["symbolic*", "examples/*"] [workspace.dependencies] anyhow = "1.0.32" @@ -18,11 +15,17 @@ criterion = { version = "0.5.1", features = ["html_reports"] } debugid = "0.8.0" dmsort = "1.0.2" elementtree = "1.2.3" -elsa = "1.8.0" +elsa = "1.8.0" fallible-iterator = "0.3.0" -flate2 = { version = "1.0.25" , default-features = false, features = ["rust_backend"] } -gimli = { version = "0.29.0" , default-features = false, features = ["read", "std", "fallible-iterator"] } -goblin = { version = "0.8.0" , default-features = false } +flate2 = { version = "1.0.25", default-features = false, features = [ + "rust_backend", +] } +gimli = { version = "0.30.0", default-features = false, features = [ + "read", + "std", + "fallible-iterator", +] } +goblin = { version = "0.8.0", default-features = false } indexmap = "2.0.0" insta = { version = "1.28.0", features = ["yaml"] } itertools = "0.13.0" @@ -33,16 +36,16 @@ minidump = "0.21.0" minidump-processor = "0.21.0" minidump-unwind = "0.21.0" msvc-demangler = "0.10.0" -nom = "7.1.3" -nom-supreme = "0.8.0" -once_cell = "1.17.1" -parking_lot = "0.12.1" -pdb-addr2line = "0.10.4" +nom = "7.1.3" +nom-supreme = "0.8.0" +once_cell = "1.17.1" +parking_lot = "0.12.1" +pdb-addr2line = "0.10.4" proguard = { version = "5.4.0", features = ["uuid"] } -regex = "1.7.1" +regex = "1.7.1" rustc-demangle = "0.1.21" # keep this in sync with whatever version `goblin` uses -scroll = "0.12.0" +scroll = "0.12.0" serde = { version = "1.0.171", features = ["derive"] } serde_json = "1.0.102" similar-asserts = "1.4.2" @@ -55,7 +58,7 @@ symbolic-common = { version = "12.8.0", path = "symbolic-common" } symbolic-debuginfo = { version = "12.8.0", path = "symbolic-debuginfo" } symbolic-demangle = { version = "12.8.0", path = "symbolic-demangle" } symbolic-il2cpp = { version = "12.8.0", path = "symbolic-il2cpp" } -symbolic-ppdb = { version = "12.8.0", path = "symbolic-ppdb" } +symbolic-ppdb = { version = "12.8.0", path = "symbolic-ppdb" } symbolic-sourcemapcache = { version = "12.8.0", path = "symbolic-sourcemapcache" } symbolic-symcache = { version = "12.8.0", path = "symbolic-symcache" } symbolic-testutils = { path = "symbolic-testutils" } @@ -68,9 +71,10 @@ tracing = "0.1.34" tracing-subscriber = "0.3.11" uuid = "1.3.0" walkdir = "2.3.1" -wasmparser = "0.208.1" +wasmparser = "0.209.1" watto = { version = "0.1.0", features = ["writer", "strings"] } -zip = { version = "1.3.1" , default-features = false, features = ["deflate"] } +zip = { version = "2.1.2", default-features = false, features = ["deflate"] } +zstd = { version = "0.13.1" } [profile.release] @@ -79,4 +83,3 @@ lto = true [profile.bench] debug = true - diff --git a/symbolic-debuginfo/Cargo.toml b/symbolic-debuginfo/Cargo.toml index 71cfd78b3..100fd584a 100644 --- a/symbolic-debuginfo/Cargo.toml +++ b/symbolic-debuginfo/Cargo.toml @@ -44,6 +44,7 @@ elf = [ "goblin/elf64", "goblin/std", "scroll", + "zstd", ] # Mach-o processing macho = [ @@ -110,6 +111,7 @@ symbolic-ppdb = { workspace = true, optional = true } thiserror = { workspace = true } wasmparser = { workspace = true, optional = true } zip = { workspace = true, optional = true } +zstd = { workspace = true, optional = true } [dev-dependencies] criterion = { workspace = true } diff --git a/symbolic-debuginfo/src/elf.rs b/symbolic-debuginfo/src/elf.rs index 03d8cdc21..ed65c2fab 100644 --- a/symbolic-debuginfo/src/elf.rs +++ b/symbolic-debuginfo/src/elf.rs @@ -29,6 +29,9 @@ const PAGE_SIZE: usize = 4096; const SHN_UNDEF: usize = elf::section_header::SHN_UNDEF as usize; const SHF_COMPRESSED: u64 = elf::section_header::SHF_COMPRESSED as u64; +/// The ELF compression header type for `zstd`, as that is not (yet) exported by `goblin`. +pub const ELFCOMPRESS_ZSTD: u32 = 2; + /// This file follows the first MIPS 32 bit ABI #[allow(unused)] const EF_MIPS_ABI_O32: u32 = 0x0000_1000; @@ -549,7 +552,12 @@ impl<'data> ElfObject<'data> { /// Decompresses the given compressed section data, if supported. fn decompress_section(&self, section_data: &[u8]) -> Option> { - let (size, compressed) = if section_data.starts_with(b"ZLIB") { + enum CompressionType { + Zlib, + Zstd, + } + + let (ty, size, compressed) = if section_data.starts_with(b"ZLIB") { // The GNU compression header is a 4 byte magic "ZLIB", followed by an 8-byte big-endian // size prefix of the decompressed data. This adds up to 12 bytes of GNU header. if section_data.len() < 12 { @@ -559,25 +567,39 @@ impl<'data> ElfObject<'data> { let mut size_bytes = [0; 8]; size_bytes.copy_from_slice(§ion_data[4..12]); - (u64::from_be_bytes(size_bytes), §ion_data[12..]) + ( + CompressionType::Zlib, + u64::from_be_bytes(size_bytes), + §ion_data[12..], + ) } else { let container = self.elf.header.container().ok()?; let endianness = self.elf.header.endianness().ok()?; let context = Ctx::new(container, endianness); let compression = CompressionHeader::parse(section_data, 0, context).ok()?; - if compression.ch_type != ELFCOMPRESS_ZLIB { - return None; - } + let ty = match compression.ch_type { + ELFCOMPRESS_ZLIB => CompressionType::Zlib, + ELFCOMPRESS_ZSTD => CompressionType::Zstd, + _ => { + return None; + } + }; let compressed = §ion_data[CompressionHeader::size(context)..]; - (compression.ch_size, compressed) + (ty, compression.ch_size, compressed) }; - let mut decompressed = Vec::with_capacity(size as usize); - Decompress::new(true) - .decompress_vec(compressed, &mut decompressed, FlushDecompress::Finish) - .ok()?; + let decompressed = match ty { + CompressionType::Zlib => { + let mut decompressed = Vec::with_capacity(size as usize); + Decompress::new(true) + .decompress_vec(compressed, &mut decompressed, FlushDecompress::Finish) + .ok()?; + decompressed + } + CompressionType::Zstd => zstd::bulk::decompress(compressed, size as usize).ok()?, + }; Some(decompressed) } diff --git a/symbolic-debuginfo/tests/test_objects.rs b/symbolic-debuginfo/tests/test_objects.rs index 36f40a35d..6372f0a18 100644 --- a/symbolic-debuginfo/tests/test_objects.rs +++ b/symbolic-debuginfo/tests/test_objects.rs @@ -282,6 +282,22 @@ fn test_elf_files() -> Result<(), Error> { assert_eq!(files.len(), 1012); insta::assert_debug_snapshot!("elf_files", FilesDebug(&files[..10])); + let view = ByteView::open(fixture("linux/crash.debug-zlib"))?; + let object = Object::parse(&view)?; + + let session = object.debug_session()?; + let files = session.files().collect::, _>>()?; + assert_eq!(files.len(), 1012); + insta::assert_debug_snapshot!("elf_files", FilesDebug(&files[..10])); + + let view = ByteView::open(fixture("linux/crash.debug-zstd"))?; + let object = Object::parse(&view)?; + + let session = object.debug_session()?; + let files = session.files().collect::, _>>()?; + assert_eq!(files.len(), 1012); + insta::assert_debug_snapshot!("elf_files", FilesDebug(&files[..10])); + Ok(()) } @@ -294,6 +310,20 @@ fn test_elf_functions() -> Result<(), Error> { let functions = session.functions().collect::, _>>()?; insta::assert_debug_snapshot!("elf_functions", FunctionsDebug(&functions[..10], 0)); + let view = ByteView::open(fixture("linux/crash.debug-zlib"))?; + let object = Object::parse(&view)?; + + let session = object.debug_session()?; + let functions = session.functions().collect::, _>>()?; + insta::assert_debug_snapshot!("elf_functions", FunctionsDebug(&functions[..10], 0)); + + let view = ByteView::open(fixture("linux/crash.debug-zstd"))?; + let object = Object::parse(&view)?; + + let session = object.debug_session()?; + let functions = session.functions().collect::, _>>()?; + insta::assert_debug_snapshot!("elf_functions", FunctionsDebug(&functions[..10], 0)); + Ok(()) } diff --git a/symbolic-testutils/fixtures/linux/README.md b/symbolic-testutils/fixtures/linux/README.md new file mode 100644 index 000000000..f1850fd6d --- /dev/null +++ b/symbolic-testutils/fixtures/linux/README.md @@ -0,0 +1,3 @@ +The `crash.debug-z{lib,std}` files contain the exact same debug information as the `crash.debug` file they were derived from. + +The files were derived using `llvm-objcopy --compress-debug-sections=z{lib,std} crash.debug crash.debug-z{lib,std}` respectively. diff --git a/symbolic-testutils/fixtures/linux/crash.debug-zlib b/symbolic-testutils/fixtures/linux/crash.debug-zlib new file mode 100755 index 000000000..d69d46b90 Binary files /dev/null and b/symbolic-testutils/fixtures/linux/crash.debug-zlib differ diff --git a/symbolic-testutils/fixtures/linux/crash.debug-zstd b/symbolic-testutils/fixtures/linux/crash.debug-zstd new file mode 100755 index 000000000..8425a9f1d Binary files /dev/null and b/symbolic-testutils/fixtures/linux/crash.debug-zstd differ