xref: /wasmtime-44.0.1/tests/all/debug.rs (revision c7d25dfd)
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                     67
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                     57
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             58
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             58
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") (result i32)
698         i32.const 0
699         i32.const 0
700         i32.div_u
701         drop
702         i32.const 42))
703     "#,
704     )?;
705 
706     debug_event_checker!(
707         D, store,
708         { 0 ;
709           wasmtime::DebugEvent::Trap(wasmtime_environ::Trap::IntegerDivisionByZero) => {
710               let frame = store.debug_exit_frames().next().unwrap();
711               let (_func, pc) = frame.wasm_function_index_and_pc(&mut store).unwrap().unwrap();
712               assert_eq!(pc, 0x26);
713           }
714         }
715     );
716 
717     let (handler, counter) = D::new_and_counter();
718     store.set_debug_handler(handler);
719 
720     let instance = Instance::new_async(&mut store, &module, &[]).await?;
721     let func = instance.get_func(&mut store, "main").unwrap();
722     let mut results = [Val::I32(0)];
723     let result = func.call_async(&mut store, &[], &mut results).await;
724     assert!(result.is_err()); // Uncaught trap.
725     assert_eq!(counter.load(Ordering::Relaxed), 1);
726 
727     Ok(())
728 }
729 
730 #[tokio::test]
731 #[cfg_attr(miri, ignore)]
732 async fn hostcall_error_events() -> wasmtime::Result<()> {
733     let _ = env_logger::try_init();
734 
735     let (module, mut store) = get_module_and_store(
736         |config| {
737             config.wasm_exceptions(true);
738         },
739         r#"
740     (module
741       (import "" "do_a_trap" (func))
742       (func (export "main")
743         call 0))
744     "#,
745     )?;
746 
747     debug_event_checker!(
748         D, store,
749         { 0 ;
750           wasmtime::DebugEvent::HostcallError(e) => {
751               assert!(format!("{e:?}").contains("secret error message"));
752           }
753         }
754     );
755 
756     let (handler, counter) = D::new_and_counter();
757     store.set_debug_handler(handler);
758 
759     let do_a_trap = Func::wrap(
760         &mut store,
761         |_caller: Caller<'_, ()>| -> wasmtime::Result<()> {
762             Err(wasmtime::format_err!("secret error message"))
763         },
764     );
765     let instance = Instance::new_async(&mut store, &module, &[Extern::Func(do_a_trap)]).await?;
766     let func = instance.get_func(&mut store, "main").unwrap();
767     let mut results = [];
768     let result = func.call_async(&mut store, &[], &mut results).await;
769     assert!(result.is_err()); // Uncaught trap.
770     assert_eq!(counter.load(Ordering::Relaxed), 1);
771     Ok(())
772 }
773 
774 #[tokio::test]
775 #[cfg_attr(miri, ignore)]
776 async fn breakpoint_events() -> wasmtime::Result<()> {
777     let _ = env_logger::try_init();
778 
779     let (module, mut store) = get_module_and_store(
780         |config| {
781             config.wasm_exceptions(true);
782         },
783         r#"
784     (module
785       (func (export "main") (param i32 i32) (result i32)
786         local.get 0
787         local.get 1
788         i32.add))
789     "#,
790     )?;
791 
792     debug_event_checker!(
793         D, store,
794         { 0 ;
795           wasmtime::DebugEvent::Breakpoint => {
796               let stack = store.debug_exit_frames().next().unwrap();
797               assert_eq!(stack.num_locals(&mut store).unwrap(), 2);
798               assert_eq!(stack.local(&mut store, 0).unwrap().unwrap_i32(), 1);
799               assert_eq!(stack.local(&mut store, 1).unwrap().unwrap_i32(), 2);
800               let (func, pc) = stack.wasm_function_index_and_pc(&mut store).unwrap().unwrap();
801               assert_eq!(func.as_u32(), 0);
802               assert_eq!(pc, 0x28);
803               let stack = stack.parent(&mut store).unwrap();
804               assert!(stack.is_none());
805           }
806         }
807     );
808 
809     let (handler, counter) = D::new_and_counter();
810     store.set_debug_handler(handler);
811     store
812         .edit_breakpoints()
813         .unwrap()
814         .add_breakpoint(&module, 0x28)?;
815 
816     let instance = Instance::new_async(&mut store, &module, &[]).await?;
817     let func = instance.get_func(&mut store, "main").unwrap();
818     let mut results = [Val::I32(0)];
819     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
820         .await?;
821     assert_eq!(counter.load(Ordering::Relaxed), 1);
822     assert_eq!(results[0].unwrap_i32(), 3);
823 
824     let breakpoints = store.breakpoints().unwrap().collect::<Vec<_>>();
825     assert_eq!(breakpoints.len(), 1);
826     assert!(Module::same(&breakpoints[0].module, &module));
827     assert_eq!(breakpoints[0].pc, 0x28);
828 
829     store
830         .edit_breakpoints()
831         .unwrap()
832         .remove_breakpoint(&module, 0x28)?;
833     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
834         .await?;
835     assert_eq!(counter.load(Ordering::Relaxed), 1); // Should not have incremented from above.
836     assert_eq!(results[0].unwrap_i32(), 3);
837 
838     // Enable single-step mode (on top of the breakpoint already enabled).
839     assert!(!store.is_single_step());
840     store.edit_breakpoints().unwrap().single_step(true).unwrap();
841     assert!(store.is_single_step());
842 
843     debug_event_checker!(
844         D2, store,
845         { 0 ;
846           wasmtime::DebugEvent::Breakpoint => {
847               let stack = store.debug_exit_frames().next().unwrap();
848               let (_, pc) = stack.wasm_function_index_and_pc(&mut store).unwrap().unwrap();
849               assert_eq!(pc, 0x24);
850           }
851         },
852         {
853           1 ;
854           wasmtime::DebugEvent::Breakpoint => {
855               let stack = store.debug_exit_frames().next().unwrap();
856               let (_, pc) = stack.wasm_function_index_and_pc(&mut store).unwrap().unwrap();
857               assert_eq!(pc, 0x26);
858           }
859         },
860         {
861           2 ;
862           wasmtime::DebugEvent::Breakpoint => {
863               let stack = store.debug_exit_frames().next().unwrap();
864               let (_, pc) = stack.wasm_function_index_and_pc(&mut store).unwrap().unwrap();
865               assert_eq!(pc, 0x28);
866           }
867         },
868         {
869           3 ;
870           wasmtime::DebugEvent::Breakpoint => {
871               let stack = store.debug_exit_frames().next().unwrap();
872               let (_, pc) = stack.wasm_function_index_and_pc(&mut store).unwrap().unwrap();
873               assert_eq!(pc, 0x29);
874           }
875         }
876     );
877 
878     let (handler, counter) = D2::new_and_counter();
879     store.set_debug_handler(handler);
880 
881     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
882         .await?;
883     assert_eq!(counter.load(Ordering::Relaxed), 4);
884 
885     // Re-enable individual breakpoint.
886     store
887         .edit_breakpoints()
888         .unwrap()
889         .add_breakpoint(&module, 0x28)
890         .unwrap();
891 
892     // Now disable single-stepping. The single breakpoint set above
893     // should still remain.
894     store
895         .edit_breakpoints()
896         .unwrap()
897         .single_step(false)
898         .unwrap();
899 
900     let (handler, counter) = D::new_and_counter();
901     store.set_debug_handler(handler);
902 
903     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
904         .await?;
905     assert_eq!(counter.load(Ordering::Relaxed), 1);
906 
907     Ok(())
908 }
909 
910 #[tokio::test]
911 #[cfg_attr(miri, ignore)]
912 async fn breakpoints_in_inlined_code() -> wasmtime::Result<()> {
913     let _ = env_logger::try_init();
914 
915     let (module, mut store) = get_module_and_store(
916         |config| {
917             config.wasm_exceptions(true);
918             config.compiler_inlining(true);
919             unsafe {
920                 config.cranelift_flag_set("wasmtime_inlining_intra_module", "true");
921             }
922         },
923         r#"
924     (module
925       (func $f (export "f") (param i32 i32) (result i32)
926         local.get 0
927         local.get 1
928         i32.add)
929 
930       (func (export "main") (param i32 i32) (result i32)
931         local.get 0
932         local.get 1
933         call $f))
934     "#,
935     )?;
936 
937     debug_event_checker!(
938         D, store,
939         { 0 ;
940           wasmtime::DebugEvent::Breakpoint => {}
941         },
942         { 1 ;
943           wasmtime::DebugEvent::Breakpoint => {}
944         }
945     );
946 
947     let (handler, counter) = D::new_and_counter();
948     store.set_debug_handler(handler);
949     store
950         .edit_breakpoints()
951         .unwrap()
952         .add_breakpoint(&module, 0x2d)?; // `i32.add` in `$f`.
953 
954     let instance = Instance::new_async(&mut store, &module, &[]).await?;
955     let func_main = instance.get_func(&mut store, "main").unwrap();
956     let func_f = instance.get_func(&mut store, "f").unwrap();
957     let mut results = [Val::I32(0)];
958     // Breakpoint in `$f` should have been hit in `main` even if it
959     // was inlined.
960     func_main
961         .call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
962         .await?;
963     assert_eq!(counter.load(Ordering::Relaxed), 1);
964     assert_eq!(results[0].unwrap_i32(), 3);
965 
966     // Breakpoint in `$f` should be hit when called directly, too.
967     func_f
968         .call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
969         .await?;
970     assert_eq!(counter.load(Ordering::Relaxed), 2);
971     assert_eq!(results[0].unwrap_i32(), 3);
972 
973     Ok(())
974 }
975 
976 #[tokio::test]
977 #[cfg_attr(miri, ignore)]
978 async fn epoch_events() -> wasmtime::Result<()> {
979     let _ = env_logger::try_init();
980 
981     let (module, mut store) = get_module_and_store(
982         |config| {
983             config.epoch_interruption(true);
984         },
985         r#"
986     (module
987       (func $f (export "f") (param i32 i32) (result i32)
988         local.get 0
989         local.get 1
990         i32.add))
991     "#,
992     )?;
993 
994     debug_event_checker!(
995         D, store,
996         { 0 ;
997           wasmtime::DebugEvent::EpochYield => {}
998         }
999     );
1000 
1001     let (handler, counter) = D::new_and_counter();
1002     store.set_debug_handler(handler);
1003 
1004     store.set_epoch_deadline(1);
1005     store.epoch_deadline_async_yield_and_update(1);
1006     store.engine().increment_epoch();
1007 
1008     let instance = Instance::new_async(&mut store, &module, &[]).await?;
1009     let func_f = instance.get_func(&mut store, "f").unwrap();
1010     let mut results = [Val::I32(0)];
1011     func_f
1012         .call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
1013         .await?;
1014     assert_eq!(counter.load(Ordering::Relaxed), 1);
1015     assert_eq!(results[0].unwrap_i32(), 3);
1016 
1017     Ok(())
1018 }
1019 
1020 #[tokio::test]
1021 #[cfg_attr(miri, ignore)]
1022 async fn invalidated_frame_handles() -> wasmtime::Result<()> {
1023     let (module, mut store) = get_module_and_store(
1024         |_config| {},
1025         r#"
1026     (module
1027       (import "" "" (func))
1028       (func (export "main")
1029         (local i32 i32)
1030         i32.const 1
1031         local.set 0
1032         i32.const 2
1033         local.set 1
1034         call 2
1035         call 0)
1036       (func
1037         (local i32 i32)
1038         i32.const 3
1039         local.set 0
1040         i32.const 4
1041         local.set 1
1042         call 0))
1043         "#,
1044     )?;
1045 
1046     let handle: Arc<Mutex<Option<FrameHandle>>> = Arc::new(Mutex::new(None));
1047 
1048     let hostfunc = Func::wrap_async(&mut store, move |mut caller, _args: ()| {
1049         let handle = handle.clone();
1050         Box::new(async move {
1051             let frame = handle.lock().unwrap().take();
1052             if let Some(frame) = frame {
1053                 // Ensure that the handle has been invalidated.
1054                 assert!(!frame.is_valid(&mut caller));
1055                 // Ensure that attempts to fetch data from the frame
1056                 // fail with a clean `Err`, not a panic or crash.
1057                 let result = frame.wasm_function_index_and_pc(&mut caller);
1058                 assert!(result.is_err());
1059                 // Ensure that we can get a new frame handle and use it.
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(), 1);
1063                 assert_eq!(frame.local(&mut caller, 1)?.unwrap_i32(), 2);
1064             } else {
1065                 let frame = caller.debug_exit_frames().next().unwrap();
1066                 assert_eq!(frame.num_locals(&mut caller)?, 2);
1067                 assert_eq!(frame.local(&mut caller, 0)?.unwrap_i32(), 3);
1068                 assert_eq!(frame.local(&mut caller, 1)?.unwrap_i32(), 4);
1069                 *handle.lock().unwrap() = Some(frame);
1070             }
1071             Ok(())
1072         })
1073     });
1074 
1075     let instance = Instance::new_async(&mut store, &module, &[Extern::Func(hostfunc)]).await?;
1076     let main = instance.get_func(&mut store, "main").unwrap();
1077     main.call_async(&mut store, &[], &mut []).await?;
1078 
1079     Ok(())
1080 }
1081 
1082 #[tokio::test]
1083 #[cfg_attr(miri, ignore)]
1084 async fn invalidated_frame_handles_in_dropped_future() -> wasmtime::Result<()> {
1085     let (module, mut store) = get_module_and_store(
1086         |_config| {},
1087         r#"
1088     (module
1089       (import "" "" (func))
1090       (func (export "main")
1091         call 0))
1092         "#,
1093     )?;
1094 
1095     let handle: Arc<Mutex<Option<FrameHandle>>> = Arc::new(Mutex::new(None));
1096     let handle_clone = handle.clone();
1097 
1098     let hostfunc = Func::wrap_async(&mut store, move |mut caller, _args: ()| {
1099         let handle_clone = handle_clone.clone();
1100         Box::new(async move {
1101             let frame = caller.debug_exit_frames().next().unwrap();
1102             *handle_clone.lock().unwrap() = Some(frame);
1103             tokio::task::yield_now().await;
1104         })
1105     });
1106 
1107     let instance = Instance::new_async(&mut store, &module, &[Extern::Func(hostfunc)]).await?;
1108     let main = instance.get_func(&mut store, "main").unwrap();
1109     let future = Box::pin(main.call_async(&mut store, &[], &mut []));
1110 
1111     // Poll once, then drop.
1112     let poll_once = PollOnce::new(future);
1113     let future = poll_once.await;
1114 
1115     drop(future);
1116 
1117     // The frame handle should now be invalid.
1118     let mut handle = handle.lock().unwrap();
1119     let frame = handle.take().unwrap();
1120     assert!(!frame.is_valid(&mut store));
1121 
1122     Ok(())
1123 }
1124 
1125 #[test]
1126 #[cfg_attr(miri, ignore)]
1127 fn module_bytecode() -> wasmtime::Result<()> {
1128     let wasm = wat::parse_str(
1129         r#"
1130         (module
1131             (func (export "add") (param i32 i32) (result i32)
1132                 local.get 0
1133                 local.get 1
1134                 i32.add
1135             )
1136         )
1137         "#,
1138     )
1139     .unwrap();
1140 
1141     let mut config = Config::default();
1142     config.guest_debug(true);
1143     let engine = Engine::new(&config)?;
1144     let module = Module::new(&engine, &wasm)?;
1145 
1146     assert_eq!(module.debug_bytecode(), Some(&wasm[..]));
1147 
1148     Ok(())
1149 }
1150 
1151 #[test]
1152 #[cfg_attr(miri, ignore)]
1153 fn module_bytecode_absent_without_debug() -> wasmtime::Result<()> {
1154     let wasm = wat::parse_str("(module)").unwrap();
1155 
1156     let mut config = Config::default();
1157     config.guest_debug(false);
1158     let engine = Engine::new(&config)?;
1159     let module = Module::new(&engine, &wasm)?;
1160 
1161     assert_eq!(module.debug_bytecode(), None);
1162 
1163     Ok(())
1164 }
1165 
1166 #[test]
1167 #[cfg_attr(miri, ignore)]
1168 fn component_bytecode() -> wasmtime::Result<()> {
1169     use wasmtime::component::{Component, Linker};
1170 
1171     // Build the bytecode for each core module by compiling them
1172     // standalone.
1173     let m1_body = r#"(func (export "f1") (result i32) i32.const 42)"#;
1174     let m2_body = r#"(func (export "f2") (result i32) i32.const 99)"#;
1175     let m1_wasm = wat::parse_str(&format!("(module $m1 {m1_body})")).unwrap();
1176     let m2_wasm = wat::parse_str(&format!("(module $m2 {m2_body})")).unwrap();
1177 
1178     // Build a component that embeds both core modules inline.
1179     let component_wasm = wat::parse_str(&format!(
1180         r#"(component
1181                (core module $m1 {m1_body})
1182                (core instance $i1 (instantiate (module $m1)))
1183                (core module $m2 {m2_body})
1184                (core instance $i2 (instantiate (module $m2))))
1185         "#,
1186     ))
1187     .unwrap();
1188 
1189     let mut config = Config::default();
1190     config.guest_debug(true);
1191     let engine = Engine::new(&config)?;
1192 
1193     let component = Component::new(&engine, &component_wasm)?;
1194     let linker: Linker<()> = Linker::new(&engine);
1195     let mut store = Store::new(&engine, ());
1196     linker.instantiate(&mut store, &component)?;
1197 
1198     let modules = store.debug_all_modules();
1199     assert_eq!(modules.len(), 2);
1200 
1201     // Modules should be registered in offset order. The API doesn't
1202     // guarantee this, but this suffices for a test.
1203     assert_eq!(modules[0].debug_bytecode().unwrap(), &m1_wasm[..]);
1204     assert_eq!(modules[1].debug_bytecode().unwrap(), &m2_wasm[..]);
1205 
1206     Ok(())
1207 }
1208 
1209 #[test]
1210 #[cfg_attr(miri, ignore)]
1211 fn debug_ids() -> wasmtime::Result<()> {
1212     let mut config = Config::default();
1213     config.guest_debug(true);
1214     config.wasm_exceptions(true);
1215     let engine = Engine::new(&config)?;
1216     let mut store = Store::new(&engine, ());
1217     let module1 = Module::new(
1218         &engine,
1219         r#"
1220         (module
1221           (memory 1 1)
1222           (memory 1 1)
1223           (global (mut i32) (i32.const 0))
1224           (global (mut i32) (i32.const 1))
1225           (table 1 1 funcref)
1226           (table 1 1 funcref)
1227           (tag (param i32))
1228           (tag (param i64)))
1229         "#,
1230     )?;
1231 
1232     let module2 = Module::new(
1233         &engine,
1234         r#"
1235         (module
1236           (memory (export "m") 1 1))
1237         "#,
1238     )?;
1239 
1240     let instance1 = Instance::new(&mut store, &module1, &[])?;
1241     let instance2 = Instance::new(&mut store, &module2, &[])?;
1242     let instance3 = Instance::new(&mut store, &module1, &[])?;
1243 
1244     assert_ne!(
1245         module1.debug_index_in_engine(),
1246         module2.debug_index_in_engine()
1247     );
1248     assert_ne!(
1249         instance1.debug_index_in_store(),
1250         instance2.debug_index_in_store()
1251     );
1252     assert_ne!(
1253         instance1
1254             .debug_memory(&mut store, 0)
1255             .unwrap()
1256             .debug_index_in_store(),
1257         instance1
1258             .debug_memory(&mut store, 1)
1259             .unwrap()
1260             .debug_index_in_store()
1261     );
1262     assert_ne!(
1263         instance1
1264             .debug_memory(&mut store, 0)
1265             .unwrap()
1266             .debug_index_in_store(),
1267         instance2
1268             .debug_memory(&mut store, 0)
1269             .unwrap()
1270             .debug_index_in_store()
1271     );
1272     assert_ne!(
1273         instance1
1274             .debug_memory(&mut store, 0)
1275             .unwrap()
1276             .debug_index_in_store(),
1277         instance3
1278             .debug_memory(&mut store, 0)
1279             .unwrap()
1280             .debug_index_in_store()
1281     );
1282     assert_ne!(
1283         instance1
1284             .debug_global(&mut store, 0)
1285             .unwrap()
1286             .debug_index_in_store(),
1287         instance3
1288             .debug_global(&mut store, 0)
1289             .unwrap()
1290             .debug_index_in_store()
1291     );
1292     assert_ne!(
1293         instance1
1294             .debug_table(&mut store, 0)
1295             .unwrap()
1296             .debug_index_in_store(),
1297         instance3
1298             .debug_table(&mut store, 0)
1299             .unwrap()
1300             .debug_index_in_store()
1301     );
1302     assert_ne!(
1303         instance1
1304             .debug_tag(&mut store, 0)
1305             .unwrap()
1306             .debug_index_in_store(),
1307         instance3
1308             .debug_tag(&mut store, 0)
1309             .unwrap()
1310             .debug_index_in_store()
1311     );
1312 
1313     let m_via_export = instance2
1314         .get_export(&mut store, "m")
1315         .unwrap()
1316         .into_memory()
1317         .unwrap();
1318     let m_via_introspection = instance2.debug_memory(&mut store, 0).unwrap();
1319     assert_eq!(
1320         m_via_export.debug_index_in_store(),
1321         m_via_introspection.debug_index_in_store()
1322     );
1323 
1324     Ok(())
1325 }
1326 
1327 #[tokio::test]
1328 #[cfg_attr(miri, ignore)]
1329 async fn single_step_before_instantiation() -> wasmtime::Result<()> {
1330     let _ = env_logger::try_init();
1331 
1332     let mut config = Config::default();
1333     config.guest_debug(true);
1334     let engine = Engine::new(&config)?;
1335     let module = Module::new(
1336         &engine,
1337         r#"
1338     (module
1339       (func (export "main") (param i32 i32) (result i32)
1340         local.get 0
1341         local.get 1
1342         i32.add))
1343     "#,
1344     )?;
1345     let mut store = Store::new(&engine, ());
1346 
1347     // Enable single-stepping *before* instantiation. The module has not
1348     // been registered with this store yet.
1349     store.edit_breakpoints().unwrap().single_step(true).unwrap();
1350     assert!(store.is_single_step());
1351 
1352     #[derive(Clone)]
1353     struct CountingHandler(Arc<AtomicUsize>);
1354     impl DebugHandler for CountingHandler {
1355         type Data = ();
1356         async fn handle(&self, _store: StoreContextMut<'_, ()>, event: DebugEvent<'_>) {
1357             match event {
1358                 DebugEvent::Breakpoint => {
1359                     self.0.fetch_add(1, Ordering::Relaxed);
1360                 }
1361                 _ => {}
1362             }
1363         }
1364     }
1365 
1366     let counter = Arc::new(AtomicUsize::new(0));
1367     store.set_debug_handler(CountingHandler(counter.clone()));
1368 
1369     let instance = Instance::new_async(&mut store, &module, &[]).await?;
1370     let func = instance.get_func(&mut store, "main").unwrap();
1371     let mut results = [Val::I32(0)];
1372     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
1373         .await?;
1374     assert_eq!(results[0].unwrap_i32(), 3);
1375 
1376     assert_eq!(counter.load(Ordering::Relaxed), 4);
1377 
1378     Ok(())
1379 }
1380 
1381 #[tokio::test]
1382 #[cfg_attr(miri, ignore)]
1383 async fn early_epoch_yield_still_has_vmctx() -> wasmtime::Result<()> {
1384     let _ = env_logger::try_init();
1385 
1386     let mut config = Config::default();
1387     config.guest_debug(true);
1388     config.epoch_interruption(true);
1389     let engine = Engine::new(&config)?;
1390     let module = Module::new(
1391         &engine,
1392         r#"
1393     (module
1394       (func (export "main") (param i32 i32) (result i32)
1395         local.get 0
1396         local.get 1
1397         i32.add))
1398     "#,
1399     )?;
1400     let mut store = Store::new(&engine, ());
1401     store.set_epoch_deadline(1);
1402     store.epoch_deadline_async_yield_and_update(1);
1403     engine.increment_epoch();
1404 
1405     #[derive(Clone)]
1406     struct H;
1407     impl DebugHandler for H {
1408         type Data = ();
1409         async fn handle(&self, mut store: StoreContextMut<'_, ()>, _event: DebugEvent<'_>) {
1410             // Ensure we can access the instance (which accesses the
1411             // vmctx slot in the frame's debug info).
1412             let frame = store.debug_exit_frames().next().unwrap();
1413             let _instance = frame.instance(&mut store);
1414         }
1415     }
1416 
1417     store.set_debug_handler(H);
1418 
1419     let instance = Instance::new_async(&mut store, &module, &[]).await?;
1420     let func = instance.get_func(&mut store, "main").unwrap();
1421     let mut results = [Val::I32(0)];
1422     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
1423         .await?;
1424     assert_eq!(results[0].unwrap_i32(), 3);
1425 
1426     Ok(())
1427 }
1428 
1429 #[tokio::test]
1430 #[cfg_attr(miri, ignore)]
1431 async fn breakpoint_slips_to_first_opcode() -> wasmtime::Result<()> {
1432     let _ = env_logger::try_init();
1433 
1434     // Breakpoints set at the function body start (which includes the
1435     // local declarations and precedes the first opcode) should be
1436     // "slipped" forward to the first opcode. This matches how LLDB
1437     // sets breakpoints using DWARF `DW_AT_low_pc`.
1438     //
1439     // For the WAT below, `wasm-objdump -d` shows:
1440     //
1441     // ```
1442     // 000023 func[0] <main>:
1443     //  000024: 20 00                      | local.get 0
1444     //  000026: 20 01                      | local.get 1
1445     //  000028: 6a                         | i32.add
1446     //  000029: 0b                         | end
1447     // ```
1448     //
1449     // 0x23 is the function body start (locals count byte), while 0x24
1450     // is the first opcode. Setting a breakpoint at 0x23 should slip
1451     // to 0x24.
1452     let (module, mut store) = get_module_and_store(
1453         |_config| {},
1454         r#"
1455     (module
1456       (func (export "main") (param i32 i32) (result i32)
1457         local.get 0
1458         local.get 1
1459         i32.add))
1460     "#,
1461     )?;
1462 
1463     debug_event_checker!(
1464         D, store,
1465         { 0 ;
1466           wasmtime::DebugEvent::Breakpoint => {
1467               let stack = store.debug_exit_frames().next().unwrap();
1468               let (func, pc) = stack.wasm_function_index_and_pc(&mut store).unwrap().unwrap();
1469               assert_eq!(func.as_u32(), 0);
1470               // The breakpoint should fire at the first opcode
1471               // (0x24), not at the function body start (0x23).
1472               assert_eq!(pc, 0x24);
1473           }
1474         }
1475     );
1476 
1477     let (handler, counter) = D::new_and_counter();
1478     store.set_debug_handler(handler);
1479 
1480     store
1481         .edit_breakpoints()
1482         .unwrap()
1483         .add_breakpoint(&module, 0x23)?;
1484 
1485     let instance = Instance::new_async(&mut store, &module, &[]).await?;
1486     let func = instance.get_func(&mut store, "main").unwrap();
1487     let mut results = [Val::I32(0)];
1488     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
1489         .await?;
1490     assert_eq!(counter.load(Ordering::Relaxed), 1);
1491     assert_eq!(results[0].unwrap_i32(), 3);
1492 
1493     // The actual breakpoint stored should be at the slipped PC.
1494     let breakpoints = store.breakpoints().unwrap().collect::<Vec<_>>();
1495     assert_eq!(breakpoints.len(), 1);
1496     assert_eq!(breakpoints[0].pc, 0x24);
1497 
1498     // Removing with the originally requested PC should work.
1499     store
1500         .edit_breakpoints()
1501         .unwrap()
1502         .remove_breakpoint(&module, 0x23)?;
1503     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
1504         .await?;
1505     // Counter should not have incremented now that we removed the
1506     // breakpoint.
1507     assert_eq!(counter.load(Ordering::Relaxed), 1);
1508 
1509     Ok(())
1510 }
1511