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