1 //! Debug-main guest to run debugger tests.
2 //!
3 //! Invoked by tests/all/debug_component.rs with particular debuggees
4 //! loaded for each test (selected by argv) below. We print "OK" to
5 //! stderr to communicate success.
6 
7 use std::time::Duration;
8 
9 mod api {
10     wit_bindgen::generate!({
11         world: "bytecodealliance:wasmtime/debug-main",
12         path: "../../crates/debugger/wit",
13         with: {
14             "wasi:io/poll@0.2.6": wasip2::io::poll,
15         }
16     });
17 }
18 use api::bytecodealliance::wasmtime::debuggee::*;
19 
20 struct Component;
21 api::export!(Component with_types_in api);
22 
23 impl api::exports::bytecodealliance::wasmtime::debugger::Guest for Component {
debug(d: &Debuggee, args: Vec<String>)24     fn debug(d: &Debuggee, args: Vec<String>) {
25         match args.get(1).map(|s| s.as_str()) {
26             Some("simple") => {
27                 test_simple(d);
28             }
29             Some("loop") => {
30                 test_loop(d);
31             }
32             other => panic!("unknown test mode: {other:?}"),
33         }
34     }
35 }
36 
37 struct Resumption {
38     future: EventFuture,
39 }
40 
41 impl Resumption {
single_step(d: &Debuggee) -> Self42     fn single_step(d: &Debuggee) -> Self {
43         let future = d.single_step(ResumptionValue::Normal);
44         Self { future }
45     }
46 
continue_(d: &Debuggee) -> Self47     fn continue_(d: &Debuggee) -> Self {
48         let future = d.continue_(ResumptionValue::Normal);
49         Self { future }
50     }
51 
result(self, d: &Debuggee) -> Result<Event, Error>52     fn result(self, d: &Debuggee) -> Result<Event, Error> {
53         EventFuture::finish(self.future, d)
54     }
55 }
56 
57 /// Tests single-stepping.
58 ///
59 /// Tests against `debugger_debuggee_simple.wat`.
test_simple(d: &Debuggee)60 fn test_simple(d: &Debuggee) {
61     // Step once to reach the first instruction.
62     let r = Resumption::single_step(d);
63     let _event = r.result(d).unwrap();
64 
65     let mut pcs = vec![];
66 
67     for _ in 0..5 {
68         let frames = d.exit_frames();
69         let pc = frames[0].get_pc(d).unwrap();
70         pcs.push(pc);
71 
72         let r = Resumption::single_step(d);
73         match r.result(d).unwrap() {
74             Event::Breakpoint => {}
75             other => panic!("unexpected event: {other:?}"),
76         }
77     }
78 
79     // There should be five PCs and they should each be distinct from the previous.
80     assert_eq!(pcs.len(), 5);
81     assert!(pcs.windows(2).all(|p| p[0] != p[1]));
82 
83     eprintln!("OK");
84 }
85 
86 /// Interrupt test: continue an infinite-loop debuggee, interrupt it,
87 /// verify the interrupt, then set the exit flag in memory and continue
88 /// to completion.
89 ///
90 /// Tests against `debugger_debuggee_loop.wat`.
test_loop(d: &Debuggee)91 fn test_loop(d: &Debuggee) {
92     // Continue execution (the debuggee should loop).
93     let r = Resumption::continue_(d);
94 
95     // Yield to the event loop and let it run for a bit.
96     std::thread::sleep(Duration::from_millis(100));
97 
98     // Request interrupt.
99     d.interrupt();
100 
101     // Wait for the interrupt event.
102     let event = r.result(d).unwrap();
103     assert!(
104         matches!(event, Event::Interrupted),
105         "expected Interrupted, got {event:?}"
106     );
107 
108     // Set the exit-flag to kill the infinite loop in the guest (the
109     // debugger environment will not otherwise end until the guest
110     // ends; we have no way of forcing an early exit yet).
111     for inst in &d.all_instances() {
112         if let Ok(mem) = inst.get_memory(d, 0) {
113             mem.set_bytes(d, 0, &[1]).unwrap();
114         }
115     }
116 
117     // Continue; the debuggee should exit normally now.
118     let r = Resumption::continue_(d);
119     let event = r.result(d).unwrap();
120     assert!(
121         matches!(event, Event::Complete),
122         "expected Complete, got {event:?}"
123     );
124 
125     eprintln!("OK");
126 }
127 
main()128 fn main() {}
129