symbolic_ppdb/cache/lookup.rs
1use symbolic_common::Language;
2
3use super::{raw, PortablePdbCache};
4
5/// Line information for a given IL offset in a function.
6#[derive(Debug, Copy, Clone, PartialEq, Eq)]
7pub struct LineInfo<'data> {
8 /// The line in the source file.
9 pub line: u32,
10 /// The source file's name.
11 pub file_name: &'data str,
12 /// The source language.
13 pub file_lang: Language,
14}
15
16impl<'data> PortablePdbCache<'data> {
17 /// Looks up line information for a function in the cache.
18 ///
19 /// `func_idx` is the (1-based) index of the function in the ECMA-335 `MethodDef` table
20 /// (see the ECMA-335 spec, Section II.22.26). In C#, it is encoded in the
21 /// [`MetadataToken`](https://docs.microsoft.com/en-us/dotnet/api/system.reflection.memberinfo.metadatatoken?view=net-6.0#system-reflection-memberinfo-metadatatoken)
22 /// property on the [`MethodBase`](https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase?view=net-6.0) class.
23 /// See [Metadata Tokens](https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms404456(v=vs.100)) for an
24 /// explanation of the encoding.
25 ///
26 /// `il_offset` is the offset from the start of the method's Intermediate Language code.
27 /// It can be obtained via the [`StackFrame.GetILOffset`](https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.stackframe.getiloffset?view=net-6.0#system-diagnostics-stackframe-getiloffset)
28 /// method.
29 pub fn lookup(&self, func_idx: u32, il_offset: u32) -> Option<LineInfo<'data>> {
30 let range = raw::Range {
31 func_idx,
32 il_offset,
33 };
34 let sl = match self.ranges.binary_search(&range) {
35 Ok(idx) => self.source_locations.get(idx)?,
36 Err(idx) => {
37 let idx = idx.checked_sub(1)?;
38 let range = self.ranges.get(idx)?;
39 if range.func_idx < func_idx {
40 return None;
41 }
42
43 self.source_locations.get(idx)?
44 }
45 };
46
47 let (file_name, file_lang) = self.get_file(sl.file_idx)?;
48
49 Some(LineInfo {
50 line: sl.line,
51 file_name,
52 file_lang,
53 })
54 }
55
56 fn get_file(&self, idx: u32) -> Option<(&'data str, Language)> {
57 let raw = self.files.get(idx as usize)?;
58 let name = self.get_string(raw.name_offset)?;
59
60 Some((name, Language::from_u32(raw.lang)))
61 }
62
63 /// Resolves a string reference to the pointed-to `&str` data.
64 fn get_string(&self, offset: u32) -> Option<&'data str> {
65 watto::StringTable::read(self.string_bytes, offset as usize).ok()
66 }
67}