swamp_vm_debug_info/
lib.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use seq_map::SeqMap;
6use swamp_vm_isa::InstructionPosition;
7use swamp_vm_types::Meta;
8use swamp_vm_types::types::FunctionInfo;
9
10pub struct FileOffsetEntry {
11    pub start_pc: u32, // This u32 is the instruction index, so this should be plenty
12    pub pc_count: u8,  // A line can't cover more than 255 instructions
13    pub file_id: u16,  // Maximum 65535 files in a program
14    pub line_row: u16, // Can not have more than 65536 lines in a single source file
15}
16
17pub struct FileOffsetTable {
18    pub entries: Vec<FileOffsetEntry>,
19}
20
21impl Default for FileOffsetTable {
22    fn default() -> Self {
23        Self::new()
24    }
25}
26
27impl FileOffsetTable {
28    #[must_use]
29    pub const fn new() -> Self {
30        Self { entries: vec![] }
31    }
32    #[must_use]
33    pub fn find(&self, ip: InstructionPosition) -> Option<&FileOffsetEntry> {
34        let pc = ip.0;
35        self.entries
36            .iter()
37            .find(|&entry| pc >= entry.start_pc && pc <= entry.start_pc + u32::from(entry.pc_count))
38    }
39}
40
41pub struct FunctionDebugInfo {
42    pub start_pc: u32,
43    pub function_id: u16,
44}
45
46pub struct FunctionTable {
47    pub entries: Vec<FunctionDebugInfo>,
48}
49
50impl Default for FunctionTable {
51    fn default() -> Self {
52        Self::new()
53    }
54}
55
56impl FunctionTable {
57    #[must_use]
58    pub const fn new() -> Self {
59        Self { entries: vec![] }
60    }
61    pub(crate) fn find(&self, ip: InstructionPosition) -> Option<&FunctionDebugInfo> {
62        let pc = ip.0;
63        let mut last_info = None;
64        for entry in &self.entries {
65            if entry.start_pc > pc {
66                return last_info;
67            }
68            last_info = Some(entry);
69        }
70        last_info
71    }
72}
73
74pub struct DebugInfo {
75    pub function_lookup: SeqMap<u32, u8>,
76    pub file_offsets: FileOffsetTable,
77    pub function_table: FunctionTable,
78    pub info_for_each_instruction: Vec<Meta>,
79    pub function_infos: SeqMap<u16, FunctionInfo>,
80}
81
82pub struct DebugInfoForPc {
83    pub meta: Meta,
84    pub function_debug_info: FunctionInfo,
85}
86
87impl Default for DebugInfo {
88    fn default() -> Self {
89        Self::new()
90    }
91}
92
93impl DebugInfo {
94    #[must_use]
95    pub fn new() -> Self {
96        Self {
97            function_lookup: SeqMap::default(),
98            file_offsets: FileOffsetTable::new(),
99            function_table: FunctionTable::new(),
100            info_for_each_instruction: vec![],
101            function_infos: SeqMap::default(),
102        }
103    }
104
105    #[must_use]
106    pub fn fetch(&self, pc: usize) -> Option<DebugInfoForPc> {
107        let ip = InstructionPosition(pc as u32);
108        let function = self.function_table.find(ip)?;
109
110        let meta = &self.info_for_each_instruction[ip.0 as usize];
111
112        let func_info = self.function_infos.get(&function.function_id)?;
113
114        let info = DebugInfoForPc {
115            meta: Meta {
116                comment: meta.comment.clone(),
117                node: meta.node.clone(),
118            },
119            function_debug_info: func_info.clone(),
120        };
121
122        Some(info)
123    }
124}