Skip to content

Commit d4c1828

Browse files
authored
Support pause and continue requests (#32)
* Support pause and continue requests * Reorder commands * Implement drop for `CairoDebugger` * Trace errors in drop * Replace channel error with trace
1 parent 18892bc commit d4c1828

File tree

3 files changed

+103
-55
lines changed

3 files changed

+103
-55
lines changed

src/connection.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use dap::base_message::Sendable;
1111
use dap::errors::ServerError;
1212
use dap::prelude::{Event, Request, ResponseBody, Server};
1313
use dap::server::{ServerReader, ServerWriter};
14+
use tracing::trace;
1415

1516
pub struct Connection {
1617
inbound_rx: mpsc::Receiver<Request>,
@@ -107,7 +108,7 @@ fn spawn_reader_thread(
107108
thread::spawn(move || {
108109
while let Ok(Some(request)) = server_reader.poll_request() {
109110
if inbound_tx.send(request).is_err() {
110-
// TODO: Add error tracing
111+
trace!("Inbound channel closed");
111112
break;
112113
}
113114
}

src/debugger.rs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
use anyhow::Result;
1+
use anyhow::{Result, bail};
22
use cairo_vm::vm::vm_core::VirtualMachine;
3-
use tracing::debug;
3+
use dap::events::ExitedEventBody;
4+
use dap::prelude::Event::{Exited, Terminated};
5+
use tracing::{debug, error};
46

57
use crate::connection::Connection;
68
use crate::debugger::handler::{HandleResult, NextAction};
@@ -35,10 +37,40 @@ impl CairoDebugger {
3537
}
3638

3739
fn sync_with_vm(&self, _vm: &VirtualMachine) -> Result<()> {
38-
while let Some(request) = self.connection.try_next_request()? {
39-
self.handle_request(request)?;
40+
while let Some(request) = self.connection.try_next_request()?
41+
&& let HandleResult::Trigger(NextAction::Stop) = self.handle_request(request)?
42+
{
43+
self.process_until_resume()?;
4044
}
4145

4246
Ok(())
4347
}
48+
49+
fn process_until_resume(&self) -> Result<()> {
50+
loop {
51+
let request = self.connection.next_request()?;
52+
match self.handle_request(request)? {
53+
HandleResult::Trigger(NextAction::Resume) => break,
54+
HandleResult::Trigger(NextAction::FinishInit) => {
55+
bail!("Unexpected request received during execution");
56+
}
57+
HandleResult::Handled | HandleResult::Trigger(NextAction::Stop) => {}
58+
}
59+
}
60+
61+
Ok(())
62+
}
63+
}
64+
65+
impl Drop for CairoDebugger {
66+
fn drop(&mut self) {
67+
if let Err(err) = self.connection.send_event(Terminated(None)) {
68+
error!("Sending terminated event failed: {}", err);
69+
}
70+
71+
// TODO(#34): Send correct exit code
72+
if let Err(err) = self.connection.send_event(Exited(ExitedEventBody { exit_code: 0 })) {
73+
error!("Sending exit event failed: {}", err);
74+
}
75+
}
4476
}

src/debugger/handler.rs

Lines changed: 65 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use anyhow::{Result, bail};
22
use dap::events::{Event, StoppedEventBody};
33
use dap::prelude::{Command, Request, ResponseBody};
44
use dap::responses::{
5-
EvaluateResponse, ScopesResponse, SetBreakpointsResponse, StackTraceResponse, ThreadsResponse,
6-
VariablesResponse,
5+
ContinueResponse, EvaluateResponse, ScopesResponse, SetBreakpointsResponse, StackTraceResponse,
6+
ThreadsResponse, VariablesResponse,
77
};
88
use dap::types::{Breakpoint, Capabilities, Source, StackFrame, StoppedEventReason, Thread};
99
use tracing::trace;
@@ -16,6 +16,8 @@ pub enum HandleResult {
1616
}
1717

1818
pub enum NextAction {
19+
Resume,
20+
Stop,
1921
FinishInit,
2022
}
2123

@@ -28,7 +30,6 @@ impl CairoDebugger {
2830
| Command::Completions(_)
2931
| Command::DataBreakpointInfo(_)
3032
| Command::Disassemble(_)
31-
| Command::Disconnect(_)
3233
| Command::Goto(_)
3334
| Command::ExceptionInfo(_)
3435
| Command::GotoTargets(_)
@@ -52,6 +53,12 @@ impl CairoDebugger {
5253
bail!("Unsupported request");
5354
}
5455

56+
// It makes no sense to send `attach` in the current architecture.
57+
Command::Attach(_) => {
58+
self.connection.send_error(request, "Attach is not supported")?;
59+
bail!("Unsupported request");
60+
}
61+
5562
// These may be supported after the MVP.
5663
// Nonetheless, if we receive these with current capabilities,
5764
// it is the client's fault.
@@ -69,13 +76,9 @@ impl CairoDebugger {
6976
bail!("Set function breakpoints is not yet supported");
7077
}
7178

72-
// It makes no sense to send `attach` in the current architecture.
73-
Command::Attach(_) => {
74-
self.connection.send_error(request, "Attach is not supported")?;
75-
bail!("Unsupported request");
76-
}
77-
7879
// Supported requests.
80+
81+
// Initialize flow requests.
7982
Command::Initialize(args) => {
8083
trace!("Initialized a client: {:?}", args.client_name);
8184
self.connection.send_success(
@@ -88,22 +91,17 @@ impl CairoDebugger {
8891
self.connection.send_event(Event::Initialized)?;
8992
Ok(HandleResult::Handled)
9093
}
91-
Command::ConfigurationDone => {
92-
trace!("Configuration done");
93-
self.connection.send_success(request, ResponseBody::ConfigurationDone)?;
94-
Ok(HandleResult::Trigger(NextAction::FinishInit))
95-
}
96-
Command::Continue(_) => {
97-
todo!()
98-
}
9994
Command::Launch(_) => {
100-
// Start running the Cairo program here.
10195
self.connection.send_success(request, ResponseBody::Launch)?;
10296
Ok(HandleResult::Handled)
10397
}
104-
Command::Next(_) => {
105-
todo!()
98+
Command::ConfigurationDone => {
99+
// Start running the Cairo program here.
100+
trace!("Configuration done");
101+
self.connection.send_success(request, ResponseBody::ConfigurationDone)?;
102+
Ok(HandleResult::Trigger(NextAction::FinishInit))
106103
}
104+
107105
Command::Pause(_) => {
108106
self.connection.send_event(Event::Stopped(StoppedEventBody {
109107
reason: StoppedEventReason::Pause,
@@ -115,8 +113,16 @@ impl CairoDebugger {
115113
hit_breakpoint_ids: None,
116114
}))?;
117115
self.connection.send_success(request, ResponseBody::Pause)?;
118-
Ok(HandleResult::Handled)
116+
Ok(HandleResult::Trigger(NextAction::Stop))
119117
}
118+
Command::Continue(_) => {
119+
self.connection.send_success(
120+
request,
121+
ResponseBody::Continue(ContinueResponse { all_threads_continued: Some(true) }),
122+
)?;
123+
Ok(HandleResult::Trigger(NextAction::Resume))
124+
}
125+
120126
Command::SetBreakpoints(args) => {
121127
let mut response_bps = Vec::new();
122128
if let Some(requested_bps) = &args.breakpoints {
@@ -138,8 +144,16 @@ impl CairoDebugger {
138144
)?;
139145
Ok(HandleResult::Handled)
140146
}
141-
Command::Source(_) => {
142-
todo!()
147+
148+
Command::Threads => {
149+
self.connection.send_success(
150+
request,
151+
ResponseBody::Threads(ThreadsResponse {
152+
// Return a single thread.
153+
threads: vec![Thread { id: 0, name: "".to_string() }],
154+
}),
155+
)?;
156+
Ok(HandleResult::Handled)
143157
}
144158
Command::StackTrace(_) => {
145159
self.connection.send_success(
@@ -160,12 +174,37 @@ impl CairoDebugger {
160174
)?;
161175
Ok(HandleResult::Handled)
162176
}
177+
Command::Scopes(_) => {
178+
// Return no scopes.
179+
self.connection.send_success(
180+
request,
181+
ResponseBody::Scopes(ScopesResponse { scopes: vec![] }),
182+
)?;
183+
Ok(HandleResult::Handled)
184+
}
185+
Command::Variables(_) => {
186+
self.connection.send_success(
187+
request,
188+
ResponseBody::Variables(VariablesResponse {
189+
// Return no variables.
190+
variables: vec![],
191+
}),
192+
)?;
193+
Ok(HandleResult::Handled)
194+
}
195+
196+
Command::Next(_) => {
197+
todo!()
198+
}
163199
Command::StepIn(_) => {
164200
todo!()
165201
}
166202
Command::StepOut(_) => {
167203
todo!()
168204
}
205+
Command::Source(_) => {
206+
todo!()
207+
}
169208

170209
Command::Evaluate(_) => {
171210
self.connection.send_success(
@@ -183,33 +222,9 @@ impl CairoDebugger {
183222
)?;
184223
Ok(HandleResult::Handled)
185224
}
186-
Command::Threads => {
187-
self.connection.send_success(
188-
request,
189-
ResponseBody::Threads(ThreadsResponse {
190-
// Return a single thread.
191-
threads: vec![Thread { id: 0, name: "".to_string() }],
192-
}),
193-
)?;
194-
Ok(HandleResult::Handled)
195-
}
196-
Command::Variables(_) => {
197-
self.connection.send_success(
198-
request,
199-
ResponseBody::Variables(VariablesResponse {
200-
// Return no variables.
201-
variables: vec![],
202-
}),
203-
)?;
204-
Ok(HandleResult::Handled)
205-
}
206-
Command::Scopes(_) => {
207-
// Return no scopes.
208-
self.connection.send_success(
209-
request,
210-
ResponseBody::Scopes(ScopesResponse { scopes: vec![] }),
211-
)?;
212-
Ok(HandleResult::Handled)
225+
226+
Command::Disconnect(_) => {
227+
todo!()
213228
}
214229
}
215230
}

0 commit comments

Comments
 (0)