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