From c28405ca740599ce73d3e0f217f92edf649c1661 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Tue, 7 Feb 2023 12:56:46 +0100 Subject: [PATCH 1/3] feat: PE - decompress embedded PPDB to file --- symbolic-debuginfo/src/pe.rs | 22 +++++++++++++++++++--- symbolic-debuginfo/tests/test_objects.rs | 9 +++++++-- symbolic-ppdb/tests/test_ppdb.rs | 4 ++-- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/symbolic-debuginfo/src/pe.rs b/symbolic-debuginfo/src/pe.rs index 8cf4d7f21..a56668fed 100644 --- a/symbolic-debuginfo/src/pe.rs +++ b/symbolic-debuginfo/src/pe.rs @@ -3,9 +3,10 @@ use std::borrow::Cow; use std::error::Error; use std::fmt; +use std::fs::File; +use std::io::BufWriter; use std::io::Read; -use flate2::read::DeflateDecoder; use gimli::RunTimeEndian; use goblin::pe; use scroll::{Pread, LE}; @@ -505,8 +506,8 @@ impl<'data, 'object> PeEmbeddedPortablePDB<'data> { } /// Reads the Portable PDB contents into the provided vector. - pub fn decompress(&self) -> Result, PeError> { - let mut decoder = DeflateDecoder::new(self.compressed_data); + pub fn decompress_to_vec(&self) -> Result, PeError> { + let mut decoder = flate2::read::DeflateDecoder::new(self.compressed_data); let mut output: Vec = vec![0; self.uncompressed_size]; let read_size = decoder.read(&mut output).map_err(PeError::new)?; if read_size != self.uncompressed_size { @@ -516,4 +517,19 @@ impl<'data, 'object> PeEmbeddedPortablePDB<'data> { } Ok(output) } + + /// Reads the Portable PDB contents into the provided file. + pub fn decompress_to_file(&self, output: File) -> Result { + use std::io::prelude::*; + let buf_writer = BufWriter::new(output); + let mut decoder = flate2::write::DeflateDecoder::new(buf_writer); + decoder + .write_all(self.compressed_data) + .map_err(PeError::new)?; + decoder + .finish() + .map_err(PeError::new)? + .into_inner() + .map_err(PeError::new) + } } diff --git a/symbolic-debuginfo/tests/test_objects.rs b/symbolic-debuginfo/tests/test_objects.rs index d34460585..cff76a8dc 100644 --- a/symbolic-debuginfo/tests/test_objects.rs +++ b/symbolic-debuginfo/tests/test_objects.rs @@ -1,4 +1,4 @@ -use std::{ffi::CString, fmt}; +use std::{env, ffi::CString, fmt}; use symbolic_common::ByteView; use symbolic_debuginfo::{ @@ -565,8 +565,13 @@ fn test_pe_embedded_ppdb() -> Result<(), Error> { let embedded_ppdb = pe.embedded_ppdb().unwrap().unwrap(); assert_eq!(embedded_ppdb.get_size(), 10540); - let buf = embedded_ppdb.decompress()?; + let buf = embedded_ppdb.decompress_to_vec()?; assert_eq!(&buf[15..25], "\0PDB v1.0\0".as_bytes()); + + let tmp_file = tempfile::tempfile()?; + let tmp_file = embedded_ppdb.decompress_to_file(tmp_file)?; + let file_buf = ByteView::map_file(tmp_file)?; + assert_eq!(buf, file_buf.as_slice()); } Ok(()) } diff --git a/symbolic-ppdb/tests/test_ppdb.rs b/symbolic-ppdb/tests/test_ppdb.rs index a3b5c0903..0dc76c7df 100644 --- a/symbolic-ppdb/tests/test_ppdb.rs +++ b/symbolic-ppdb/tests/test_ppdb.rs @@ -109,7 +109,7 @@ fn test_pe_embedded_ppdb_without_sources() { let pe = PeObject::parse(&pe_buf).unwrap(); let embedded_ppdb = pe.embedded_ppdb().unwrap().unwrap(); - let ppdb_buf = embedded_ppdb.decompress().unwrap(); + let ppdb_buf = embedded_ppdb.decompress_to_vec().unwrap(); let ppdb = PortablePdb::parse(&ppdb_buf).unwrap(); assert_eq!(ppdb.pdb_id().unwrap(), pe.debug_id()); @@ -128,7 +128,7 @@ fn test_pe_embedded_ppdb_with_sources() { let pe = PeObject::parse(&pe_buf).unwrap(); let embedded_ppdb = pe.embedded_ppdb().unwrap().unwrap(); - let ppdb_buf = embedded_ppdb.decompress().unwrap(); + let ppdb_buf = embedded_ppdb.decompress_to_vec().unwrap(); let ppdb = PortablePdb::parse(&ppdb_buf).unwrap(); assert_eq!(ppdb.pdb_id().unwrap(), pe.debug_id()); From 20bd5d30e7ce2d7c9ec0ab151ad44eb06c7dc8d1 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Tue, 7 Feb 2023 13:59:18 +0100 Subject: [PATCH 2/3] chore: update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ad99cde8..79acefb99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ - Correctly read the `debug_id` of Deterministic PE files ([#658](https://github.com/getsentry/symbolic/pull/658)) - Gracefully handle invalid PPDBs ([#751](https://github.com/getsentry/symbolic/pull/751)) -- Support embedded PortablePDB in DLLs ([#752](https://github.com/getsentry/symbolic/pull/752)) +- Support embedded PortablePDB in DLLs ([#752](https://github.com/getsentry/symbolic/pull/752), [#757](https://github.com/getsentry/symbolic/pull/757)) ## 11.0.0 From 737376bc0f54522036cd710031a5937563e9d444 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Tue, 7 Feb 2023 14:26:23 +0100 Subject: [PATCH 3/3] refactor: PeEmbeddedPortablePDB decompression --- symbolic-debuginfo/src/pe.rs | 31 +++++------------------- symbolic-debuginfo/tests/test_objects.rs | 7 +++--- symbolic-ppdb/tests/test_ppdb.rs | 6 +++-- 3 files changed, 14 insertions(+), 30 deletions(-) diff --git a/symbolic-debuginfo/src/pe.rs b/symbolic-debuginfo/src/pe.rs index a56668fed..31a6995a1 100644 --- a/symbolic-debuginfo/src/pe.rs +++ b/symbolic-debuginfo/src/pe.rs @@ -3,9 +3,7 @@ use std::borrow::Cow; use std::error::Error; use std::fmt; -use std::fs::File; -use std::io::BufWriter; -use std::io::Read; +use std::io::Write; use gimli::RunTimeEndian; use goblin::pe; @@ -505,31 +503,14 @@ impl<'data, 'object> PeEmbeddedPortablePDB<'data> { self.uncompressed_size } - /// Reads the Portable PDB contents into the provided vector. - pub fn decompress_to_vec(&self) -> Result, PeError> { - let mut decoder = flate2::read::DeflateDecoder::new(self.compressed_data); - let mut output: Vec = vec![0; self.uncompressed_size]; - let read_size = decoder.read(&mut output).map_err(PeError::new)?; - if read_size != self.uncompressed_size { - return Err(PeError::new(symbolic_ppdb::FormatError::from( - symbolic_ppdb::FormatErrorKind::InvalidLength, - ))); - } - Ok(output) - } - - /// Reads the Portable PDB contents into the provided file. - pub fn decompress_to_file(&self, output: File) -> Result { + /// Reads the Portable PDB contents into the writer. + pub fn decompress_to(&self, output: W) -> Result<(), PeError> { use std::io::prelude::*; - let buf_writer = BufWriter::new(output); - let mut decoder = flate2::write::DeflateDecoder::new(buf_writer); + let mut decoder = flate2::write::DeflateDecoder::new(output); decoder .write_all(self.compressed_data) + .and_then(|_| decoder.finish()) .map_err(PeError::new)?; - decoder - .finish() - .map_err(PeError::new)? - .into_inner() - .map_err(PeError::new) + Ok(()) } } diff --git a/symbolic-debuginfo/tests/test_objects.rs b/symbolic-debuginfo/tests/test_objects.rs index cff76a8dc..dcfd3797c 100644 --- a/symbolic-debuginfo/tests/test_objects.rs +++ b/symbolic-debuginfo/tests/test_objects.rs @@ -1,4 +1,4 @@ -use std::{env, ffi::CString, fmt}; +use std::{env, ffi::CString, fmt, io::BufWriter}; use symbolic_common::ByteView; use symbolic_debuginfo::{ @@ -565,11 +565,12 @@ fn test_pe_embedded_ppdb() -> Result<(), Error> { let embedded_ppdb = pe.embedded_ppdb().unwrap().unwrap(); assert_eq!(embedded_ppdb.get_size(), 10540); - let buf = embedded_ppdb.decompress_to_vec()?; + let mut buf = Vec::new(); + embedded_ppdb.decompress_to(&mut buf)?; assert_eq!(&buf[15..25], "\0PDB v1.0\0".as_bytes()); let tmp_file = tempfile::tempfile()?; - let tmp_file = embedded_ppdb.decompress_to_file(tmp_file)?; + embedded_ppdb.decompress_to(BufWriter::new(&tmp_file))?; let file_buf = ByteView::map_file(tmp_file)?; assert_eq!(buf, file_buf.as_slice()); } diff --git a/symbolic-ppdb/tests/test_ppdb.rs b/symbolic-ppdb/tests/test_ppdb.rs index 0dc76c7df..1e5e6da47 100644 --- a/symbolic-ppdb/tests/test_ppdb.rs +++ b/symbolic-ppdb/tests/test_ppdb.rs @@ -109,7 +109,8 @@ fn test_pe_embedded_ppdb_without_sources() { let pe = PeObject::parse(&pe_buf).unwrap(); let embedded_ppdb = pe.embedded_ppdb().unwrap().unwrap(); - let ppdb_buf = embedded_ppdb.decompress_to_vec().unwrap(); + let mut ppdb_buf = Vec::new(); + embedded_ppdb.decompress_to(&mut ppdb_buf).unwrap(); let ppdb = PortablePdb::parse(&ppdb_buf).unwrap(); assert_eq!(ppdb.pdb_id().unwrap(), pe.debug_id()); @@ -128,7 +129,8 @@ fn test_pe_embedded_ppdb_with_sources() { let pe = PeObject::parse(&pe_buf).unwrap(); let embedded_ppdb = pe.embedded_ppdb().unwrap().unwrap(); - let ppdb_buf = embedded_ppdb.decompress_to_vec().unwrap(); + let mut ppdb_buf = Vec::new(); + embedded_ppdb.decompress_to(&mut ppdb_buf).unwrap(); let ppdb = PortablePdb::parse(&ppdb_buf).unwrap(); assert_eq!(ppdb.pdb_id().unwrap(), pe.debug_id());