xref: /wasmtime-44.0.1/tests/all/debug.rs (revision cfd8a4d2)
1 //! Tests for instrumentation-based debugging.
2 
3 use std::sync::atomic::{AtomicUsize, Ordering};
4 use std::sync::{Arc, Mutex};
5 use wasmtime::{
6     AsContextMut, Caller, Config, DebugEvent, DebugHandler, Engine, Extern, FrameHandle, Func,
7     Global, GlobalType, Instance, Module, Mutability, Store, StoreContextMut, Val, ValType,
8 };
9 
10 use crate::async_functions::PollOnce;
11 
12 #[test]
13 fn debugging_does_not_work_with_signal_based_traps() {
14     let mut config = Config::default();
15     config.guest_debug(true).signals_based_traps(true);
16     let err = Engine::new(&config).expect_err("invalid config should produce an error");
17     assert!(format!("{err:?}").contains("cannot use signals-based traps"));
18 }
19 
20 #[test]
21 fn debugging_apis_are_denied_without_debugging() -> wasmtime::Result<()> {
22     let mut config = Config::default();
23     config.guest_debug(false);
24     let engine = Engine::new(&config)?;
25     let module = Module::new(&engine, "(module (global $g (mut i32) (i32.const 0)))")?;
26     let mut store = Store::new(&engine, ());
27     let instance = Instance::new(&mut store, &module, &[])?;
28 
29     assert!(store.debug_exit_frames().next().is_none());
30     assert!(instance.debug_global(&mut store, 0).is_none());
31 
32     Ok(())
33 }
34 
35 fn get_module_and_store<C: Fn(&mut Config)>(
36     c: C,
37     wat: &str,
38 ) -> wasmtime::Result<(Module, Store<()>)> {
39     let mut config = Config::default();
40     config.guest_debug(true);
41     config.wasm_exceptions(true);
42     c(&mut config);
43     let engine = Engine::new(&config)?;
44     let module = Module::new(&engine, wat)?;
45     Ok((module, Store::new(&engine, ())))
46 }
47 
48 fn test_stack_values<
49     C: Fn(&mut Config),
50     F: Fn(Caller<'_, ()>) -> wasmtime::Result<()> + Send + Sync + 'static,
51 >(
52     wat: &str,
53     c: C,
54     f: F,
55 ) -> wasmtime::Result<()> {
56     let (module, mut store) = get_module_and_store(c, wat)?;
57     let func = Func::wrap(&mut store, move |caller: Caller<'_, ()>| {
58         f(caller)?;
59         Ok(())
60     });
61     let instance = Instance::new(&mut store, &module, &[Extern::Func(func)])?;
62     let mut results = [];
63     instance
64         .get_func(&mut store, "main")
65         .unwrap()
66         .call(&mut store, &[], &mut results)?;
67 
68     Ok(())
69 }
70 
71 #[test]
72 #[cfg_attr(miri, ignore)]
73 fn stack_values_two_frames() -> wasmtime::Result<()> {
74     let _ = env_logger::try_init();
75 
76     for inlining in [false, true] {
77         test_stack_values(
78             r#"
79     (module
80       (import "" "host" (func))
81       (func (export "main")
82         i32.const 1
83         i32.const 2
84         call 2
85         drop)
86       (func (param i32 i32) (result i32)
87         local.get 0
88         local.get 1
89         call 0
90         i32.add))
91     "#,
92             |config| {
93                 config.compiler_inlining(inlining);
94                 if inlining {
95                     unsafe {
96                         config.cranelift_flag_set("wasmtime_inlining_intra_module", "true");
97                     }
98                 }
99             },
100             |mut caller: Caller<'_, ()>| {
101                 let stack = caller.debug_exit_frames().next().unwrap();
102                 assert_eq!(
103                     stack
104                         .wasm_function_index_and_pc(&mut caller)?
105                         .unwrap()
106                         .0
107                         .as_u32(),
108                     1
109                 );
110                 assert_eq!(
111                     stack.wasm_function_index_and_pc(&mut caller)?.unwrap().1,
112                     65
113                 );
114 
115                 assert_eq!(stack.num_locals(&mut caller)?, 2);
116                 assert_eq!(stack.num_stacks(&mut caller)?, 2);
117                 assert_eq!(stack.local(&mut caller, 0)?.unwrap_i32(), 1);
118                 assert_eq!(stack.local(&mut caller, 1)?.unwrap_i32(), 2);
119                 assert_eq!(stack.stack(&mut caller, 0)?.unwrap_i32(), 1);
120                 assert_eq!(stack.stack(&mut caller, 1)?.unwrap_i32(), 2);
121 
122                 let stack = stack.parent(&mut caller)?.unwrap();
123                 assert_eq!(
124                     stack
125                         .wasm_function_index_and_pc(&mut caller)?
126                         .unwrap()
127                         .0
128                         .as_u32(),
129                     0
130                 );
131                 assert_eq!(
132                     stack.wasm_function_index_and_pc(&mut caller)?.unwrap().1,
133                     55
134                 );
135 
136                 let stack = stack.parent(&mut caller)?;
137                 assert!(stack.is_none());
138                 Ok(())
139             },
140         )?;
141     }
142     Ok(())
143 }
144 
145 #[test]
146 #[cfg_attr(miri, ignore)]
147 fn stack_values_exceptions() -> wasmtime::Result<()> {
148     test_stack_values(
149         r#"
150     (module
151       (tag $t (param i32))
152       (import "" "host" (func))
153       (func (export "main")
154         (block $b (result i32)
155           (try_table (catch $t $b)
156             (throw $t (i32.const 42)))
157           i32.const 0)
158         (call 0)
159         (drop)))
160     "#,
161         |_config| {},
162         |mut caller: Caller<'_, ()>| {
163             let stack = caller.debug_exit_frames().next().unwrap();
164             assert_eq!(stack.num_stacks(&mut caller)?, 1);
165             assert_eq!(stack.stack(&mut caller, 0)?.unwrap_i32(), 42);
166             let stack = stack.parent(&mut caller)?;
167             assert!(stack.is_none());
168             Ok(())
169         },
170     )
171 }
172 
173 #[test]
174 #[cfg_attr(miri, ignore)]
175 fn stack_values_dead_gc_ref() -> wasmtime::Result<()> {
176     test_stack_values(
177         r#"
178     (module
179       (type $s (struct))
180       (import "" "host" (func))
181       (func (export "main")
182         (struct.new $s)
183         (call 0)
184         (drop)))
185     "#,
186         |config| {
187             config.wasm_gc(true);
188         },
189         |mut caller: Caller<'_, ()>| {
190             let stack = caller.debug_exit_frames().next().unwrap();
191             assert_eq!(stack.num_stacks(&mut caller)?, 1);
192             assert!(stack.stack(&mut caller, 0)?.unwrap_anyref().is_some());
193             let stack = stack.parent(&mut caller)?;
194             assert!(stack.is_none());
195             Ok(())
196         },
197     )
198 }
199 
200 #[test]
201 #[cfg_attr(miri, ignore)]
202 fn gc_access_during_call() -> wasmtime::Result<()> {
203     test_stack_values(
204         r#"
205     (module
206       (type $s (struct (field i32)))
207       (import "" "host" (func))
208       (func (export "main")
209         (local $l (ref null $s))
210         (local.set $l (struct.new $s (i32.const 42)))
211         (call 0)))
212     "#,
213         |config| {
214             config.wasm_gc(true);
215         },
216         |mut caller: Caller<'_, ()>| {
217             let stack = caller.debug_exit_frames().next().unwrap();
218 
219             // Do a GC while we hold the stack cursor.
220             caller.as_context_mut().gc(None).unwrap();
221 
222             assert_eq!(stack.num_stacks(&mut caller)?, 0);
223             assert_eq!(stack.num_locals(&mut caller)?, 1);
224             // Note that this struct is dead during the call, and the
225             // ref could otherwise be optimized away (no longer in the
226             // stackmap at this point); but we verify it is still
227             // alive here because it is rooted in the
228             // debug-instrumentation slot.
229             let s = stack
230                 .local(&mut caller, 0)?
231                 .unwrap_any_ref()
232                 .unwrap()
233                 .unwrap_struct(&caller)
234                 .unwrap();
235             assert_eq!(s.field(&mut caller, 0).unwrap().unwrap_i32(), 42);
236             let stack = stack.parent(&mut caller)?;
237             assert!(stack.is_none());
238             Ok(())
239         },
240     )
241 }
242 
243 #[test]
244 #[cfg_attr(miri, ignore)]
245 fn stack_values_two_activations() -> wasmtime::Result<()> {
246     let _ = env_logger::try_init();
247 
248     let mut config = Config::default();
249     config.guest_debug(true);
250     config.wasm_exceptions(true);
251     let engine = Engine::new(&config)?;
252     let module1 = Module::new(
253         &engine,
254         r#"
255     (module
256       (import "" "host1" (func (param i32 i32) (result i32)))
257       (func (export "main") (result i32)
258         i32.const 1
259         i32.const 2
260         call 0))
261     "#,
262     )?;
263     let module2 = Module::new(
264         &engine,
265         r#"
266     (module
267       (import "" "host2" (func))
268       (func (export "inner") (param i32 i32) (result i32)
269         local.get 0
270         local.get 1
271         call 0
272         i32.add))
273     "#,
274     )?;
275     let mut store = Store::new(&engine, ());
276 
277     let module1_clone = module1.clone();
278     let module2_clone = module2.clone();
279     let host2 = Func::wrap(&mut store, move |mut caller: Caller<'_, ()>| {
280         let exits = caller.debug_exit_frames().collect::<Vec<_>>();
281         assert_eq!(exits.len(), 2);
282         let stack = exits[0].clone();
283         assert_eq!(
284             stack
285                 .wasm_function_index_and_pc(&mut caller)?
286                 .unwrap()
287                 .0
288                 .as_u32(),
289             0
290         );
291         assert_eq!(
292             stack.wasm_function_index_and_pc(&mut caller)?.unwrap().1,
293             56
294         );
295         assert!(Module::same(
296             stack.module(&mut caller)?.unwrap(),
297             &module2_clone
298         ));
299         assert_eq!(stack.num_locals(&mut caller)?, 2);
300         assert_eq!(stack.num_stacks(&mut caller)?, 2);
301         assert_eq!(stack.local(&mut caller, 0)?.unwrap_i32(), 1);
302         assert_eq!(stack.local(&mut caller, 1)?.unwrap_i32(), 2);
303         assert_eq!(stack.stack(&mut caller, 0)?.unwrap_i32(), 1);
304         assert_eq!(stack.stack(&mut caller, 1)?.unwrap_i32(), 2);
305         let inner_instance = stack.instance(&mut caller)?;
306 
307         let stack = stack.parent(&mut caller)?;
308         assert!(stack.is_none());
309 
310         let stack = exits[1].clone();
311         assert_eq!(
312             stack
313                 .wasm_function_index_and_pc(&mut caller)?
314                 .unwrap()
315                 .0
316                 .as_u32(),
317             0
318         );
319         assert_eq!(
320             stack.wasm_function_index_and_pc(&mut caller)?.unwrap().1,
321             56
322         );
323         assert!(Module::same(
324             stack.module(&mut caller)?.unwrap(),
325             &module1_clone
326         ));
327         assert_eq!(stack.num_locals(&mut caller)?, 0);
328         assert_eq!(stack.num_stacks(&mut caller)?, 2);
329         assert_eq!(stack.stack(&mut caller, 0)?.unwrap_i32(), 1);
330         assert_eq!(stack.stack(&mut caller, 1)?.unwrap_i32(), 2);
331         let outer_instance = stack.instance(&mut caller)?;
332         assert_ne!(inner_instance, outer_instance);
333 
334         let stack = stack.parent(&mut caller)?;
335         assert!(stack.is_none());
336 
337         Ok(())
338     });
339 
340     let instance2 = Instance::new(&mut store, &module2, &[Extern::Func(host2)])?;
341     let inner = instance2.get_func(&mut store, "inner").unwrap();
342 
343     let host1 = Func::wrap(
344         &mut store,
345         move |mut caller: Caller<'_, ()>, a: i32, b: i32| -> i32 {
346             let mut results = [Val::I32(0)];
347             inner
348                 .call(&mut caller, &[Val::I32(a), Val::I32(b)], &mut results[..])
349                 .unwrap();
350             results[0].unwrap_i32()
351         },
352     );
353 
354     let instance1 = Instance::new(&mut store, &module1, &[Extern::Func(host1)])?;
355     let main = instance1.get_func(&mut store, "main").unwrap();
356 
357     let mut results = [Val::I32(0)];
358     main.call(&mut store, &[], &mut results)?;
359     assert_eq!(results[0].unwrap_i32(), 3);
360     Ok(())
361 }
362 
363 #[test]
364 #[cfg_attr(miri, ignore)]
365 fn debug_frames_on_store_with_no_wasm_activation() -> wasmtime::Result<()> {
366     let mut config = Config::default();
367     config.guest_debug(true);
368     let engine = Engine::new(&config)?;
369     let mut store = Store::new(&engine, ());
370     let frames = store.debug_exit_frames().collect::<Vec<_>>();
371     assert_eq!(frames.len(), 0);
372     Ok(())
373 }
374 
375 #[test]
376 #[cfg_attr(miri, ignore)]
377 fn private_entity_access() -> wasmtime::Result<()> {
378     let mut config = Config::default();
379     config.guest_debug(true);
380     config.wasm_gc(true);
381     config.gc_support(true);
382     config.wasm_exceptions(true);
383     let engine = Engine::new(&config)?;
384     let mut store = Store::new(&engine, ());
385     let module = Module::new(
386         &engine,
387         r#"
388         (module
389           (import "" "i" (global (mut i32)))
390           (import "" "f" (func (result i32)))
391           (global $g (mut i32) (i32.const 0))
392           (memory $m 1 1)
393           (table $t 10 10 i31ref)
394           (tag $tag (param f64))
395           (func (export "main")
396             ;; $g := 42
397             i32.const 42
398             global.set $g
399             ;; $m[1024] := 1
400             i32.const 1024
401             i32.const 1
402             i32.store8 $m
403             ;; $t[1] := (ref.i31 (i32.const 100))
404             i32.const 1
405             i32.const 100
406             ref.i31
407             table.set $t)
408 
409           (func (param i32)
410             local.get 0
411             global.set $g))
412         "#,
413     )?;
414 
415     let host_global = Global::new(
416         &mut store,
417         GlobalType::new(ValType::I32, Mutability::Var),
418         Val::I32(1000),
419     )?;
420     let host_func = Func::wrap(&mut store, |_caller: Caller<'_, ()>| -> i32 { 7 });
421 
422     let instance = Instance::new(
423         &mut store,
424         &module,
425         &[Extern::Global(host_global), Extern::Func(host_func)],
426     )?;
427     let func = instance.get_func(&mut store, "main").unwrap();
428     func.call(&mut store, &[], &mut [])?;
429 
430     // Nothing is exported except for `main`, yet we can still access
431     // (below).
432     let exports = instance.exports(&mut store).collect::<Vec<_>>();
433     assert_eq!(exports.len(), 1);
434     assert!(exports.into_iter().next().unwrap().into_func().is_some());
435 
436     // We can call a non-exported function.
437     let f = instance.debug_function(&mut store, 2).unwrap();
438     f.call(&mut store, &[Val::I32(1234)], &mut [])?;
439 
440     let g = instance.debug_global(&mut store, 1).unwrap();
441     assert_eq!(g.get(&mut store).unwrap_i32(), 1234);
442 
443     let m = instance.debug_memory(&mut store, 0).unwrap();
444     assert_eq!(m.data(&mut store)[1024], 1);
445 
446     let t = instance.debug_table(&mut store, 0).unwrap();
447     let t_val = t.get(&mut store, 1).unwrap();
448     let t_val = t_val.as_any().unwrap().unwrap().unwrap_i31(&store).unwrap();
449     assert_eq!(t_val.get_u32(), 100);
450 
451     let tag = instance.debug_tag(&mut store, 0).unwrap();
452     assert!(matches!(
453         tag.ty(&store).ty().param(0).unwrap(),
454         ValType::F64
455     ));
456 
457     // Check that we can access an imported global in the instance's
458     // index space.
459     let host_global_import = instance.debug_global(&mut store, 0).unwrap();
460     assert_eq!(host_global_import.get(&mut store).unwrap_i32(), 1000);
461 
462     // Check that we can call an imported function in the instance's
463     // index space.
464     let host_func_import = instance.debug_function(&mut store, 0).unwrap();
465     let mut results = [Val::I32(0)];
466     host_func_import.call(&mut store, &[], &mut results[..])?;
467     assert_eq!(results[0].unwrap_i32(), 7);
468 
469     // Check that out-of-bounds returns `None` rather than panic'ing.
470     assert!(instance.debug_global(&mut store, 2).is_none());
471 
472     Ok(())
473 }
474 
475 #[test]
476 #[cfg_attr(miri, ignore)]
477 #[cfg(target_pointer_width = "64")] // Threads not supported on 32-bit systems.
478 fn private_entity_access_shared_memory() -> wasmtime::Result<()> {
479     let mut config = Config::default();
480     config.guest_debug(true);
481     config.shared_memory(true);
482     config.wasm_threads(true);
483     let engine = Engine::new(&config)?;
484     let mut store = Store::new(&engine, ());
485     let module = Module::new(
486         &engine,
487         r#"
488         (module
489           (memory 1 1 shared))
490         "#,
491     )?;
492 
493     let instance = Instance::new(&mut store, &module, &[])?;
494 
495     let m = instance.debug_shared_memory(&mut store, 0).unwrap();
496     let unsafe_cell = &m.data()[1024];
497     assert_eq!(unsafe { *unsafe_cell.get() }, 0);
498 
499     Ok(())
500 }
501 
502 #[test]
503 #[cfg_attr(miri, ignore)]
504 fn all_instances_and_modules_in_store() -> wasmtime::Result<()> {
505     let mut config = Config::default();
506     config.guest_debug(true);
507     let engine = Engine::new(&config)?;
508     let mut store = Store::new(&engine, ());
509     let m1 = Module::new(
510         &engine,
511         r#"
512         (module (func (param i32) (result i32) (local.get 0)))
513         "#,
514     )?;
515     let m2 = Module::new(
516         &engine,
517         r#"
518         (module (func (param i32) (result i32) (local.get 0)))
519         "#,
520     )?;
521     let i1 = Instance::new(&mut store, &m1, &[])?;
522     let i2 = Instance::new(&mut store, &m2, &[])?;
523 
524     let instances = store.debug_all_instances();
525     let modules = store.debug_all_modules();
526     assert_eq!(instances.len(), 2);
527     assert_eq!(modules.len(), 2);
528     assert!(
529         (Module::same(&modules[0], &m1) && Module::same(&modules[1], &m2))
530             || (Module::same(&modules[1], &m1) && Module::same(&modules[0], &m2))
531     );
532     assert!(instances[0] == i1);
533     assert!(instances[1] == i2);
534     Ok(())
535 }
536 
537 macro_rules! debug_event_checker {
538     ($ty:tt,
539      $store:tt,
540      $(
541          { $i:expr ; $pat:pat => $body:tt }
542      ),*)
543     =>
544     {
545         #[derive(Clone)]
546         struct $ty(Arc<AtomicUsize>);
547         impl $ty {
548             fn new_and_counter() -> (Self, Arc<AtomicUsize>) {
549                 let counter = Arc::new(AtomicUsize::new(0));
550                 let counter_clone = counter.clone();
551                 ($ty(counter), counter_clone)
552             }
553         }
554         impl DebugHandler for $ty {
555             type Data = ();
556             fn handle(
557                 &self,
558                 #[allow(unused_variables, reason = "macro rules")]
559                 #[allow(unused_mut, reason = "macro rules")]
560                 mut $store: StoreContextMut<'_, ()>,
561                 event: DebugEvent<'_>,
562             ) -> impl Future<Output = ()> + Send {
563                 let step = self.0.fetch_add(1, Ordering::Relaxed);
564                 async move {
565                     if false {}
566                     $(
567                         else if step == $i {
568                             match event {
569                                 $pat => {
570                                     $body;
571                                 }
572                                 _ => panic!("Incorrect event"),
573                             }
574                         }
575                     )*
576                     else {
577                         panic!("Too many steps");
578                     }
579                 }
580             }
581         }
582     }
583 }
584 
585 #[tokio::test]
586 #[cfg_attr(miri, ignore)]
587 async fn uncaught_exception_events() -> wasmtime::Result<()> {
588     let _ = env_logger::try_init();
589 
590     let (module, mut store) = get_module_and_store(
591         |config| {
592             config.wasm_exceptions(true);
593         },
594         r#"
595     (module
596       (tag $t (param i32))
597       (func (export "main")
598         call 1)
599       (func
600         (local $i i32)
601         (local.set $i (i32.const 100))
602         (throw $t (i32.const 42))))
603     "#,
604     )?;
605 
606     debug_event_checker!(
607         D, store,
608         { 0 ;
609           wasmtime::DebugEvent::UncaughtExceptionThrown(e) => {
610               assert_eq!(e.field(&mut store, 0).unwrap().unwrap_i32(), 42);
611               let stack = store.debug_exit_frames().next().unwrap();
612               assert_eq!(stack.num_locals(&mut store).unwrap(), 1);
613               assert_eq!(stack.local(&mut store, 0).unwrap().unwrap_i32(), 100);
614               let stack = stack.parent(&mut store).unwrap().unwrap();
615               let stack = stack.parent(&mut store).unwrap();
616               assert!(stack.is_none());
617           }
618         }
619     );
620 
621     let (handler, counter) = D::new_and_counter();
622     store.set_debug_handler(handler);
623 
624     let instance = Instance::new_async(&mut store, &module, &[]).await?;
625     let func = instance.get_func(&mut store, "main").unwrap();
626     let mut results = [];
627     let result = func.call_async(&mut store, &[], &mut results).await;
628     assert!(result.is_err()); // Uncaught exception.
629     assert_eq!(counter.load(Ordering::Relaxed), 1);
630 
631     Ok(())
632 }
633 
634 #[tokio::test]
635 #[cfg_attr(miri, ignore)]
636 async fn caught_exception_events() -> wasmtime::Result<()> {
637     let _ = env_logger::try_init();
638 
639     let (module, mut store) = get_module_and_store(
640         |config| {
641             config.wasm_exceptions(true);
642         },
643         r#"
644     (module
645       (tag $t (param i32))
646       (func (export "main")
647         (block $b (result i32)
648           (try_table (catch $t $b)
649             call 1)
650           i32.const 0)
651         drop)
652       (func
653         (local $i i32)
654         (local.set $i (i32.const 100))
655         (throw $t (i32.const 42))))
656     "#,
657     )?;
658 
659     debug_event_checker!(
660         D, store,
661         { 0 ;
662           wasmtime::DebugEvent::CaughtExceptionThrown(e) => {
663               assert_eq!(e.field(&mut store, 0).unwrap().unwrap_i32(), 42);
664               let stack = store.debug_exit_frames().next().unwrap();
665               assert_eq!(stack.num_locals(&mut store).unwrap(), 1);
666               assert_eq!(stack.local(&mut store, 0).unwrap().unwrap_i32(), 100);
667               let stack = stack.parent(&mut store).unwrap().unwrap();
668               let stack = stack.parent(&mut store).unwrap();
669               assert!(stack.is_none());
670           }
671         }
672     );
673 
674     let (handler, counter) = D::new_and_counter();
675     store.set_debug_handler(handler);
676 
677     let instance = Instance::new_async(&mut store, &module, &[]).await?;
678     let func = instance.get_func(&mut store, "main").unwrap();
679     let mut results = [];
680     func.call_async(&mut store, &[], &mut results).await?;
681     assert_eq!(counter.load(Ordering::Relaxed), 1);
682 
683     Ok(())
684 }
685 
686 #[tokio::test]
687 #[cfg_attr(miri, ignore)]
688 async fn hostcall_trap_events() -> wasmtime::Result<()> {
689     let _ = env_logger::try_init();
690 
691     let (module, mut store) = get_module_and_store(
692         |config| {
693             config.wasm_exceptions(true);
694         },
695         r#"
696     (module
697       (func (export "main")
698         i32.const 0
699         i32.const 0
700         i32.div_u
701         drop))
702     "#,
703     )?;
704 
705     debug_event_checker!(
706         D, store,
707         { 0 ;
708           wasmtime::DebugEvent::Trap(wasmtime_environ::Trap::IntegerDivisionByZero) => {}
709         }
710     );
711 
712     let (handler, counter) = D::new_and_counter();
713     store.set_debug_handler(handler);
714 
715     let instance = Instance::new_async(&mut store, &module, &[]).await?;
716     let func = instance.get_func(&mut store, "main").unwrap();
717     let mut results = [];
718     let result = func.call_async(&mut store, &[], &mut results).await;
719     assert!(result.is_err()); // Uncaught trap.
720     assert_eq!(counter.load(Ordering::Relaxed), 1);
721 
722     Ok(())
723 }
724 
725 #[tokio::test]
726 #[cfg_attr(miri, ignore)]
727 async fn hostcall_error_events() -> wasmtime::Result<()> {
728     let _ = env_logger::try_init();
729 
730     let (module, mut store) = get_module_and_store(
731         |config| {
732             config.wasm_exceptions(true);
733         },
734         r#"
735     (module
736       (import "" "do_a_trap" (func))
737       (func (export "main")
738         call 0))
739     "#,
740     )?;
741 
742     debug_event_checker!(
743         D, store,
744         { 0 ;
745           wasmtime::DebugEvent::HostcallError(e) => {
746               assert!(format!("{e:?}").contains("secret error message"));
747           }
748         }
749     );
750 
751     let (handler, counter) = D::new_and_counter();
752     store.set_debug_handler(handler);
753 
754     let do_a_trap = Func::wrap(
755         &mut store,
756         |_caller: Caller<'_, ()>| -> wasmtime::Result<()> {
757             Err(wasmtime::format_err!("secret error message"))
758         },
759     );
760     let instance = Instance::new_async(&mut store, &module, &[Extern::Func(do_a_trap)]).await?;
761     let func = instance.get_func(&mut store, "main").unwrap();
762     let mut results = [];
763     let result = func.call_async(&mut store, &[], &mut results).await;
764     assert!(result.is_err()); // Uncaught trap.
765     assert_eq!(counter.load(Ordering::Relaxed), 1);
766     Ok(())
767 }
768 
769 #[tokio::test]
770 #[cfg_attr(miri, ignore)]
771 async fn breakpoint_events() -> wasmtime::Result<()> {
772     let _ = env_logger::try_init();
773 
774     let (module, mut store) = get_module_and_store(
775         |config| {
776             config.wasm_exceptions(true);
777         },
778         r#"
779     (module
780       (func (export "main") (param i32 i32) (result i32)
781         local.get 0
782         local.get 1
783         i32.add))
784     "#,
785     )?;
786 
787     debug_event_checker!(
788         D, store,
789         { 0 ;
790           wasmtime::DebugEvent::Breakpoint => {
791               let stack = store.debug_exit_frames().next().unwrap();
792               assert_eq!(stack.num_locals(&mut store).unwrap(), 2);
793               assert_eq!(stack.local(&mut store, 0).unwrap().unwrap_i32(), 1);
794               assert_eq!(stack.local(&mut store, 1).unwrap().unwrap_i32(), 2);
795               let (func, pc) = stack.wasm_function_index_and_pc(&mut store).unwrap().unwrap();
796               assert_eq!(func.as_u32(), 0);
797               assert_eq!(pc, 0x28);
798               let stack = stack.parent(&mut store).unwrap();
799               assert!(stack.is_none());
800           }
801         }
802     );
803 
804     let (handler, counter) = D::new_and_counter();
805     store.set_debug_handler(handler);
806     store
807         .edit_breakpoints()
808         .unwrap()
809         .add_breakpoint(&module, 0x28)?;
810 
811     let instance = Instance::new_async(&mut store, &module, &[]).await?;
812     let func = instance.get_func(&mut store, "main").unwrap();
813     let mut results = [Val::I32(0)];
814     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
815         .await?;
816     assert_eq!(counter.load(Ordering::Relaxed), 1);
817     assert_eq!(results[0].unwrap_i32(), 3);
818 
819     let breakpoints = store.breakpoints().unwrap().collect::<Vec<_>>();
820     assert_eq!(breakpoints.len(), 1);
821     assert!(Module::same(&breakpoints[0].module, &module));
822     assert_eq!(breakpoints[0].pc, 0x28);
823 
824     store
825         .edit_breakpoints()
826         .unwrap()
827         .remove_breakpoint(&module, 0x28)?;
828     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
829         .await?;
830     assert_eq!(counter.load(Ordering::Relaxed), 1); // Should not have incremented from above.
831     assert_eq!(results[0].unwrap_i32(), 3);
832 
833     // Enable single-step mode (on top of the breakpoint already enabled).
834     assert!(!store.is_single_step());
835     store.edit_breakpoints().unwrap().single_step(true).unwrap();
836     assert!(store.is_single_step());
837 
838     debug_event_checker!(
839         D2, store,
840         { 0 ;
841           wasmtime::DebugEvent::Breakpoint => {
842               let stack = store.debug_exit_frames().next().unwrap();
843               let (_, pc) = stack.wasm_function_index_and_pc(&mut store).unwrap().unwrap();
844               assert_eq!(pc, 0x24);
845           }
846         },
847         {
848           1 ;
849           wasmtime::DebugEvent::Breakpoint => {
850               let stack = store.debug_exit_frames().next().unwrap();
851               let (_, pc) = stack.wasm_function_index_and_pc(&mut store).unwrap().unwrap();
852               assert_eq!(pc, 0x26);
853           }
854         },
855         {
856           2 ;
857           wasmtime::DebugEvent::Breakpoint => {
858               let stack = store.debug_exit_frames().next().unwrap();
859               let (_, pc) = stack.wasm_function_index_and_pc(&mut store).unwrap().unwrap();
860               assert_eq!(pc, 0x28);
861           }
862         },
863         {
864           3 ;
865           wasmtime::DebugEvent::Breakpoint => {
866               let stack = store.debug_exit_frames().next().unwrap();
867               let (_, pc) = stack.wasm_function_index_and_pc(&mut store).unwrap().unwrap();
868               assert_eq!(pc, 0x29);
869           }
870         }
871     );
872 
873     let (handler, counter) = D2::new_and_counter();
874     store.set_debug_handler(handler);
875 
876     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
877         .await?;
878     assert_eq!(counter.load(Ordering::Relaxed), 4);
879 
880     // Re-enable individual breakpoint.
881     store
882         .edit_breakpoints()
883         .unwrap()
884         .add_breakpoint(&module, 0x28)
885         .unwrap();
886 
887     // Now disable single-stepping. The single breakpoint set above
888     // should still remain.
889     store
890         .edit_breakpoints()
891         .unwrap()
892         .single_step(false)
893         .unwrap();
894 
895     let (handler, counter) = D::new_and_counter();
896     store.set_debug_handler(handler);
897 
898     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
899         .await?;
900     assert_eq!(counter.load(Ordering::Relaxed), 1);
901 
902     Ok(())
903 }
904 
905 #[tokio::test]
906 #[cfg_attr(miri, ignore)]
907 async fn breakpoints_in_inlined_code() -> wasmtime::Result<()> {
908     let _ = env_logger::try_init();
909 
910     let (module, mut store) = get_module_and_store(
911         |config| {
912             config.wasm_exceptions(true);
913             config.compiler_inlining(true);
914             unsafe {
915                 config.cranelift_flag_set("wasmtime_inlining_intra_module", "true");
916             }
917         },
918         r#"
919     (module
920       (func $f (export "f") (param i32 i32) (result i32)
921         local.get 0
922         local.get 1
923         i32.add)
924 
925       (func (export "main") (param i32 i32) (result i32)
926         local.get 0
927         local.get 1
928         call $f))
929     "#,
930     )?;
931 
932     debug_event_checker!(
933         D, store,
934         { 0 ;
935           wasmtime::DebugEvent::Breakpoint => {}
936         },
937         { 1 ;
938           wasmtime::DebugEvent::Breakpoint => {}
939         }
940     );
941 
942     let (handler, counter) = D::new_and_counter();
943     store.set_debug_handler(handler);
944     store
945         .edit_breakpoints()
946         .unwrap()
947         .add_breakpoint(&module, 0x2d)?; // `i32.add` in `$f`.
948 
949     let instance = Instance::new_async(&mut store, &module, &[]).await?;
950     let func_main = instance.get_func(&mut store, "main").unwrap();
951     let func_f = instance.get_func(&mut store, "f").unwrap();
952     let mut results = [Val::I32(0)];
953     // Breakpoint in `$f` should have been hit in `main` even if it
954     // was inlined.
955     func_main
956         .call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
957         .await?;
958     assert_eq!(counter.load(Ordering::Relaxed), 1);
959     assert_eq!(results[0].unwrap_i32(), 3);
960 
961     // Breakpoint in `$f` should be hit when called directly, too.
962     func_f
963         .call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
964         .await?;
965     assert_eq!(counter.load(Ordering::Relaxed), 2);
966     assert_eq!(results[0].unwrap_i32(), 3);
967 
968     Ok(())
969 }
970 
971 #[tokio::test]
972 #[cfg_attr(miri, ignore)]
973 async fn epoch_events() -> wasmtime::Result<()> {
974     let _ = env_logger::try_init();
975 
976     let (module, mut store) = get_module_and_store(
977         |config| {
978             config.epoch_interruption(true);
979         },
980         r#"
981     (module
982       (func $f (export "f") (param i32 i32) (result i32)
983         local.get 0
984         local.get 1
985         i32.add))
986     "#,
987     )?;
988 
989     debug_event_checker!(
990         D, store,
991         { 0 ;
992           wasmtime::DebugEvent::EpochYield => {}
993         }
994     );
995 
996     let (handler, counter) = D::new_and_counter();
997     store.set_debug_handler(handler);
998 
999     store.set_epoch_deadline(1);
1000     store.epoch_deadline_async_yield_and_update(1);
1001     store.engine().increment_epoch();
1002 
1003     let instance = Instance::new_async(&mut store, &module, &[]).await?;
1004     let func_f = instance.get_func(&mut store, "f").unwrap();
1005     let mut results = [Val::I32(0)];
1006     func_f
1007         .call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
1008         .await?;
1009     assert_eq!(counter.load(Ordering::Relaxed), 1);
1010     assert_eq!(results[0].unwrap_i32(), 3);
1011 
1012     Ok(())
1013 }
1014 
1015 #[tokio::test]
1016 #[cfg_attr(miri, ignore)]
1017 async fn invalidated_frame_handles() -> wasmtime::Result<()> {
1018     let (module, mut store) = get_module_and_store(
1019         |_config| {},
1020         r#"
1021     (module
1022       (import "" "" (func))
1023       (func (export "main")
1024         (local i32 i32)
1025         i32.const 1
1026         local.set 0
1027         i32.const 2
1028         local.set 1
1029         call 2
1030         call 0)
1031       (func
1032         (local i32 i32)
1033         i32.const 3
1034         local.set 0
1035         i32.const 4
1036         local.set 1
1037         call 0))
1038         "#,
1039     )?;
1040 
1041     let handle: Arc<Mutex<Option<FrameHandle>>> = Arc::new(Mutex::new(None));
1042 
1043     let hostfunc = Func::wrap_async(&mut store, move |mut caller, _args: ()| {
1044         let handle = handle.clone();
1045         Box::new(async move {
1046             let frame = handle.lock().unwrap().take();
1047             if let Some(frame) = frame {
1048                 // Ensure that the handle has been invalidated.
1049                 assert!(!frame.is_valid(&mut caller));
1050                 // Ensure that attempts to fetch data from the frame
1051                 // fail with a clean `Err`, not a panic or crash.
1052                 let result = frame.wasm_function_index_and_pc(&mut caller);
1053                 assert!(result.is_err());
1054                 // Ensure that we can get a new frame handle and use it.
1055                 let frame = caller.debug_exit_frames().next().unwrap();
1056                 assert_eq!(frame.num_locals(&mut caller)?, 2);
1057                 assert_eq!(frame.local(&mut caller, 0)?.unwrap_i32(), 1);
1058                 assert_eq!(frame.local(&mut caller, 1)?.unwrap_i32(), 2);
1059             } else {
1060                 let frame = caller.debug_exit_frames().next().unwrap();
1061                 assert_eq!(frame.num_locals(&mut caller)?, 2);
1062                 assert_eq!(frame.local(&mut caller, 0)?.unwrap_i32(), 3);
1063                 assert_eq!(frame.local(&mut caller, 1)?.unwrap_i32(), 4);
1064                 *handle.lock().unwrap() = Some(frame);
1065             }
1066             Ok(())
1067         })
1068     });
1069 
1070     let instance = Instance::new_async(&mut store, &module, &[Extern::Func(hostfunc)]).await?;
1071     let main = instance.get_func(&mut store, "main").unwrap();
1072     main.call_async(&mut store, &[], &mut []).await?;
1073 
1074     Ok(())
1075 }
1076 
1077 #[tokio::test]
1078 #[cfg_attr(miri, ignore)]
1079 async fn invalidated_frame_handles_in_dropped_future() -> wasmtime::Result<()> {
1080     let (module, mut store) = get_module_and_store(
1081         |_config| {},
1082         r#"
1083     (module
1084       (import "" "" (func))
1085       (func (export "main")
1086         call 0))
1087         "#,
1088     )?;
1089 
1090     let handle: Arc<Mutex<Option<FrameHandle>>> = Arc::new(Mutex::new(None));
1091     let handle_clone = handle.clone();
1092 
1093     let hostfunc = Func::wrap_async(&mut store, move |mut caller, _args: ()| {
1094         let handle_clone = handle_clone.clone();
1095         Box::new(async move {
1096             let frame = caller.debug_exit_frames().next().unwrap();
1097             *handle_clone.lock().unwrap() = Some(frame);
1098             tokio::task::yield_now().await;
1099         })
1100     });
1101 
1102     let instance = Instance::new_async(&mut store, &module, &[Extern::Func(hostfunc)]).await?;
1103     let main = instance.get_func(&mut store, "main").unwrap();
1104     let future = Box::pin(main.call_async(&mut store, &[], &mut []));
1105 
1106     // Poll once, then drop.
1107     let poll_once = PollOnce::new(future);
1108     let future = poll_once.await;
1109 
1110     drop(future);
1111 
1112     // The frame handle should now be invalid.
1113     let mut handle = handle.lock().unwrap();
1114     let frame = handle.take().unwrap();
1115     assert!(!frame.is_valid(&mut store));
1116 
1117     Ok(())
1118 }
1119 
1120 #[test]
1121 #[cfg_attr(miri, ignore)]
1122 fn module_bytecode() -> wasmtime::Result<()> {
1123     let wasm = wat::parse_str(
1124         r#"
1125         (module
1126             (func (export "add") (param i32 i32) (result i32)
1127                 local.get 0
1128                 local.get 1
1129                 i32.add
1130             )
1131         )
1132         "#,
1133     )
1134     .unwrap();
1135 
1136     let mut config = Config::default();
1137     config.guest_debug(true);
1138     let engine = Engine::new(&config)?;
1139     let module = Module::new(&engine, &wasm)?;
1140 
1141     assert_eq!(module.debug_bytecode(), Some(&wasm[..]));
1142 
1143     Ok(())
1144 }
1145 
1146 #[test]
1147 #[cfg_attr(miri, ignore)]
1148 fn module_bytecode_absent_without_debug() -> wasmtime::Result<()> {
1149     let wasm = wat::parse_str("(module)").unwrap();
1150 
1151     let mut config = Config::default();
1152     config.guest_debug(false);
1153     let engine = Engine::new(&config)?;
1154     let module = Module::new(&engine, &wasm)?;
1155 
1156     assert_eq!(module.debug_bytecode(), None);
1157 
1158     Ok(())
1159 }
1160 
1161 #[test]
1162 #[cfg_attr(miri, ignore)]
1163 fn component_bytecode() -> wasmtime::Result<()> {
1164     use wasmtime::component::{Component, Linker};
1165 
1166     // Build the bytecode for each core module by compiling them
1167     // standalone.
1168     let m1_body = r#"(func (export "f1") (result i32) i32.const 42)"#;
1169     let m2_body = r#"(func (export "f2") (result i32) i32.const 99)"#;
1170     let m1_wasm = wat::parse_str(&format!("(module $m1 {m1_body})")).unwrap();
1171     let m2_wasm = wat::parse_str(&format!("(module $m2 {m2_body})")).unwrap();
1172 
1173     // Build a component that embeds both core modules inline.
1174     let component_wasm = wat::parse_str(&format!(
1175         r#"(component
1176                (core module $m1 {m1_body})
1177                (core instance $i1 (instantiate (module $m1)))
1178                (core module $m2 {m2_body})
1179                (core instance $i2 (instantiate (module $m2))))
1180         "#,
1181     ))
1182     .unwrap();
1183 
1184     let mut config = Config::default();
1185     config.guest_debug(true);
1186     let engine = Engine::new(&config)?;
1187 
1188     let component = Component::new(&engine, &component_wasm)?;
1189     let linker: Linker<()> = Linker::new(&engine);
1190     let mut store = Store::new(&engine, ());
1191     linker.instantiate(&mut store, &component)?;
1192 
1193     let modules = store.debug_all_modules();
1194     assert_eq!(modules.len(), 2);
1195 
1196     // Modules should be registered in offset order. The API doesn't
1197     // guarantee this, but this suffices for a test.
1198     assert_eq!(modules[0].debug_bytecode().unwrap(), &m1_wasm[..]);
1199     assert_eq!(modules[1].debug_bytecode().unwrap(), &m2_wasm[..]);
1200 
1201     Ok(())
1202 }
1203 
1204 #[test]
1205 #[cfg_attr(miri, ignore)]
1206 fn debug_ids() -> wasmtime::Result<()> {
1207     let mut config = Config::default();
1208     config.guest_debug(true);
1209     config.wasm_exceptions(true);
1210     let engine = Engine::new(&config)?;
1211     let mut store = Store::new(&engine, ());
1212     let module1 = Module::new(
1213         &engine,
1214         r#"
1215         (module
1216           (memory 1 1)
1217           (memory 1 1)
1218           (global (mut i32) (i32.const 0))
1219           (global (mut i32) (i32.const 1))
1220           (table 1 1 funcref)
1221           (table 1 1 funcref)
1222           (tag (param i32))
1223           (tag (param i64)))
1224         "#,
1225     )?;
1226 
1227     let module2 = Module::new(
1228         &engine,
1229         r#"
1230         (module
1231           (memory (export "m") 1 1))
1232         "#,
1233     )?;
1234 
1235     let instance1 = Instance::new(&mut store, &module1, &[])?;
1236     let instance2 = Instance::new(&mut store, &module2, &[])?;
1237     let instance3 = Instance::new(&mut store, &module1, &[])?;
1238 
1239     assert_ne!(
1240         module1.debug_index_in_engine(),
1241         module2.debug_index_in_engine()
1242     );
1243     assert_ne!(
1244         instance1.debug_index_in_store(),
1245         instance2.debug_index_in_store()
1246     );
1247     assert_ne!(
1248         instance1
1249             .debug_memory(&mut store, 0)
1250             .unwrap()
1251             .debug_index_in_store(),
1252         instance1
1253             .debug_memory(&mut store, 1)
1254             .unwrap()
1255             .debug_index_in_store()
1256     );
1257     assert_ne!(
1258         instance1
1259             .debug_memory(&mut store, 0)
1260             .unwrap()
1261             .debug_index_in_store(),
1262         instance2
1263             .debug_memory(&mut store, 0)
1264             .unwrap()
1265             .debug_index_in_store()
1266     );
1267     assert_ne!(
1268         instance1
1269             .debug_memory(&mut store, 0)
1270             .unwrap()
1271             .debug_index_in_store(),
1272         instance3
1273             .debug_memory(&mut store, 0)
1274             .unwrap()
1275             .debug_index_in_store()
1276     );
1277     assert_ne!(
1278         instance1
1279             .debug_global(&mut store, 0)
1280             .unwrap()
1281             .debug_index_in_store(),
1282         instance3
1283             .debug_global(&mut store, 0)
1284             .unwrap()
1285             .debug_index_in_store()
1286     );
1287     assert_ne!(
1288         instance1
1289             .debug_table(&mut store, 0)
1290             .unwrap()
1291             .debug_index_in_store(),
1292         instance3
1293             .debug_table(&mut store, 0)
1294             .unwrap()
1295             .debug_index_in_store()
1296     );
1297     assert_ne!(
1298         instance1
1299             .debug_tag(&mut store, 0)
1300             .unwrap()
1301             .debug_index_in_store(),
1302         instance3
1303             .debug_tag(&mut store, 0)
1304             .unwrap()
1305             .debug_index_in_store()
1306     );
1307 
1308     let m_via_export = instance2
1309         .get_export(&mut store, "m")
1310         .unwrap()
1311         .into_memory()
1312         .unwrap();
1313     let m_via_introspection = instance2.debug_memory(&mut store, 0).unwrap();
1314     assert_eq!(
1315         m_via_export.debug_index_in_store(),
1316         m_via_introspection.debug_index_in_store()
1317     );
1318 
1319     Ok(())
1320 }
1321 
1322 #[tokio::test]
1323 #[cfg_attr(miri, ignore)]
1324 async fn single_step_before_instantiation() -> wasmtime::Result<()> {
1325     let _ = env_logger::try_init();
1326 
1327     let mut config = Config::default();
1328     config.guest_debug(true);
1329     let engine = Engine::new(&config)?;
1330     let module = Module::new(
1331         &engine,
1332         r#"
1333     (module
1334       (func (export "main") (param i32 i32) (result i32)
1335         local.get 0
1336         local.get 1
1337         i32.add))
1338     "#,
1339     )?;
1340     let mut store = Store::new(&engine, ());
1341 
1342     // Enable single-stepping *before* instantiation. The module has not
1343     // been registered with this store yet.
1344     store.edit_breakpoints().unwrap().single_step(true).unwrap();
1345     assert!(store.is_single_step());
1346 
1347     #[derive(Clone)]
1348     struct CountingHandler(Arc<AtomicUsize>);
1349     impl DebugHandler for CountingHandler {
1350         type Data = ();
1351         async fn handle(&self, _store: StoreContextMut<'_, ()>, event: DebugEvent<'_>) {
1352             match event {
1353                 DebugEvent::Breakpoint => {
1354                     self.0.fetch_add(1, Ordering::Relaxed);
1355                 }
1356                 _ => {}
1357             }
1358         }
1359     }
1360 
1361     let counter = Arc::new(AtomicUsize::new(0));
1362     store.set_debug_handler(CountingHandler(counter.clone()));
1363 
1364     let instance = Instance::new_async(&mut store, &module, &[]).await?;
1365     let func = instance.get_func(&mut store, "main").unwrap();
1366     let mut results = [Val::I32(0)];
1367     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
1368         .await?;
1369     assert_eq!(results[0].unwrap_i32(), 3);
1370 
1371     assert_eq!(counter.load(Ordering::Relaxed), 4);
1372 
1373     Ok(())
1374 }
1375 
1376 #[tokio::test]
1377 #[cfg_attr(miri, ignore)]
1378 async fn early_epoch_yield_still_has_vmctx() -> wasmtime::Result<()> {
1379     let _ = env_logger::try_init();
1380 
1381     let mut config = Config::default();
1382     config.guest_debug(true);
1383     config.epoch_interruption(true);
1384     let engine = Engine::new(&config)?;
1385     let module = Module::new(
1386         &engine,
1387         r#"
1388     (module
1389       (func (export "main") (param i32 i32) (result i32)
1390         local.get 0
1391         local.get 1
1392         i32.add))
1393     "#,
1394     )?;
1395     let mut store = Store::new(&engine, ());
1396     store.set_epoch_deadline(1);
1397     store.epoch_deadline_async_yield_and_update(1);
1398     engine.increment_epoch();
1399 
1400     #[derive(Clone)]
1401     struct H;
1402     impl DebugHandler for H {
1403         type Data = ();
1404         async fn handle(&self, mut store: StoreContextMut<'_, ()>, _event: DebugEvent<'_>) {
1405             // Ensure we can access the instance (which accesses the
1406             // vmctx slot in the frame's debug info).
1407             let frame = store.debug_exit_frames().next().unwrap();
1408             let _instance = frame.instance(&mut store);
1409         }
1410     }
1411 
1412     store.set_debug_handler(H);
1413 
1414     let instance = Instance::new_async(&mut store, &module, &[]).await?;
1415     let func = instance.get_func(&mut store, "main").unwrap();
1416     let mut results = [Val::I32(0)];
1417     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
1418         .await?;
1419     assert_eq!(results[0].unwrap_i32(), 3);
1420 
1421     Ok(())
1422 }
1423