symbolic_symcache/
lookup.rs1use std::fmt;
2
3use symbolic_common::{Language, Name, NameMangling};
4
5use super::{raw, SymCache};
6
7impl<'data> SymCache<'data> {
8 pub fn lookup(&self, addr: u64) -> SourceLocations<'data, '_> {
11 let addr = match u32::try_from(addr) {
12 Ok(addr) => addr,
13 Err(_) => {
14 return SourceLocations {
15 cache: self,
16 source_location_idx: u32::MAX,
17 }
18 }
19 };
20
21 let source_location_start = (self.source_locations.len() - self.ranges.len()) as u32;
22 let mut source_location_idx = match self.ranges.binary_search_by_key(&addr, |r| r.0) {
23 Ok(idx) => source_location_start + idx as u32,
24 Err(0) => u32::MAX,
25 Err(idx) => source_location_start + idx as u32 - 1,
26 };
27
28 if let Some(source_location) = self.source_locations.get(source_location_idx as usize) {
29 if *source_location == raw::NO_SOURCE_LOCATION {
30 source_location_idx = u32::MAX;
31 }
32 }
33
34 SourceLocations {
35 cache: self,
36 source_location_idx,
37 }
38 }
39
40 pub(crate) fn get_file(&self, file_idx: u32) -> Option<File<'data>> {
41 let raw_file = self.files.get(file_idx as usize)?;
42 Some(File {
43 comp_dir: self.get_string(raw_file.comp_dir_offset),
44 directory: self.get_string(raw_file.directory_offset),
45 name: self.get_string(raw_file.name_offset).unwrap_or_default(),
46 })
47 }
48
49 pub(crate) fn get_function(&self, function_idx: u32) -> Option<Function<'data>> {
50 let raw_function = self.functions.get(function_idx as usize)?;
51 Some(Function {
52 name: self.get_string(raw_function.name_offset).unwrap_or("?"),
53 entry_pc: raw_function.entry_pc,
54 language: Language::from_u32(raw_function.lang),
55 })
56 }
57
58 pub fn functions(&self) -> Functions<'data> {
65 Functions {
66 cache: self.clone(),
67 function_idx: 0,
68 }
69 }
70
71 pub fn files(&self) -> Files<'data> {
76 Files {
77 cache: self.clone(),
78 file_idx: 0,
79 }
80 }
81}
82
83#[derive(Debug, Clone)]
85pub struct File<'data> {
86 comp_dir: Option<&'data str>,
88 directory: Option<&'data str>,
90 name: &'data str,
92}
93
94impl File<'_> {
95 pub fn full_path(&self) -> String {
97 let comp_dir = self.comp_dir.unwrap_or_default();
98 let directory = self.directory.unwrap_or_default();
99
100 let prefix = symbolic_common::join_path(comp_dir, directory);
101 let full_path = symbolic_common::join_path(&prefix, self.name);
102 let full_path = symbolic_common::clean_path(&full_path).into_owned();
103
104 full_path
105 }
106}
107
108#[derive(Clone, Debug)]
110pub struct Function<'data> {
111 name: &'data str,
112 entry_pc: u32,
113 language: Language,
114}
115
116impl<'data> Function<'data> {
117 pub fn name(&self) -> &'data str {
119 self.name
120 }
121
122 pub fn name_for_demangling(&self) -> Name<'data> {
124 Name::new(self.name, NameMangling::Unknown, self.language)
125 }
126
127 pub fn entry_pc(&self) -> u32 {
129 self.entry_pc
130 }
131
132 pub fn language(&self) -> Language {
134 self.language
135 }
136}
137
138impl Default for Function<'_> {
139 fn default() -> Self {
140 Self {
141 name: "?",
142 entry_pc: u32::MAX,
143 language: Language::Unknown,
144 }
145 }
146}
147
148#[derive(Debug, Clone, PartialEq, Eq)]
153pub struct SourceLocation<'data, 'cache> {
154 pub(crate) cache: &'cache SymCache<'data>,
155 pub(crate) source_location: &'data raw::SourceLocation,
156}
157
158impl<'data> SourceLocation<'data, '_> {
159 pub fn line(&self) -> u32 {
163 self.source_location.line
164 }
165
166 pub fn file(&self) -> Option<File<'data>> {
168 self.cache.get_file(self.source_location.file_idx)
169 }
170
171 pub fn function(&self) -> Function<'data> {
173 self.cache
174 .get_function(self.source_location.function_idx)
175 .unwrap_or_default()
176 }
177
178 }
181
182#[derive(Debug, Clone)]
184pub struct SourceLocations<'data, 'cache> {
185 pub(crate) cache: &'cache SymCache<'data>,
186 pub(crate) source_location_idx: u32,
187}
188
189impl<'data, 'cache> Iterator for SourceLocations<'data, 'cache> {
190 type Item = SourceLocation<'data, 'cache>;
191
192 fn next(&mut self) -> Option<Self::Item> {
193 if self.source_location_idx == u32::MAX {
194 return None;
195 }
196 self.cache
197 .source_locations
198 .get(self.source_location_idx as usize)
199 .map(|source_location| {
200 self.source_location_idx = source_location.inlined_into_idx;
201 SourceLocation {
202 cache: self.cache,
203 source_location,
204 }
205 })
206 }
207}
208
209#[derive(Debug, Clone)]
211pub struct Functions<'data> {
212 cache: SymCache<'data>,
213 function_idx: u32,
214}
215
216impl<'data> Iterator for Functions<'data> {
217 type Item = Function<'data>;
218
219 fn next(&mut self) -> Option<Self::Item> {
220 let mut function = self.cache.get_function(self.function_idx);
221
222 while let Some(ref f) = function {
223 if f.entry_pc == u32::MAX {
224 self.function_idx += 1;
225 function = self.cache.get_function(self.function_idx);
226 } else {
227 break;
228 }
229 }
230
231 if function.is_some() {
232 self.function_idx += 1;
233 }
234
235 function
236 }
237}
238
239pub struct FunctionsDebug<'a>(pub &'a SymCache<'a>);
245
246impl fmt::Debug for FunctionsDebug<'_> {
247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 let mut vec: Vec<_> = self.0.functions().collect();
249
250 vec.sort_by_key(|f| (f.entry_pc, f.name));
251 for function in vec {
252 writeln!(f, "{:>16x} {}", &function.entry_pc, &function.name)?;
253 }
254
255 Ok(())
256 }
257}
258
259#[derive(Debug, Clone)]
261pub struct Files<'data> {
262 cache: SymCache<'data>,
263 file_idx: u32,
264}
265
266impl<'data> Iterator for Files<'data> {
267 type Item = File<'data>;
268
269 fn next(&mut self) -> Option<Self::Item> {
270 let file = self.cache.get_file(self.file_idx);
271 if file.is_some() {
272 self.file_idx += 1;
273 }
274 file
275 }
276}
277
278pub struct FilesDebug<'a>(pub &'a SymCache<'a>);
283
284impl fmt::Debug for FilesDebug<'_> {
285 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
286 let mut vec: Vec<_> = self.0.files().map(|f| f.full_path()).collect();
287
288 vec.sort();
289 for file in vec {
290 writeln!(f, "{file}")?;
291 }
292
293 Ok(())
294 }
295}