Skip to content

Commit ab41f70

Browse files
committed
Don't copy the breakpad index in-memory bytes when writing the index file.
1 parent a06e6c3 commit ab41f70

File tree

5 files changed

+116
-54
lines changed

5 files changed

+116
-54
lines changed

samply-symbols/src/breakpad/index.rs

Lines changed: 83 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::collections::BTreeMap;
22
use std::fmt::Debug;
3+
use std::io::Write;
34
use std::str::FromStr;
45
use std::{mem, str};
56

@@ -188,12 +189,11 @@ impl<'a> BreakpadIndex<'a> {
188189
})
189190
}
190191

191-
pub fn serialize_to_bytes(&self) -> Vec<u8> {
192+
fn header_and_total_size(&self) -> (BreakpadSymindexFileHeader, u32) {
192193
let header_len = HEADER_SIZE;
193194
let module_info_offset = header_len;
194195
let module_info_len = self.module_info_bytes.len() as u32;
195-
let padding_after_module_info = align_to_4_bytes(module_info_len) - module_info_len;
196-
let file_entries_offset = module_info_offset + module_info_len + padding_after_module_info;
196+
let file_entries_offset = module_info_offset + align_to_4_bytes(module_info_len);
197197
let file_count = self.files.len() as u32;
198198
let file_entries_len = file_count * FILE_OR_INLINE_ORIGIN_ENTRY_SIZE;
199199
let inline_origin_entries_offset = file_entries_offset + file_entries_len;
@@ -217,19 +217,37 @@ impl<'a> BreakpadIndex<'a> {
217217
symbol_addresses_offset: symbol_addresses_offset.into(),
218218
symbol_entries_offset: symbol_entries_offset.into(),
219219
};
220+
(header, total_file_len)
221+
}
222+
223+
pub fn to_writer<W: Write>(&self, w: W) -> std::io::Result<()> {
224+
let (header, _) = self.header_and_total_size();
225+
self.to_writer_inner(w, header)
226+
}
220227

221-
let mut vec = Vec::with_capacity(total_file_len as usize);
222-
vec.extend_from_slice(header.as_bytes());
223-
vec.extend_from_slice(self.module_info_bytes);
224-
vec.extend(std::iter::repeat(0).take(padding_after_module_info as usize));
225-
vec.extend_from_slice(self.files.as_slice().as_bytes());
226-
vec.extend_from_slice(self.inline_origins.as_slice().as_bytes());
227-
vec.extend_from_slice(self.symbol_addresses.as_bytes());
228-
vec.extend_from_slice(self.symbol_entries.as_bytes());
228+
fn to_writer_inner<W: Write>(
229+
&self,
230+
mut w: W,
231+
header: BreakpadSymindexFileHeader,
232+
) -> std::io::Result<()> {
233+
w.write_all(header.as_bytes())?;
234+
w.write_all(self.module_info_bytes)?;
235+
let padding_after_module_info = header.file_entries_offset.get()
236+
- (header.module_info_offset.get() + header.module_info_len.get());
237+
w.write_all(&[0; 4][..padding_after_module_info as usize])?;
238+
w.write_all(self.files.as_slice().as_bytes())?;
239+
w.write_all(self.inline_origins.as_slice().as_bytes())?;
240+
w.write_all(self.symbol_addresses.as_bytes())?;
241+
w.write_all(self.symbol_entries.as_bytes())?;
229242

230-
assert_eq!(vec.len(), total_file_len as usize);
243+
Ok(())
244+
}
231245

232-
vec
246+
pub fn serialize_to_bytes(&self) -> Vec<u8> {
247+
let (header, total_size) = self.header_and_total_size();
248+
let mut v = Vec::with_capacity(total_size as usize);
249+
self.to_writer_inner(&mut v, header).unwrap();
250+
v
233251
}
234252
}
235253

@@ -583,7 +601,7 @@ impl BreakpadIndexCreator {
583601
line_buffer.consume(chunk, |offset, line| inner.process_line(offset, line));
584602
}
585603

586-
pub fn finish(mut self) -> Result<Vec<u8>, BreakpadParseError> {
604+
pub fn finish(mut self) -> Result<OwnedBreakpadIndex, BreakpadParseError> {
587605
let inner = &mut self.inner;
588606
let final_offset = self
589607
.line_buffer
@@ -674,7 +692,10 @@ impl BreakpadIndexCreatorInner {
674692
}
675693
}
676694

677-
pub fn finish(mut self, file_end_offset: u64) -> Result<Vec<u8>, BreakpadParseError> {
695+
pub fn finish(
696+
mut self,
697+
file_end_offset: u64,
698+
) -> Result<OwnedBreakpadIndex, BreakpadParseError> {
678699
self.finish_pending_func_block(file_end_offset);
679700
let BreakpadIndexCreatorInner {
680701
mut symbols,
@@ -697,20 +718,53 @@ impl BreakpadIndexCreatorInner {
697718

698719
let (debug_id, os, arch, debug_name) =
699720
module_info.ok_or(BreakpadParseError::NoModuleInfoInSymFile)?;
700-
let index = BreakpadIndex {
701-
module_info_bytes: &module_info_bytes,
702-
debug_name,
721+
722+
Ok(OwnedBreakpadIndex {
723+
module_info_bytes,
703724
debug_id,
704-
code_id,
705-
name,
706-
arch,
707725
os,
708-
symbol_addresses: &symbol_addresses,
709-
symbol_entries: &symbol_entries,
710-
files: StringListRef::new(&files),
711-
inline_origins: StringListRef::new(&inline_origins),
712-
};
713-
Ok(index.serialize_to_bytes())
726+
arch,
727+
debug_name,
728+
name,
729+
code_id,
730+
files,
731+
inline_origins,
732+
symbol_addresses,
733+
symbol_entries,
734+
})
735+
}
736+
}
737+
738+
#[derive(Debug, Clone, Default)]
739+
pub struct OwnedBreakpadIndex {
740+
module_info_bytes: Vec<u8>,
741+
debug_name: String,
742+
debug_id: DebugId,
743+
arch: String,
744+
os: String,
745+
name: Option<String>,
746+
code_id: Option<CodeId>,
747+
files: Vec<StringLocation>,
748+
inline_origins: Vec<StringLocation>,
749+
symbol_addresses: Vec<U32<LittleEndian>>,
750+
symbol_entries: Vec<BreakpadSymbolEntry>,
751+
}
752+
753+
impl OwnedBreakpadIndex {
754+
pub fn index(&self) -> BreakpadIndex<'_> {
755+
BreakpadIndex {
756+
module_info_bytes: &self.module_info_bytes,
757+
debug_name: self.debug_name.clone(),
758+
debug_id: self.debug_id,
759+
code_id: self.code_id.clone(),
760+
name: self.name.clone(),
761+
arch: self.arch.clone(),
762+
os: self.os.clone(),
763+
symbol_addresses: &self.symbol_addresses,
764+
symbol_entries: &self.symbol_entries,
765+
files: StringListRef::new(&self.files),
766+
inline_origins: StringListRef::new(&self.inline_origins),
767+
}
714768
}
715769
}
716770

@@ -1194,7 +1248,7 @@ curity/sandbox/chromium/base/strings/safe_sprintf.cc:f150bc1f71d09e1e1941065951f
11941248
for chunk in data.chunks(84) {
11951249
parser.consume(chunk);
11961250
}
1197-
let index_bytes = parser.finish().unwrap();
1251+
let index_bytes = parser.finish().unwrap().index().serialize_to_bytes();
11981252
let index = BreakpadIndex::parse_symindex_file(&*index_bytes).unwrap();
11991253

12001254
assert_eq!(
@@ -1230,7 +1284,7 @@ curity/sandbox/chromium/base/strings/safe_sprintf.cc:f150bc1f71d09e1e1941065951f
12301284
parser.consume(b"\n2b78e 2 306 0\n2b790 c 305 0\n2b79c b 309 0\n2b7a7 10 660 0\n2b7b7 2 ");
12311285
parser.consume(b"661 0\n2b7b9 11 662 0\n2b7ca 9 340 0\n2b7d3 e 341 0\n2b7e1 c 668 0\n2b7");
12321286
parser.consume(b"ed b 7729 1\n2b7f8 6 668 0");
1233-
let index_bytes = parser.finish().unwrap();
1287+
let index_bytes = parser.finish().unwrap().index().serialize_to_bytes();
12341288
let index = BreakpadIndex::parse_symindex_file(&*index_bytes).unwrap();
12351289
assert_eq!(&index.debug_name, "firefox.pdb");
12361290
assert_eq!(

samply-symbols/src/breakpad/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ mod symbol_map;
33

44
pub use index::{
55
BreakpadIndex, BreakpadIndexCreator, BreakpadParseError, BreakpadSymindexParseError,
6+
OwnedBreakpadIndex,
67
};
78
pub use symbol_map::get_symbol_map_for_breakpad_sym;
89

samply-symbols/src/breakpad/symbol_map.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use super::index::{
1010
BreakpadPublicSymbol, BreakpadPublicSymbolInfo, StringListRef, SYMBOL_ENTRY_KIND_FUNC,
1111
SYMBOL_ENTRY_KIND_PUBLIC,
1212
};
13-
use crate::breakpad::index::{Inlinee, SourceLine};
13+
use crate::breakpad::index::{Inlinee, OwnedBreakpadIndex, SourceLine};
1414
use crate::generation::SymbolMapGeneration;
1515
use crate::source_file_path::SourceFilePathHandle;
1616
use crate::symbol_map::{GetInnerSymbolMap, SymbolMapTrait};
@@ -42,7 +42,7 @@ impl<T: FileContents> GetInnerSymbolMap for BreakpadSymbolMap<T> {
4242

4343
enum IndexStorage<T: FileContents> {
4444
File(FileContentsWrapper<T>),
45-
Owned(Vec<u8>),
45+
Owned(Box<OwnedBreakpadIndex>),
4646
}
4747

4848
pub struct BreakpadSymbolMapOuter<T: FileContents> {
@@ -88,18 +88,16 @@ impl<T: FileContents> BreakpadSymbolMapOuter<T> {
8888
buffer.clear();
8989
offset += CHUNK_SIZE;
9090
}
91-
let index_bytes = index_parser.finish()?;
92-
Ok(IndexStorage::Owned(index_bytes))
91+
let index = index_parser.finish()?;
92+
Ok(IndexStorage::Owned(Box::new(index)))
9393
}
9494

9595
pub fn make_symbol_map(&self) -> BreakpadSymbolMapInnerWrapper<'_> {
9696
let index = match &self.index {
9797
IndexStorage::File(index_data) => {
9898
BreakpadIndex::parse_symindex_file(index_data).unwrap()
9999
}
100-
IndexStorage::Owned(index_data) => {
101-
BreakpadIndex::parse_symindex_file(&index_data[..]).unwrap()
102-
}
100+
IndexStorage::Owned(owned_index) => owned_index.index(),
103101
};
104102
let cache = Mutex::new(BreakpadSymbolMapCache::new(&index));
105103
let inner_impl = BreakpadSymbolMapInner {
@@ -421,7 +419,7 @@ mod test {
421419
for s in data_slices {
422420
parser.consume(s);
423421
}
424-
let index_bytes = parser.finish().unwrap();
422+
let index_bytes = parser.finish().unwrap().index().serialize_to_bytes();
425423

426424
let full_sym_contents = data_slices.concat();
427425
let sym_fc = FileContentsWrapper::new(full_sym_contents);

samply-symbols/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ mod windows;
240240
pub use crate::binary_image::{BinaryImage, CodeByteReadingError};
241241
pub use crate::breakpad::{
242242
BreakpadIndex, BreakpadIndexCreator, BreakpadParseError, BreakpadSymindexParseError,
243+
OwnedBreakpadIndex,
243244
};
244245
pub use crate::cache::{FileByteSource, FileContentsWithChunkedCaching};
245246
pub use crate::compact_symbol_table::CompactSymbolTable;

wholesym/src/breakpad.rs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::path::{Path, PathBuf};
22
use std::sync::Arc;
33

4-
use samply_symbols::{BreakpadIndex, BreakpadIndexCreator, BreakpadParseError};
4+
use samply_symbols::{BreakpadIndex, BreakpadIndexCreator, BreakpadParseError, OwnedBreakpadIndex};
55
use tokio::io::{AsyncReadExt, AsyncWriteExt};
66

77
use crate::downloader::{ChunkConsumer, Downloader, DownloaderObserver, FileDownloadOutcome};
@@ -189,7 +189,7 @@ impl BreakpadSymbolDownloaderInner {
189189
async fn write_symindex(
190190
&self,
191191
symindex_path: &Path,
192-
index_bytes: Vec<u8>,
192+
index: OwnedBreakpadIndex,
193193
) -> Result<(), SymindexGenerationError> {
194194
if let Some(parent_dir) = symindex_path.parent() {
195195
tokio::fs::create_dir_all(parent_dir).await.map_err(|e| {
@@ -202,17 +202,15 @@ impl BreakpadSymbolDownloaderInner {
202202
let index_size_result: Result<u64, CleanFileCreationError<SymindexGenerationError>> =
203203
create_file_cleanly(
204204
symindex_path,
205-
|index_file| async move {
206-
let mut index_file = tokio::fs::File::from_std(index_file);
207-
index_file
208-
.write_all(&index_bytes)
209-
.await
210-
.map_err(SymindexGenerationError::FileWriting)?;
211-
index_file
212-
.flush()
213-
.await
214-
.map_err(SymindexGenerationError::FileWriting)?;
215-
Ok(index_bytes.len() as u64)
205+
|mut index_file| async move {
206+
tokio::task::spawn_blocking(move || -> std::io::Result<u64> {
207+
index.index().to_writer(&mut index_file)?;
208+
let metadata = index_file.metadata()?;
209+
Ok(metadata.len())
210+
})
211+
.await
212+
.unwrap()
213+
.map_err(SymindexGenerationError::FileWriting)
216214
},
217215
|| async {
218216
let size = std::fs::metadata(symindex_path)
@@ -267,15 +265,25 @@ impl BreakpadSymbolDownloaderInner {
267265
let _ = tokio::fs::remove_file(&symindex_path).await;
268266
}
269267

270-
let index_bytes = self.parse_sym_file_into_index(sym_path).await?;
271-
self.write_symindex(&symindex_path, index_bytes).await?;
268+
self.create_symindex_for_sym_file(sym_path, &symindex_path)
269+
.await?;
272270
Ok(symindex_path)
273271
}
274272

273+
async fn create_symindex_for_sym_file(
274+
&self,
275+
sym_path: &Path,
276+
symindex_path: &Path,
277+
) -> Result<(), SymindexGenerationError> {
278+
let index_bytes = self.parse_sym_file_into_index(sym_path).await?;
279+
self.write_symindex(symindex_path, index_bytes).await?;
280+
Ok(())
281+
}
282+
275283
async fn parse_sym_file_into_index(
276284
&self,
277285
sym_path: &Path,
278-
) -> Result<Vec<u8>, SymindexGenerationError> {
286+
) -> Result<OwnedBreakpadIndex, SymindexGenerationError> {
279287
let mut sym_file = tokio::fs::File::open(sym_path)
280288
.await
281289
.map_err(SymindexGenerationError::SymReading)?;
@@ -307,7 +315,7 @@ async fn validate_symindex_magic_and_version(file: &mut tokio::fs::File) -> bool
307315
struct BreakpadIndexCreatorChunkConsumer(BreakpadIndexCreator);
308316

309317
impl ChunkConsumer for BreakpadIndexCreatorChunkConsumer {
310-
type Output = Result<Vec<u8>, BreakpadParseError>;
318+
type Output = Result<OwnedBreakpadIndex, BreakpadParseError>;
311319

312320
fn consume_chunk(&mut self, chunk_data: &[u8]) {
313321
self.0.consume(chunk_data);

0 commit comments

Comments
 (0)