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