wasmer_compiler/engine/trap/
frame_info.rs1use crate::types::address_map::{
16 ArchivedFunctionAddressMap, ArchivedInstructionAddressMap, FunctionAddressMap,
17 InstructionAddressMap,
18};
19use crate::types::function::{ArchivedCompiledFunctionFrameInfo, CompiledFunctionFrameInfo};
20use crate::ArtifactBuildFromArchive;
21use rkyv::vec::ArchivedVec;
22use std::collections::BTreeMap;
23use std::sync::{Arc, RwLock};
24use wasmer_types::lib::std::{cmp, ops::Deref};
25use wasmer_types::{
26 entity::{BoxedSlice, EntityRef, PrimaryMap},
27 FrameInfo, LocalFunctionIndex, ModuleInfo, SourceLoc, TrapInformation,
28};
29use wasmer_vm::FunctionBodyPtr;
30
31lazy_static::lazy_static! {
32 pub static ref FRAME_INFO: RwLock<GlobalFrameInfo> = Default::default();
38}
39
40#[derive(Default)]
41pub struct GlobalFrameInfo {
42 ranges: BTreeMap<usize, ModuleInfoFrameInfo>,
52}
53
54#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
57pub struct GlobalFrameInfoRegistration {
58 key: usize,
61}
62
63#[derive(Debug)]
64struct ModuleInfoFrameInfo {
65 start: usize,
66 functions: BTreeMap<usize, FunctionInfo>,
67 module: Arc<ModuleInfo>,
68 frame_infos: FrameInfosVariant,
69}
70
71impl ModuleInfoFrameInfo {
72 fn function_debug_info(
73 &self,
74 local_index: LocalFunctionIndex,
75 ) -> CompiledFunctionFrameInfoVariant {
76 self.frame_infos.get(local_index).unwrap()
77 }
78
79 fn function_info(&self, pc: usize) -> Option<&FunctionInfo> {
81 let (end, func) = self.functions.range(pc..).next()?;
82 if func.start <= pc && pc <= *end {
83 Some(func)
84 } else {
85 None
86 }
87 }
88}
89
90#[derive(Debug)]
91struct FunctionInfo {
92 start: usize,
93 local_index: LocalFunctionIndex,
94}
95
96impl GlobalFrameInfo {
97 pub fn lookup_frame_info(&self, pc: usize) -> Option<FrameInfo> {
102 let module = self.module_info(pc)?;
103 let func = module.function_info(pc)?;
104
105 let rel_pos = pc - func.start;
109 let debug_info = module.function_debug_info(func.local_index);
110 let instr_map = debug_info.address_map();
111 let pos = match instr_map.instructions().code_offset_by_key(rel_pos) {
112 Ok(pos) => Some(pos),
114
115 Err(0) => None,
118
119 Err(n) => {
125 let instr = &instr_map.instructions().get(n - 1);
126 if instr.code_offset <= rel_pos && rel_pos < instr.code_offset + instr.code_len {
127 Some(n - 1)
128 } else {
129 None
130 }
131 }
132 };
133
134 let instr = match pos {
135 Some(pos) => instr_map.instructions().get(pos).srcloc,
136 None => instr_map.start_srcloc(),
141 };
142 let func_index = module.module.func_index(func.local_index);
143 Some(FrameInfo::new(
144 module.module.name(),
145 func_index.index() as u32,
146 module.module.function_names.get(&func_index).cloned(),
147 instr_map.start_srcloc(),
148 instr,
149 ))
150 }
151
152 pub fn lookup_trap_info(&self, pc: usize) -> Option<TrapInformation> {
154 let module = self.module_info(pc)?;
155 let func = module.function_info(pc)?;
156 let debug_info = module.function_debug_info(func.local_index);
157 let traps = debug_info.traps();
158 let idx = traps
159 .binary_search_by_key(&((pc - func.start) as u32), |info| info.code_offset)
160 .ok()?;
161 Some(traps[idx])
162 }
163
164 fn module_info(&self, pc: usize) -> Option<&ModuleInfoFrameInfo> {
166 let (end, module_info) = self.ranges.range(pc..).next()?;
167 if module_info.start <= pc && pc <= *end {
168 Some(module_info)
169 } else {
170 None
171 }
172 }
173}
174
175impl Drop for GlobalFrameInfoRegistration {
176 fn drop(&mut self) {
177 if let Ok(mut info) = FRAME_INFO.write() {
178 info.ranges.remove(&self.key);
179 }
180 }
181}
182
183#[derive(Debug)]
186#[repr(C)]
187pub struct FunctionExtent {
188 pub ptr: FunctionBodyPtr,
191 pub length: usize,
193}
194
195#[derive(Debug)]
198pub enum FrameInfosVariant {
199 Owned(PrimaryMap<LocalFunctionIndex, CompiledFunctionFrameInfo>),
201 Archived(ArtifactBuildFromArchive),
203}
204
205impl FrameInfosVariant {
206 pub fn get(&self, index: LocalFunctionIndex) -> Option<CompiledFunctionFrameInfoVariant> {
208 match self {
209 Self::Owned(map) => map.get(index).map(CompiledFunctionFrameInfoVariant::Ref),
210 Self::Archived(archive) => archive
211 .get_frame_info_ref()
212 .get(index)
213 .map(CompiledFunctionFrameInfoVariant::Archived),
214 }
215 }
216}
217
218#[derive(Debug)]
220pub enum CompiledFunctionFrameInfoVariant<'a> {
221 Ref(&'a CompiledFunctionFrameInfo),
223 Archived(&'a ArchivedCompiledFunctionFrameInfo),
225}
226
227impl CompiledFunctionFrameInfoVariant<'_> {
228 pub fn address_map(&self) -> FunctionAddressMapVariant<'_> {
230 match self {
231 CompiledFunctionFrameInfoVariant::Ref(info) => {
232 FunctionAddressMapVariant::Ref(&info.address_map)
233 }
234 CompiledFunctionFrameInfoVariant::Archived(info) => {
235 FunctionAddressMapVariant::Archived(&info.address_map)
236 }
237 }
238 }
239
240 pub fn traps(&self) -> VecTrapInformationVariant {
242 match self {
243 CompiledFunctionFrameInfoVariant::Ref(info) => {
244 VecTrapInformationVariant::Ref(&info.traps)
245 }
246 CompiledFunctionFrameInfoVariant::Archived(info) => {
247 let traps = rkyv::deserialize::<_, rkyv::rancor::Error>(&info.traps).unwrap();
248 VecTrapInformationVariant::Owned(traps)
249 }
250 }
251 }
252}
253
254#[derive(Debug)]
256pub enum VecTrapInformationVariant<'a> {
257 Ref(&'a Vec<TrapInformation>),
258 Owned(Vec<TrapInformation>),
259}
260
261impl Deref for VecTrapInformationVariant<'_> {
263 type Target = [TrapInformation];
264
265 fn deref(&self) -> &Self::Target {
266 match self {
267 VecTrapInformationVariant::Ref(traps) => traps,
268 VecTrapInformationVariant::Owned(traps) => traps,
269 }
270 }
271}
272
273#[derive(Debug)]
274pub enum FunctionAddressMapVariant<'a> {
275 Ref(&'a FunctionAddressMap),
276 Archived(&'a ArchivedFunctionAddressMap),
277}
278
279impl FunctionAddressMapVariant<'_> {
280 pub fn instructions(&self) -> FunctionAddressMapInstructionVariant {
281 match self {
282 FunctionAddressMapVariant::Ref(map) => {
283 FunctionAddressMapInstructionVariant::Owned(&map.instructions)
284 }
285 FunctionAddressMapVariant::Archived(map) => {
286 FunctionAddressMapInstructionVariant::Archived(&map.instructions)
287 }
288 }
289 }
290
291 pub fn start_srcloc(&self) -> SourceLoc {
292 match self {
293 FunctionAddressMapVariant::Ref(map) => map.start_srcloc,
294 FunctionAddressMapVariant::Archived(map) => {
295 rkyv::deserialize::<_, rkyv::rancor::Error>(&map.start_srcloc).unwrap()
296 }
297 }
298 }
299
300 pub fn end_srcloc(&self) -> SourceLoc {
301 match self {
302 FunctionAddressMapVariant::Ref(map) => map.end_srcloc,
303 FunctionAddressMapVariant::Archived(map) => {
304 rkyv::deserialize::<_, rkyv::rancor::Error>(&map.end_srcloc).unwrap()
305 }
306 }
307 }
308
309 pub fn body_offset(&self) -> usize {
310 match self {
311 FunctionAddressMapVariant::Ref(map) => map.body_offset,
312 FunctionAddressMapVariant::Archived(map) => map.body_offset.to_native() as usize,
313 }
314 }
315
316 pub fn body_len(&self) -> usize {
317 match self {
318 FunctionAddressMapVariant::Ref(map) => map.body_len,
319 FunctionAddressMapVariant::Archived(map) => map.body_len.to_native() as usize,
320 }
321 }
322}
323
324#[derive(Debug)]
325pub enum FunctionAddressMapInstructionVariant<'a> {
326 Owned(&'a Vec<InstructionAddressMap>),
327 Archived(&'a ArchivedVec<ArchivedInstructionAddressMap>),
328}
329
330impl FunctionAddressMapInstructionVariant<'_> {
331 pub fn code_offset_by_key(&self, key: usize) -> Result<usize, usize> {
332 match self {
333 FunctionAddressMapInstructionVariant::Owned(instructions) => {
334 instructions.binary_search_by_key(&key, |map| map.code_offset)
335 }
336 FunctionAddressMapInstructionVariant::Archived(instructions) => {
337 instructions.binary_search_by_key(&key, |map| map.code_offset.to_native() as usize)
338 }
339 }
340 }
341
342 pub fn get(&self, index: usize) -> InstructionAddressMap {
343 match self {
344 FunctionAddressMapInstructionVariant::Owned(instructions) => instructions[index],
345 FunctionAddressMapInstructionVariant::Archived(instructions) => instructions
346 .get(index)
347 .map(|map| InstructionAddressMap {
348 srcloc: rkyv::deserialize::<_, rkyv::rancor::Error>(&map.srcloc).unwrap(),
349 code_offset: map.code_offset.to_native() as usize,
350 code_len: map.code_len.to_native() as usize,
351 })
352 .unwrap(),
353 }
354 }
355}
356
357pub fn register(
364 module: Arc<ModuleInfo>,
365 finished_functions: &BoxedSlice<LocalFunctionIndex, FunctionExtent>,
366 frame_infos: FrameInfosVariant,
367) -> Option<GlobalFrameInfoRegistration> {
368 let mut min = usize::MAX;
369 let mut max = 0;
370 let mut functions = BTreeMap::new();
371 for (
372 i,
373 FunctionExtent {
374 ptr: start,
375 length: len,
376 },
377 ) in finished_functions.iter()
378 {
379 let start = **start as usize;
380 let end = start + len - 1;
382 min = cmp::min(min, start);
383 max = cmp::max(max, end);
384 let func = FunctionInfo {
385 start,
386 local_index: i,
387 };
388 assert!(functions.insert(end, func).is_none());
389 }
390 if functions.is_empty() {
391 return None;
392 }
393
394 let mut info = FRAME_INFO.write().unwrap();
395 if let Some((_, prev)) = info.ranges.range(max..).next() {
398 assert!(prev.start > max);
399 }
400 if let Some((prev_end, _)) = info.ranges.range(..=min).next_back() {
401 assert!(*prev_end < min);
402 }
403
404 let prev = info.ranges.insert(
406 max,
407 ModuleInfoFrameInfo {
408 start: min,
409 functions,
410 module,
411 frame_infos,
412 },
413 );
414 assert!(prev.is_none());
415 Some(GlobalFrameInfoRegistration { key: max })
416}