xref: /wasmtime-44.0.1/tests/all/debug.rs (revision 9acefdfe)
1 //! Tests for instrumentation-based debugging.
2 
3 use std::sync::Arc;
4 use std::sync::atomic::{AtomicUsize, Ordering};
5 use wasmtime::{
6     AsContextMut, Caller, Config, DebugEvent, DebugHandler, Engine, Extern, FrameParentResult,
7     Func, Global, GlobalType, Instance, Module, Mutability, Store, StoreContextMut, Val, ValType,
8 };
9 
10 #[test]
11 fn debugging_does_not_work_with_signal_based_traps() {
12     let mut config = Config::default();
13     config.guest_debug(true).signals_based_traps(true);
14     let err = Engine::new(&config).expect_err("invalid config should produce an error");
15     assert!(format!("{err:?}").contains("cannot use signals-based traps"));
16 }
17 
18 #[test]
19 fn debugging_apis_are_denied_without_debugging() -> wasmtime::Result<()> {
20     let mut config = Config::default();
21     config.guest_debug(false);
22     let engine = Engine::new(&config)?;
23     let module = Module::new(&engine, "(module (global $g (mut i32) (i32.const 0)))")?;
24     let mut store = Store::new(&engine, ());
25     let instance = Instance::new(&mut store, &module, &[])?;
26 
27     assert!(store.debug_frames().is_none());
28     assert!(instance.debug_global(&mut store, 0).is_none());
29 
30     Ok(())
31 }
32 
33 fn get_module_and_store<C: Fn(&mut Config)>(
34     c: C,
35     wat: &str,
36 ) -> wasmtime::Result<(Module, Store<()>)> {
37     let mut config = Config::default();
38     config.guest_debug(true);
39     config.wasm_exceptions(true);
40     c(&mut config);
41     let engine = Engine::new(&config)?;
42     let module = Module::new(&engine, wat)?;
43     Ok((module, Store::new(&engine, ())))
44 }
45 
46 fn test_stack_values<C: Fn(&mut Config), F: Fn(Caller<'_, ()>) + Send + Sync + 'static>(
47     wat: &str,
48     c: C,
49     f: F,
50 ) -> wasmtime::Result<()> {
51     let (module, mut store) = get_module_and_store(c, wat)?;
52     let func = Func::wrap(&mut store, move |caller: Caller<'_, ()>| {
53         f(caller);
54     });
55     let instance = Instance::new(&mut store, &module, &[Extern::Func(func)])?;
56     let mut results = [];
57     instance
58         .get_func(&mut store, "main")
59         .unwrap()
60         .call(&mut store, &[], &mut results)?;
61 
62     Ok(())
63 }
64 
65 #[test]
66 #[cfg_attr(miri, ignore)]
67 fn stack_values_two_frames() -> wasmtime::Result<()> {
68     let _ = env_logger::try_init();
69 
70     for inlining in [false, true] {
71         test_stack_values(
72             r#"
73     (module
74       (import "" "host" (func))
75       (func (export "main")
76         i32.const 1
77         i32.const 2
78         call 2
79         drop)
80       (func (param i32 i32) (result i32)
81         local.get 0
82         local.get 1
83         call 0
84         i32.add))
85     "#,
86             |config| {
87                 config.compiler_inlining(inlining);
88                 if inlining {
89                     unsafe {
90                         config.cranelift_flag_set("wasmtime_inlining_intra_module", "true");
91                     }
92                 }
93             },
94             |mut caller: Caller<'_, ()>| {
95                 let mut stack = caller.debug_frames().unwrap();
96                 assert!(!stack.done());
97                 assert_eq!(stack.wasm_function_index_and_pc().unwrap().0.as_u32(), 1);
98                 assert_eq!(stack.wasm_function_index_and_pc().unwrap().1, 65);
99 
100                 assert_eq!(stack.num_locals(), 2);
101                 assert_eq!(stack.num_stacks(), 2);
102                 assert_eq!(stack.local(0).unwrap_i32(), 1);
103                 assert_eq!(stack.local(1).unwrap_i32(), 2);
104                 assert_eq!(stack.stack(0).unwrap_i32(), 1);
105                 assert_eq!(stack.stack(1).unwrap_i32(), 2);
106 
107                 assert_eq!(stack.move_to_parent(), FrameParentResult::SameActivation);
108                 assert!(!stack.done());
109                 assert_eq!(stack.wasm_function_index_and_pc().unwrap().0.as_u32(), 0);
110                 assert_eq!(stack.wasm_function_index_and_pc().unwrap().1, 55);
111 
112                 assert_eq!(stack.move_to_parent(), FrameParentResult::SameActivation);
113                 assert!(stack.done());
114             },
115         )?;
116     }
117     Ok(())
118 }
119 
120 #[test]
121 #[cfg_attr(miri, ignore)]
122 fn stack_values_exceptions() -> wasmtime::Result<()> {
123     test_stack_values(
124         r#"
125     (module
126       (tag $t (param i32))
127       (import "" "host" (func))
128       (func (export "main")
129         (block $b (result i32)
130           (try_table (catch $t $b)
131             (throw $t (i32.const 42)))
132           i32.const 0)
133         (call 0)
134         (drop)))
135     "#,
136         |_config| {},
137         |mut caller: Caller<'_, ()>| {
138             let mut stack = caller.debug_frames().unwrap();
139             assert!(!stack.done());
140             assert_eq!(stack.num_stacks(), 1);
141             assert_eq!(stack.stack(0).unwrap_i32(), 42);
142             assert_eq!(stack.move_to_parent(), FrameParentResult::SameActivation);
143             assert!(stack.done());
144         },
145     )
146 }
147 
148 #[test]
149 #[cfg_attr(miri, ignore)]
150 fn stack_values_dead_gc_ref() -> wasmtime::Result<()> {
151     test_stack_values(
152         r#"
153     (module
154       (type $s (struct))
155       (import "" "host" (func))
156       (func (export "main")
157         (struct.new $s)
158         (call 0)
159         (drop)))
160     "#,
161         |config| {
162             config.wasm_gc(true);
163         },
164         |mut caller: Caller<'_, ()>| {
165             let mut stack = caller.debug_frames().unwrap();
166             assert!(!stack.done());
167             assert_eq!(stack.num_stacks(), 1);
168             assert!(stack.stack(0).unwrap_anyref().is_some());
169             assert_eq!(stack.move_to_parent(), FrameParentResult::SameActivation);
170             assert!(stack.done());
171         },
172     )
173 }
174 
175 #[test]
176 #[cfg_attr(miri, ignore)]
177 fn gc_access_during_call() -> wasmtime::Result<()> {
178     test_stack_values(
179         r#"
180     (module
181       (type $s (struct (field i32)))
182       (import "" "host" (func))
183       (func (export "main")
184         (local $l (ref null $s))
185         (local.set $l (struct.new $s (i32.const 42)))
186         (call 0)))
187     "#,
188         |config| {
189             config.wasm_gc(true);
190         },
191         |mut caller: Caller<'_, ()>| {
192             let mut stack = caller.debug_frames().unwrap();
193 
194             // Do a GC while we hold the stack cursor.
195             stack.as_context_mut().gc(None).unwrap();
196 
197             assert!(!stack.done());
198             assert_eq!(stack.num_stacks(), 0);
199             assert_eq!(stack.num_locals(), 1);
200             // Note that this struct is dead during the call, and the
201             // ref could otherwise be optimized away (no longer in the
202             // stackmap at this point); but we verify it is still
203             // alive here because it is rooted in the
204             // debug-instrumentation slot.
205             let s = stack
206                 .local(0)
207                 .unwrap_any_ref()
208                 .unwrap()
209                 .unwrap_struct(&stack)
210                 .unwrap();
211             assert_eq!(s.field(&mut stack, 0).unwrap().unwrap_i32(), 42);
212             assert_eq!(stack.move_to_parent(), FrameParentResult::SameActivation);
213             assert!(stack.done());
214         },
215     )
216 }
217 
218 #[test]
219 #[cfg_attr(miri, ignore)]
220 fn stack_values_two_activations() -> wasmtime::Result<()> {
221     let _ = env_logger::try_init();
222 
223     let mut config = Config::default();
224     config.guest_debug(true);
225     config.wasm_exceptions(true);
226     let engine = Engine::new(&config)?;
227     let module1 = Module::new(
228         &engine,
229         r#"
230     (module
231       (import "" "host1" (func (param i32 i32) (result i32)))
232       (func (export "main") (result i32)
233         i32.const 1
234         i32.const 2
235         call 0))
236     "#,
237     )?;
238     let module2 = Module::new(
239         &engine,
240         r#"
241     (module
242       (import "" "host2" (func))
243       (func (export "inner") (param i32 i32) (result i32)
244         local.get 0
245         local.get 1
246         call 0
247         i32.add))
248     "#,
249     )?;
250     let mut store = Store::new(&engine, ());
251 
252     let module1_clone = module1.clone();
253     let module2_clone = module2.clone();
254     let host2 = Func::wrap(&mut store, move |mut caller: Caller<'_, ()>| {
255         let mut stack = caller.debug_frames().unwrap();
256         assert!(!stack.done());
257         assert_eq!(stack.wasm_function_index_and_pc().unwrap().0.as_u32(), 0);
258         assert_eq!(stack.wasm_function_index_and_pc().unwrap().1, 56);
259         assert!(Module::same(stack.module().unwrap(), &module2_clone));
260         assert_eq!(stack.num_locals(), 2);
261         assert_eq!(stack.num_stacks(), 2);
262         assert_eq!(stack.local(0).unwrap_i32(), 1);
263         assert_eq!(stack.local(1).unwrap_i32(), 2);
264         assert_eq!(stack.stack(0).unwrap_i32(), 1);
265         assert_eq!(stack.stack(1).unwrap_i32(), 2);
266         let inner_instance = stack.instance();
267 
268         assert_eq!(stack.move_to_parent(), FrameParentResult::NewActivation);
269         assert!(!stack.done());
270 
271         assert_eq!(stack.wasm_function_index_and_pc().unwrap().0.as_u32(), 0);
272         assert_eq!(stack.wasm_function_index_and_pc().unwrap().1, 56);
273         assert!(Module::same(stack.module().unwrap(), &module1_clone));
274         assert_eq!(stack.num_locals(), 0);
275         assert_eq!(stack.num_stacks(), 2);
276         assert_eq!(stack.stack(0).unwrap_i32(), 1);
277         assert_eq!(stack.stack(1).unwrap_i32(), 2);
278         let outer_instance = stack.instance();
279 
280         assert_ne!(inner_instance, outer_instance);
281 
282         assert_eq!(stack.move_to_parent(), FrameParentResult::SameActivation);
283         assert!(stack.done());
284     });
285 
286     let instance2 = Instance::new(&mut store, &module2, &[Extern::Func(host2)])?;
287     let inner = instance2.get_func(&mut store, "inner").unwrap();
288 
289     let host1 = Func::wrap(
290         &mut store,
291         move |mut caller: Caller<'_, ()>, a: i32, b: i32| -> i32 {
292             let mut results = [Val::I32(0)];
293             inner
294                 .call(&mut caller, &[Val::I32(a), Val::I32(b)], &mut results[..])
295                 .unwrap();
296             results[0].unwrap_i32()
297         },
298     );
299 
300     let instance1 = Instance::new(&mut store, &module1, &[Extern::Func(host1)])?;
301     let main = instance1.get_func(&mut store, "main").unwrap();
302 
303     let mut results = [Val::I32(0)];
304     main.call(&mut store, &[], &mut results)?;
305     assert_eq!(results[0].unwrap_i32(), 3);
306     Ok(())
307 }
308 
309 #[test]
310 #[cfg_attr(miri, ignore)]
311 fn debug_frames_on_store_with_no_wasm_activation() -> wasmtime::Result<()> {
312     let mut config = Config::default();
313     config.guest_debug(true);
314     let engine = Engine::new(&config)?;
315     let mut store = Store::new(&engine, ());
316     let frames = store
317         .debug_frames()
318         .expect("Debug frames should be available");
319     assert!(frames.done());
320     Ok(())
321 }
322 
323 #[test]
324 #[cfg_attr(miri, ignore)]
325 fn private_entity_access() -> wasmtime::Result<()> {
326     let mut config = Config::default();
327     config.guest_debug(true);
328     config.wasm_gc(true);
329     config.gc_support(true);
330     config.wasm_exceptions(true);
331     let engine = Engine::new(&config)?;
332     let mut store = Store::new(&engine, ());
333     let module = Module::new(
334         &engine,
335         r#"
336         (module
337           (import "" "i" (global (mut i32)))
338           (import "" "f" (func (result i32)))
339           (global $g (mut i32) (i32.const 0))
340           (memory $m 1 1)
341           (table $t 10 10 i31ref)
342           (tag $tag (param f64))
343           (func (export "main")
344             ;; $g := 42
345             i32.const 42
346             global.set $g
347             ;; $m[1024] := 1
348             i32.const 1024
349             i32.const 1
350             i32.store8 $m
351             ;; $t[1] := (ref.i31 (i32.const 100))
352             i32.const 1
353             i32.const 100
354             ref.i31
355             table.set $t)
356 
357           (func (param i32)
358             local.get 0
359             global.set $g))
360         "#,
361     )?;
362 
363     let host_global = Global::new(
364         &mut store,
365         GlobalType::new(ValType::I32, Mutability::Var),
366         Val::I32(1000),
367     )?;
368     let host_func = Func::wrap(&mut store, |_caller: Caller<'_, ()>| -> i32 { 7 });
369 
370     let instance = Instance::new(
371         &mut store,
372         &module,
373         &[Extern::Global(host_global), Extern::Func(host_func)],
374     )?;
375     let func = instance.get_func(&mut store, "main").unwrap();
376     func.call(&mut store, &[], &mut [])?;
377 
378     // Nothing is exported except for `main`, yet we can still access
379     // (below).
380     let exports = instance.exports(&mut store).collect::<Vec<_>>();
381     assert_eq!(exports.len(), 1);
382     assert!(exports.into_iter().next().unwrap().into_func().is_some());
383 
384     // We can call a non-exported function.
385     let f = instance.debug_function(&mut store, 2).unwrap();
386     f.call(&mut store, &[Val::I32(1234)], &mut [])?;
387 
388     let g = instance.debug_global(&mut store, 1).unwrap();
389     assert_eq!(g.get(&mut store).unwrap_i32(), 1234);
390 
391     let m = instance.debug_memory(&mut store, 0).unwrap();
392     assert_eq!(m.data(&mut store)[1024], 1);
393 
394     let t = instance.debug_table(&mut store, 0).unwrap();
395     let t_val = t.get(&mut store, 1).unwrap();
396     let t_val = t_val.as_any().unwrap().unwrap().unwrap_i31(&store).unwrap();
397     assert_eq!(t_val.get_u32(), 100);
398 
399     let tag = instance.debug_tag(&mut store, 0).unwrap();
400     assert!(matches!(
401         tag.ty(&store).ty().param(0).unwrap(),
402         ValType::F64
403     ));
404 
405     // Check that we can access an imported global in the instance's
406     // index space.
407     let host_global_import = instance.debug_global(&mut store, 0).unwrap();
408     assert_eq!(host_global_import.get(&mut store).unwrap_i32(), 1000);
409 
410     // Check that we can call an imported function in the instance's
411     // index space.
412     let host_func_import = instance.debug_function(&mut store, 0).unwrap();
413     let mut results = [Val::I32(0)];
414     host_func_import.call(&mut store, &[], &mut results[..])?;
415     assert_eq!(results[0].unwrap_i32(), 7);
416 
417     // Check that out-of-bounds returns `None` rather than panic'ing.
418     assert!(instance.debug_global(&mut store, 2).is_none());
419 
420     Ok(())
421 }
422 
423 #[test]
424 #[cfg_attr(miri, ignore)]
425 #[cfg(target_pointer_width = "64")] // Threads not supported on 32-bit systems.
426 fn private_entity_access_shared_memory() -> wasmtime::Result<()> {
427     let mut config = Config::default();
428     config.guest_debug(true);
429     config.shared_memory(true);
430     config.wasm_threads(true);
431     let engine = Engine::new(&config)?;
432     let mut store = Store::new(&engine, ());
433     let module = Module::new(
434         &engine,
435         r#"
436         (module
437           (memory 1 1 shared))
438         "#,
439     )?;
440 
441     let instance = Instance::new(&mut store, &module, &[])?;
442 
443     let m = instance.debug_shared_memory(&mut store, 0).unwrap();
444     let unsafe_cell = &m.data()[1024];
445     assert_eq!(unsafe { *unsafe_cell.get() }, 0);
446 
447     Ok(())
448 }
449 
450 macro_rules! debug_event_checker {
451     ($ty:tt,
452      $store:tt,
453      $(
454          { $i:expr ; $pat:pat => $body:tt }
455      ),*)
456     =>
457     {
458         #[derive(Clone)]
459         struct $ty(Arc<AtomicUsize>);
460         impl $ty {
461             fn new_and_counter() -> (Self, Arc<AtomicUsize>) {
462                 let counter = Arc::new(AtomicUsize::new(0));
463                 let counter_clone = counter.clone();
464                 ($ty(counter), counter_clone)
465             }
466         }
467         impl DebugHandler for $ty {
468             type Data = ();
469             fn handle(
470                 &self,
471                 #[allow(unused_variables, reason = "macro rules")]
472                 #[allow(unused_mut, reason = "macro rules")]
473                 mut $store: StoreContextMut<'_, ()>,
474                 event: DebugEvent<'_>,
475             ) -> impl Future<Output = ()> + Send {
476                 let step = self.0.fetch_add(1, Ordering::Relaxed);
477                 async move {
478                     if false {}
479                     $(
480                         else if step == $i {
481                             match event {
482                                 $pat => {
483                                     $body;
484                                 }
485                                 _ => panic!("Incorrect event"),
486                             }
487                         }
488                     )*
489                     else {
490                         panic!("Too many steps");
491                     }
492                 }
493             }
494         }
495     }
496 }
497 
498 #[tokio::test]
499 #[cfg_attr(miri, ignore)]
500 async fn uncaught_exception_events() -> wasmtime::Result<()> {
501     let _ = env_logger::try_init();
502 
503     let (module, mut store) = get_module_and_store(
504         |config| {
505             config.wasm_exceptions(true);
506         },
507         r#"
508     (module
509       (tag $t (param i32))
510       (func (export "main")
511         call 1)
512       (func
513         (local $i i32)
514         (local.set $i (i32.const 100))
515         (throw $t (i32.const 42))))
516     "#,
517     )?;
518 
519     debug_event_checker!(
520         D, store,
521         { 0 ;
522           wasmtime::DebugEvent::UncaughtExceptionThrown(e) => {
523               assert_eq!(e.field(&mut store, 0).unwrap().unwrap_i32(), 42);
524               let mut stack = store.debug_frames().expect("frame cursor must be available");
525               assert!(!stack.done());
526               assert_eq!(stack.num_locals(), 1);
527               assert_eq!(stack.local(0).unwrap_i32(), 100);
528               assert_eq!(stack.move_to_parent(), FrameParentResult::SameActivation);
529               assert!(!stack.done());
530               assert_eq!(stack.move_to_parent(), FrameParentResult::SameActivation);
531               assert!(stack.done());
532           }
533         }
534     );
535 
536     let (handler, counter) = D::new_and_counter();
537     store.set_debug_handler(handler);
538 
539     let instance = Instance::new_async(&mut store, &module, &[]).await?;
540     let func = instance.get_func(&mut store, "main").unwrap();
541     let mut results = [];
542     let result = func.call_async(&mut store, &[], &mut results).await;
543     assert!(result.is_err()); // Uncaught exception.
544     assert_eq!(counter.load(Ordering::Relaxed), 1);
545 
546     Ok(())
547 }
548 
549 #[tokio::test]
550 #[cfg_attr(miri, ignore)]
551 async fn caught_exception_events() -> wasmtime::Result<()> {
552     let _ = env_logger::try_init();
553 
554     let (module, mut store) = get_module_and_store(
555         |config| {
556             config.wasm_exceptions(true);
557         },
558         r#"
559     (module
560       (tag $t (param i32))
561       (func (export "main")
562         (block $b (result i32)
563           (try_table (catch $t $b)
564             call 1)
565           i32.const 0)
566         drop)
567       (func
568         (local $i i32)
569         (local.set $i (i32.const 100))
570         (throw $t (i32.const 42))))
571     "#,
572     )?;
573 
574     debug_event_checker!(
575         D, store,
576         { 0 ;
577           wasmtime::DebugEvent::CaughtExceptionThrown(e) => {
578               assert_eq!(e.field(&mut store, 0).unwrap().unwrap_i32(), 42);
579               let mut stack = store.debug_frames().expect("frame cursor must be available");
580               assert!(!stack.done());
581               assert_eq!(stack.num_locals(), 1);
582               assert_eq!(stack.local(0).unwrap_i32(), 100);
583               assert_eq!(stack.move_to_parent(), FrameParentResult::SameActivation);
584               assert!(!stack.done());
585               assert_eq!(stack.move_to_parent(), FrameParentResult::SameActivation);
586               assert!(stack.done());
587           }
588         }
589     );
590 
591     let (handler, counter) = D::new_and_counter();
592     store.set_debug_handler(handler);
593 
594     let instance = Instance::new_async(&mut store, &module, &[]).await?;
595     let func = instance.get_func(&mut store, "main").unwrap();
596     let mut results = [];
597     func.call_async(&mut store, &[], &mut results).await?;
598     assert_eq!(counter.load(Ordering::Relaxed), 1);
599 
600     Ok(())
601 }
602 
603 #[tokio::test]
604 #[cfg_attr(miri, ignore)]
605 async fn hostcall_trap_events() -> wasmtime::Result<()> {
606     let _ = env_logger::try_init();
607 
608     let (module, mut store) = get_module_and_store(
609         |config| {
610             config.wasm_exceptions(true);
611         },
612         r#"
613     (module
614       (func (export "main")
615         i32.const 0
616         i32.const 0
617         i32.div_u
618         drop))
619     "#,
620     )?;
621 
622     debug_event_checker!(
623         D, store,
624         { 0 ;
625           wasmtime::DebugEvent::Trap(wasmtime_environ::Trap::IntegerDivisionByZero) => {}
626         }
627     );
628 
629     let (handler, counter) = D::new_and_counter();
630     store.set_debug_handler(handler);
631 
632     let instance = Instance::new_async(&mut store, &module, &[]).await?;
633     let func = instance.get_func(&mut store, "main").unwrap();
634     let mut results = [];
635     let result = func.call_async(&mut store, &[], &mut results).await;
636     assert!(result.is_err()); // Uncaught trap.
637     assert_eq!(counter.load(Ordering::Relaxed), 1);
638 
639     Ok(())
640 }
641 
642 #[tokio::test]
643 #[cfg_attr(miri, ignore)]
644 async fn hostcall_error_events() -> wasmtime::Result<()> {
645     let _ = env_logger::try_init();
646 
647     let (module, mut store) = get_module_and_store(
648         |config| {
649             config.wasm_exceptions(true);
650         },
651         r#"
652     (module
653       (import "" "do_a_trap" (func))
654       (func (export "main")
655         call 0))
656     "#,
657     )?;
658 
659     debug_event_checker!(
660         D, store,
661         { 0 ;
662           wasmtime::DebugEvent::HostcallError(e) => {
663               assert!(format!("{e:?}").contains("secret error message"));
664           }
665         }
666     );
667 
668     let (handler, counter) = D::new_and_counter();
669     store.set_debug_handler(handler);
670 
671     let do_a_trap = Func::wrap(
672         &mut store,
673         |_caller: Caller<'_, ()>| -> wasmtime::Result<()> {
674             Err(wasmtime::format_err!("secret error message"))
675         },
676     );
677     let instance = Instance::new_async(&mut store, &module, &[Extern::Func(do_a_trap)]).await?;
678     let func = instance.get_func(&mut store, "main").unwrap();
679     let mut results = [];
680     let result = func.call_async(&mut store, &[], &mut results).await;
681     assert!(result.is_err()); // Uncaught trap.
682     assert_eq!(counter.load(Ordering::Relaxed), 1);
683     Ok(())
684 }
685 
686 #[tokio::test]
687 #[cfg_attr(miri, ignore)]
688 async fn breakpoint_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") (param i32 i32) (result i32)
698         local.get 0
699         local.get 1
700         i32.add))
701     "#,
702     )?;
703 
704     debug_event_checker!(
705         D, store,
706         { 0 ;
707           wasmtime::DebugEvent::Breakpoint => {
708               let mut stack = store.debug_frames().expect("frame cursor must be available");
709               assert!(!stack.done());
710               assert_eq!(stack.num_locals(), 2);
711               assert_eq!(stack.local(0).unwrap_i32(), 1);
712               assert_eq!(stack.local(1).unwrap_i32(), 2);
713               let (func, pc) = stack.wasm_function_index_and_pc().unwrap();
714               assert_eq!(func.as_u32(), 0);
715               assert_eq!(pc, 0x28);
716               assert_eq!(stack.move_to_parent(), FrameParentResult::SameActivation);
717               assert!(stack.done());
718           }
719         }
720     );
721 
722     let (handler, counter) = D::new_and_counter();
723     store.set_debug_handler(handler);
724     store
725         .edit_breakpoints()
726         .unwrap()
727         .add_breakpoint(&module, 0x28)?;
728 
729     let instance = Instance::new_async(&mut store, &module, &[]).await?;
730     let func = instance.get_func(&mut store, "main").unwrap();
731     let mut results = [Val::I32(0)];
732     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
733         .await?;
734     assert_eq!(counter.load(Ordering::Relaxed), 1);
735     assert_eq!(results[0].unwrap_i32(), 3);
736 
737     let breakpoints = store.breakpoints().unwrap().collect::<Vec<_>>();
738     assert_eq!(breakpoints.len(), 1);
739     assert!(Module::same(&breakpoints[0].module, &module));
740     assert_eq!(breakpoints[0].pc, 0x28);
741 
742     store
743         .edit_breakpoints()
744         .unwrap()
745         .remove_breakpoint(&module, 0x28)?;
746     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
747         .await?;
748     assert_eq!(counter.load(Ordering::Relaxed), 1); // Should not have incremented from above.
749     assert_eq!(results[0].unwrap_i32(), 3);
750 
751     // Enable single-step mode (on top of the breakpoint already enabled).
752     assert!(!store.is_single_step());
753     store.edit_breakpoints().unwrap().single_step(true).unwrap();
754     assert!(store.is_single_step());
755 
756     debug_event_checker!(
757         D2, store,
758         { 0 ;
759           wasmtime::DebugEvent::Breakpoint => {
760               let stack = store.debug_frames().unwrap();
761               assert!(!stack.done());
762               let (_, pc) = stack.wasm_function_index_and_pc().unwrap();
763               assert_eq!(pc, 0x24);
764           }
765         },
766         {
767           1 ;
768           wasmtime::DebugEvent::Breakpoint => {
769               let stack = store.debug_frames().unwrap();
770               assert!(!stack.done());
771               let (_, pc) = stack.wasm_function_index_and_pc().unwrap();
772               assert_eq!(pc, 0x26);
773           }
774         },
775         {
776           2 ;
777           wasmtime::DebugEvent::Breakpoint => {
778               let stack = store.debug_frames().unwrap();
779               assert!(!stack.done());
780               let (_, pc) = stack.wasm_function_index_and_pc().unwrap();
781               assert_eq!(pc, 0x28);
782           }
783         },
784         {
785           3 ;
786           wasmtime::DebugEvent::Breakpoint => {
787               let stack = store.debug_frames().unwrap();
788               assert!(!stack.done());
789               let (_, pc) = stack.wasm_function_index_and_pc().unwrap();
790               assert_eq!(pc, 0x29);
791           }
792         }
793     );
794 
795     let (handler, counter) = D2::new_and_counter();
796     store.set_debug_handler(handler);
797 
798     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
799         .await?;
800     assert_eq!(counter.load(Ordering::Relaxed), 4);
801 
802     // Re-enable individual breakpoint.
803     store
804         .edit_breakpoints()
805         .unwrap()
806         .add_breakpoint(&module, 0x28)
807         .unwrap();
808 
809     // Now disable single-stepping. The single breakpoint set above
810     // should still remain.
811     store
812         .edit_breakpoints()
813         .unwrap()
814         .single_step(false)
815         .unwrap();
816 
817     let (handler, counter) = D::new_and_counter();
818     store.set_debug_handler(handler);
819 
820     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
821         .await?;
822     assert_eq!(counter.load(Ordering::Relaxed), 1);
823 
824     Ok(())
825 }
826 
827 #[tokio::test]
828 #[cfg_attr(miri, ignore)]
829 async fn breakpoints_in_inlined_code() -> wasmtime::Result<()> {
830     let _ = env_logger::try_init();
831 
832     let (module, mut store) = get_module_and_store(
833         |config| {
834             config.wasm_exceptions(true);
835             config.compiler_inlining(true);
836             unsafe {
837                 config.cranelift_flag_set("wasmtime_inlining_intra_module", "true");
838             }
839         },
840         r#"
841     (module
842       (func $f (export "f") (param i32 i32) (result i32)
843         local.get 0
844         local.get 1
845         i32.add)
846 
847       (func (export "main") (param i32 i32) (result i32)
848         local.get 0
849         local.get 1
850         call $f))
851     "#,
852     )?;
853 
854     debug_event_checker!(
855         D, store,
856         { 0 ;
857           wasmtime::DebugEvent::Breakpoint => {}
858         },
859         { 1 ;
860           wasmtime::DebugEvent::Breakpoint => {}
861         }
862     );
863 
864     let (handler, counter) = D::new_and_counter();
865     store.set_debug_handler(handler);
866     store
867         .edit_breakpoints()
868         .unwrap()
869         .add_breakpoint(&module, 0x2d)?; // `i32.add` in `$f`.
870 
871     let instance = Instance::new_async(&mut store, &module, &[]).await?;
872     let func_main = instance.get_func(&mut store, "main").unwrap();
873     let func_f = instance.get_func(&mut store, "f").unwrap();
874     let mut results = [Val::I32(0)];
875     // Breakpoint in `$f` should have been hit in `main` even if it
876     // was inlined.
877     func_main
878         .call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
879         .await?;
880     assert_eq!(counter.load(Ordering::Relaxed), 1);
881     assert_eq!(results[0].unwrap_i32(), 3);
882 
883     // Breakpoint in `$f` should be hit when called directly, too.
884     func_f
885         .call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
886         .await?;
887     assert_eq!(counter.load(Ordering::Relaxed), 2);
888     assert_eq!(results[0].unwrap_i32(), 3);
889 
890     Ok(())
891 }
892 
893 #[tokio::test]
894 #[cfg_attr(miri, ignore)]
895 async fn epoch_events() -> wasmtime::Result<()> {
896     let _ = env_logger::try_init();
897 
898     let (module, mut store) = get_module_and_store(
899         |config| {
900             config.epoch_interruption(true);
901         },
902         r#"
903     (module
904       (func $f (export "f") (param i32 i32) (result i32)
905         local.get 0
906         local.get 1
907         i32.add))
908     "#,
909     )?;
910 
911     debug_event_checker!(
912         D, store,
913         { 0 ;
914           wasmtime::DebugEvent::EpochYield => {}
915         }
916     );
917 
918     let (handler, counter) = D::new_and_counter();
919     store.set_debug_handler(handler);
920 
921     store.set_epoch_deadline(1);
922     store.epoch_deadline_async_yield_and_update(1);
923     store.engine().increment_epoch();
924 
925     let instance = Instance::new_async(&mut store, &module, &[]).await?;
926     let func_f = instance.get_func(&mut store, "f").unwrap();
927     let mut results = [Val::I32(0)];
928     func_f
929         .call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
930         .await?;
931     assert_eq!(counter.load(Ordering::Relaxed), 1);
932     assert_eq!(results[0].unwrap_i32(), 3);
933 
934     Ok(())
935 }
936