Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use dap::base_message::Sendable;
use dap::errors::ServerError;
use dap::prelude::{Event, Request, ResponseBody, Server};
use dap::server::{ServerReader, ServerWriter};
use tracing::trace;

pub struct Connection {
inbound_rx: mpsc::Receiver<Request>,
Expand Down Expand Up @@ -107,7 +108,7 @@ fn spawn_reader_thread(
thread::spawn(move || {
while let Ok(Some(request)) = server_reader.poll_request() {
if inbound_tx.send(request).is_err() {
// TODO: Add error tracing
trace!("Inbound channel closed");
break;
}
}
Expand Down
40 changes: 36 additions & 4 deletions src/debugger.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use anyhow::Result;
use anyhow::{Result, bail};
use cairo_vm::vm::vm_core::VirtualMachine;
use tracing::debug;
use dap::events::ExitedEventBody;
use dap::prelude::Event::{Exited, Terminated};
use tracing::{debug, error};

use crate::connection::Connection;
use crate::debugger::handler::{HandleResult, NextAction};
Expand Down Expand Up @@ -35,10 +37,40 @@ impl CairoDebugger {
}

fn sync_with_vm(&self, _vm: &VirtualMachine) -> Result<()> {
while let Some(request) = self.connection.try_next_request()? {
self.handle_request(request)?;
while let Some(request) = self.connection.try_next_request()?
&& let HandleResult::Trigger(NextAction::Stop) = self.handle_request(request)?
{
self.process_until_resume()?;
}

Ok(())
}

fn process_until_resume(&self) -> Result<()> {
loop {
let request = self.connection.next_request()?;
match self.handle_request(request)? {
HandleResult::Trigger(NextAction::Resume) => break,
HandleResult::Trigger(NextAction::FinishInit) => {
bail!("Unexpected request received during execution");
}
HandleResult::Handled | HandleResult::Trigger(NextAction::Stop) => {}
}
}

Ok(())
}
}

impl Drop for CairoDebugger {
fn drop(&mut self) {
if let Err(err) = self.connection.send_event(Terminated(None)) {
error!("Sending terminated event failed: {}", err);
}

// TODO(#34): Send correct exit code
if let Err(err) = self.connection.send_event(Exited(ExitedEventBody { exit_code: 0 })) {
error!("Sending exit event failed: {}", err);
}
}
}
115 changes: 65 additions & 50 deletions src/debugger/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use anyhow::{Result, bail};
use dap::events::{Event, StoppedEventBody};
use dap::prelude::{Command, Request, ResponseBody};
use dap::responses::{
EvaluateResponse, ScopesResponse, SetBreakpointsResponse, StackTraceResponse, ThreadsResponse,
VariablesResponse,
ContinueResponse, EvaluateResponse, ScopesResponse, SetBreakpointsResponse, StackTraceResponse,
ThreadsResponse, VariablesResponse,
};
use dap::types::{Breakpoint, Capabilities, Source, StackFrame, StoppedEventReason, Thread};
use tracing::trace;
Expand All @@ -16,6 +16,8 @@ pub enum HandleResult {
}

pub enum NextAction {
Resume,
Stop,
FinishInit,
}

Expand All @@ -28,7 +30,6 @@ impl CairoDebugger {
| Command::Completions(_)
| Command::DataBreakpointInfo(_)
| Command::Disassemble(_)
| Command::Disconnect(_)
| Command::Goto(_)
| Command::ExceptionInfo(_)
| Command::GotoTargets(_)
Expand All @@ -52,6 +53,12 @@ impl CairoDebugger {
bail!("Unsupported request");
}

// It makes no sense to send `attach` in the current architecture.
Command::Attach(_) => {
self.connection.send_error(request, "Attach is not supported")?;
bail!("Unsupported request");
}

// These may be supported after the MVP.
// Nonetheless, if we receive these with current capabilities,
// it is the client's fault.
Expand All @@ -69,13 +76,9 @@ impl CairoDebugger {
bail!("Set function breakpoints is not yet supported");
}

// It makes no sense to send `attach` in the current architecture.
Command::Attach(_) => {
self.connection.send_error(request, "Attach is not supported")?;
bail!("Unsupported request");
}

// Supported requests.

// Initialize flow requests.
Command::Initialize(args) => {
trace!("Initialized a client: {:?}", args.client_name);
self.connection.send_success(
Expand All @@ -88,22 +91,17 @@ impl CairoDebugger {
self.connection.send_event(Event::Initialized)?;
Ok(HandleResult::Handled)
}
Command::ConfigurationDone => {
trace!("Configuration done");
self.connection.send_success(request, ResponseBody::ConfigurationDone)?;
Ok(HandleResult::Trigger(NextAction::FinishInit))
}
Command::Continue(_) => {
todo!()
}
Command::Launch(_) => {
// Start running the Cairo program here.
self.connection.send_success(request, ResponseBody::Launch)?;
Ok(HandleResult::Handled)
}
Command::Next(_) => {
todo!()
Command::ConfigurationDone => {
// Start running the Cairo program here.
trace!("Configuration done");
self.connection.send_success(request, ResponseBody::ConfigurationDone)?;
Ok(HandleResult::Trigger(NextAction::FinishInit))
}

Command::Pause(_) => {
self.connection.send_event(Event::Stopped(StoppedEventBody {
reason: StoppedEventReason::Pause,
Expand All @@ -115,8 +113,16 @@ impl CairoDebugger {
hit_breakpoint_ids: None,
}))?;
self.connection.send_success(request, ResponseBody::Pause)?;
Ok(HandleResult::Handled)
Ok(HandleResult::Trigger(NextAction::Stop))
}
Command::Continue(_) => {
self.connection.send_success(
request,
ResponseBody::Continue(ContinueResponse { all_threads_continued: Some(true) }),
)?;
Ok(HandleResult::Trigger(NextAction::Resume))
}

Command::SetBreakpoints(args) => {
let mut response_bps = Vec::new();
if let Some(requested_bps) = &args.breakpoints {
Expand All @@ -138,8 +144,16 @@ impl CairoDebugger {
)?;
Ok(HandleResult::Handled)
}
Command::Source(_) => {
todo!()

Command::Threads => {
self.connection.send_success(
request,
ResponseBody::Threads(ThreadsResponse {
// Return a single thread.
threads: vec![Thread { id: 0, name: "".to_string() }],
}),
)?;
Ok(HandleResult::Handled)
}
Command::StackTrace(_) => {
self.connection.send_success(
Expand All @@ -160,12 +174,37 @@ impl CairoDebugger {
)?;
Ok(HandleResult::Handled)
}
Command::Scopes(_) => {
// Return no scopes.
self.connection.send_success(
request,
ResponseBody::Scopes(ScopesResponse { scopes: vec![] }),
)?;
Ok(HandleResult::Handled)
}
Command::Variables(_) => {
self.connection.send_success(
request,
ResponseBody::Variables(VariablesResponse {
// Return no variables.
variables: vec![],
}),
)?;
Ok(HandleResult::Handled)
}

Command::Next(_) => {
todo!()
}
Command::StepIn(_) => {
todo!()
}
Command::StepOut(_) => {
todo!()
}
Command::Source(_) => {
todo!()
}

Command::Evaluate(_) => {
self.connection.send_success(
Expand All @@ -183,33 +222,9 @@ impl CairoDebugger {
)?;
Ok(HandleResult::Handled)
}
Command::Threads => {
self.connection.send_success(
request,
ResponseBody::Threads(ThreadsResponse {
// Return a single thread.
threads: vec![Thread { id: 0, name: "".to_string() }],
}),
)?;
Ok(HandleResult::Handled)
}
Command::Variables(_) => {
self.connection.send_success(
request,
ResponseBody::Variables(VariablesResponse {
// Return no variables.
variables: vec![],
}),
)?;
Ok(HandleResult::Handled)
}
Command::Scopes(_) => {
// Return no scopes.
self.connection.send_success(
request,
ResponseBody::Scopes(ScopesResponse { scopes: vec![] }),
)?;
Ok(HandleResult::Handled)

Command::Disconnect(_) => {
todo!()
}
}
}
Expand Down