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}