symbolic_ppdb/cache/
writer.rs1use std::collections::BTreeMap;
2use std::io::Write;
3
4use indexmap::IndexSet;
5use symbolic_common::{DebugId, Language};
6use watto::{Pod, StringTable};
7
8use super::{raw, CacheError};
9use crate::PortablePdb;
10
11#[derive(Debug, Default)]
16pub struct PortablePdbCacheConverter {
17 pdb_id: DebugId,
19 files: IndexSet<raw::File>,
21 ranges: BTreeMap<raw::Range, raw::SourceLocation>,
26 string_table: StringTable,
27}
28
29impl PortablePdbCacheConverter {
30 pub fn new() -> Self {
32 Self::default()
33 }
34
35 pub fn process_portable_pdb(&mut self, portable_pdb: &PortablePdb) -> Result<(), CacheError> {
37 if let Some(id) = portable_pdb.pdb_id() {
38 self.set_pdb_id(id);
39 }
40
41 for (function, sequence_points) in portable_pdb.get_all_sequence_points().enumerate() {
42 let func_idx = (function + 1) as u32;
43 let sequence_points = sequence_points?;
44
45 for sp in sequence_points.iter() {
46 if sp.is_hidden() {
47 continue;
48 }
49 let range = raw::Range {
50 func_idx,
51 il_offset: sp.il_offset,
52 };
53
54 let doc = portable_pdb.get_document(sp.document_id as usize)?;
55 let file_idx = self.insert_file(&doc.name, doc.lang);
56 let source_location = raw::SourceLocation {
57 line: sp.start_line,
58 file_idx,
59 };
60
61 self.ranges.insert(range, source_location);
62 }
63 }
64
65 Ok(())
66 }
67
68 pub fn serialize<W: Write>(self, writer: &mut W) -> std::io::Result<()> {
72 let mut writer = watto::Writer::new(writer);
73
74 let num_ranges = self.ranges.len() as u32;
75 let num_files = self.files.len() as u32;
76 let string_bytes = self.string_table.into_bytes();
77
78 let header = raw::Header {
79 magic: raw::PPDBCACHE_MAGIC,
80 version: super::PPDBCACHE_VERSION,
81
82 pdb_id: self.pdb_id,
83
84 num_files,
85 num_ranges,
86 string_bytes: string_bytes.len() as u32,
87 _reserved: [0; 16],
88 };
89
90 writer.write_all(header.as_bytes())?;
91 writer.align_to(8)?;
92
93 for file in self.files.into_iter() {
94 writer.write_all(file.as_bytes())?;
95 }
96 writer.align_to(8)?;
97
98 for sl in self.ranges.values() {
99 writer.write_all(sl.as_bytes())?;
100 }
101 writer.align_to(8)?;
102
103 for r in self.ranges.keys() {
104 writer.write_all(r.as_bytes())?;
105 }
106 writer.align_to(8)?;
107
108 writer.write_all(&string_bytes)?;
109
110 Ok(())
111 }
112
113 fn set_pdb_id(&mut self, id: DebugId) {
114 self.pdb_id = id;
115 }
116
117 fn insert_file(&mut self, name: &str, lang: Language) -> u32 {
118 let name_offset = self.string_table.insert(name) as u32;
119 let file = raw::File {
120 name_offset,
121 lang: lang as u32,
122 };
123
124 self.files.insert_full(file).0 as u32
125 }
126}