portal_pc_waffle/ir/
debug.rs

1//! Debug info (currently, source-location maps).
2
3use crate::declare_entity;
4use crate::entity::EntityVec;
5// use addr2line::gimli;
6use alloc::borrow::ToOwned;
7use alloc::string::String;
8use alloc::vec;
9use alloc::vec::Vec;
10use hashbrown::hash_map::Entry as HashEntry;
11use hashbrown::HashMap;
12
13declare_entity!(SourceFile, "file");
14declare_entity!(SourceLoc, "loc");
15
16#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
17pub struct Debug {
18    /// Interned source-file names, indexed by a `SourceFile` entity
19    /// index.
20    pub source_files: EntityVec<SourceFile, String>,
21    source_file_dedup: HashMap<String, SourceFile>,
22    /// Interned source locations (file, line, and column),, indexed
23    /// by a `SourceLoc` entity index.
24    pub source_locs: EntityVec<SourceLoc, SourceLocData>,
25    source_loc_dedup: HashMap<SourceLocData, SourceLoc>,
26}
27
28#[derive(
29    Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
30)]
31/// A "source location": a filename (interned to an ID), a line, and a
32/// column.
33
34pub struct SourceLocData {
35    pub file: SourceFile,
36    pub line: u32,
37    pub col: u32,
38}
39
40impl Debug {
41    /// Intern a filename to an ID.
42    pub fn intern_file(&mut self, path: &str) -> SourceFile {
43        if let Some(id) = self.source_file_dedup.get(path) {
44            return *id;
45        }
46        let id = self.source_files.push(path.to_owned());
47        self.source_file_dedup.insert(path.to_owned(), id);
48        id
49    }
50
51    /// Intern a location (line and column) in an already-interned
52    /// filename.
53    pub fn intern_loc(&mut self, file: SourceFile, line: u32, col: u32) -> SourceLoc {
54        let data = SourceLocData { file, line, col };
55        match self.source_loc_dedup.entry(data) {
56            HashEntry::Vacant(v) => {
57                let id = self.source_locs.push(data);
58                *v.insert(id)
59            }
60            HashEntry::Occupied(o) => *o.get(),
61        }
62    }
63}
64
65#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
66/// A map from ranges of offsets in the original Wasm file to source
67/// locations.
68
69pub struct DebugMap {
70    /// Offset of code section relative to the Wasm file start.
71    pub code_offset: u32,
72    /// Each tuple is `(start, len, loc)`. The `start` offset is
73    /// relative to the code section.
74    pub tuples: Vec<(u32, u32, SourceLoc)>,
75}
76
77impl DebugMap {
78    // pub(crate) fn from_dwarf<R: gimli::Reader>(
79    //     // dwarf: gimli::Dwarf<R>,
80    //     debug: &mut Debug,
81    //     code_offset: u32,
82    // ) -> anyhow::Result<DebugMap> {
83    // anyhow::bail!("todo: reimplement or use no_std dwarf")
84    // let ctx = addr2line::Context::from_dwarf(dwarf)?;
85    // let mut tuples = vec![];
86
87    // let mut locs = ctx.find_location_range(0, u64::MAX).unwrap();
88    // while let Some((start, len, loc)) = locs.next() {
89    //     let file = debug.intern_file(loc.file.unwrap_or(""));
90    //     let loc = debug.intern_loc(file, loc.line.unwrap_or(0), loc.column.unwrap_or(0));
91    //     log::trace!("tuple: loc {} start {:x} len {:x}", loc, start, len);
92    //     tuples.push((start as u32, len as u32, loc));
93    // }
94    // tuples.sort();
95
96    // let mut last = 0;
97    // tuples.retain(|&(start, len, _)| {
98    //     let retain = start >= last;
99    //     if retain {
100    //         last = start + len;
101    //     }
102    //     retain
103    // });
104
105    // Ok(DebugMap {
106    //     code_offset,
107    //     tuples,
108    // })
109    // }
110}