From 00edac18cb6eaf6b1c06f8401e554a8489c83791 Mon Sep 17 00:00:00 2001 From: William Wallace Date: Wed, 9 Dec 2020 06:34:18 +0000 Subject: [PATCH] Add `#dis`, wait-for-configure, other tweaks to Auxtools (#233) This fulfils some auxtool debugger requests you had. 1) All connection modes except for `BACKGROUND` wait for the DAP client to be configured before continuing. 2) stddef.dm contents are sent to the debug client 3) disassemble eval command works (with the added benefit of being able to disassemble procs that aren't currently running) The updated auxtools also does some other stuff you wanted: 1) src/usr moved to arguments 2) your PR https://github.com/willox/auxtools/pull/11 3) arguments with no formal parameter in a proc that is being debugged should show up --- src/langserver/debugger/auxtools.rs | 40 +++++++++++++++++++ src/langserver/debugger/auxtools_types.rs | 9 +++++ src/langserver/debugger/evaluate.rs | 48 ++++++++++++++++++++--- src/langserver/debugger/mod.rs | 5 ++- 4 files changed, 96 insertions(+), 6 deletions(-) diff --git a/src/langserver/debugger/auxtools.rs b/src/langserver/debugger/auxtools.rs index a3fad8ba..c6825fad 100644 --- a/src/langserver/debugger/auxtools.rs +++ b/src/langserver/debugger/auxtools.rs @@ -146,6 +146,46 @@ impl Auxtools { self.stream = StreamState::Disconnected; } + pub fn configured(&mut self) -> Result<(), Box> { + debug_output!(in self.seq, "[auxtools] configured"); + self.send_or_disconnect(Request::Configured)?; + + match self.read_response_or_disconnect()? { + Response::Ack { .. } => Ok(()), + response => Err(Box::new(UnexpectedResponse::new("Ack", response))), + } + } + + pub fn get_stddef(&mut self) -> Result, Box> { + self.send_or_disconnect(Request::StdDef)?; + + match self.read_response_or_disconnect()? { + Response::StdDef(contents) => Ok(contents), + response => Err(Box::new(UnexpectedResponse::new("StdDef", response))), + } + } + + pub fn disassemble(&mut self, path: &str, override_id: u32) -> Result> { + self.send_or_disconnect(Request::Disassemble(ProcRef { + path: path.to_owned(), + override_id, + }))?; + + match self.read_response_or_disconnect()? { + Response::Disassemble(res) => Ok(res), + response => Err(Box::new(UnexpectedResponse::new("Disassemble", response))), + } + } + + pub fn get_current_proc(&mut self, frame_id: u32) -> Result, Box> { + self.send_or_disconnect(Request::CurrentInstruction { frame_id })?; + + match self.read_response_or_disconnect()? { + Response::CurrentInstruction(ins) => Ok(ins.map(|x| (x.proc.path, x.proc.override_id))), + response => Err(Box::new(UnexpectedResponse::new("CurrentInstruction", response))), + } + } + pub fn get_line_number(&mut self, path: &str, override_id: u32, offset: u32) -> Result, Box> { self.send_or_disconnect(Request::LineNumber { proc: ProcRef { diff --git a/src/langserver/debugger/auxtools_types.rs b/src/langserver/debugger/auxtools_types.rs index f01ed3ad..5ba985c6 100644 --- a/src/langserver/debugger/auxtools_types.rs +++ b/src/langserver/debugger/auxtools_types.rs @@ -9,6 +9,12 @@ pub const DEFAULT_PORT: u16 = 2448; #[derive(Serialize, Deserialize, Debug)] pub enum Request { Disconnect, + Configured, + StdDef, + Disassemble(ProcRef), + CurrentInstruction { + frame_id: u32, + }, BreakpointSet { instruction: InstructionRef, }, @@ -48,6 +54,9 @@ pub enum Request { #[derive(Serialize, Deserialize, Debug)] pub enum Response { Ack, + StdDef(Option), + Disassemble(String), + CurrentInstruction(Option), BreakpointSet { result: BreakpointSetResult, }, diff --git a/src/langserver/debugger/evaluate.rs b/src/langserver/debugger/evaluate.rs index e813f1ee..7d3caaa1 100644 --- a/src/langserver/debugger/evaluate.rs +++ b/src/langserver/debugger/evaluate.rs @@ -1,23 +1,31 @@ +use regex::Regex; +use lazy_static; + use super::dap_types::*; use super::*; -const EVALUATE_HELP: &str = " +const EXTOOLS_HELP: &str = " #dis, #disassemble: show disassembly for current stack frame"; +const AUXTOOLS_HELP: &str = " +#dis, #disassemble: show disassembly for current stack frame +#dis, #disassemble : show disassembly for specified proc"; + impl Debugger { pub fn evaluate( &mut self, params: EvaluateArguments, ) -> Result> { let input = params.expression.trim_start(); - if input.starts_with("#help") { - return Ok(EvaluateResponse::from(EVALUATE_HELP.trim())); - } match &mut self.client { DebugClient::Extools(extools) => { let extools = extools.get()?; + if input.starts_with("#help") { + return Ok(EvaluateResponse::from(EXTOOLS_HELP.trim())); + } + guard!(let Some(frame_id) = params.frameId else { return Err(Box::new(GenericError("Must select a stack frame to evaluate in"))); }); @@ -36,7 +44,37 @@ impl Debugger { } } - DebugClient::Auxtools(_) => {} + DebugClient::Auxtools(auxtools) => { + lazy_static! { + static ref DISASSEMBLE_REGEX: Regex = Regex::new(r"^#dis(?:assemble)? (?P[^ ]+) ?(?P[0-9]*)$").unwrap(); + } + + if input.starts_with("#help") { + return Ok(EvaluateResponse::from(AUXTOOLS_HELP.trim())); + } + + if input == "#dis" || input == "#disassemble" { + guard!(let Some(frame_id) = params.frameId else { + return Err(Box::new(GenericError("Must select a stack frame to evaluate in"))); + }); + + let (path, override_id) = auxtools.get_current_proc(frame_id as u32)?.ok_or_else(|| { + Box::new(GenericError("Couldn't find current proc")) + })?; + + return Ok(EvaluateResponse::from(auxtools.disassemble(&path, override_id)?)); + } + + if let Some(captures) = DISASSEMBLE_REGEX.captures(input) { + let path = &captures["path"]; + let override_id = match captures.name("override").map(|x| x.as_str()) { + Some(str) => str.parse::().unwrap_or(0), + _ => 0, + }; + + return Ok(EvaluateResponse::from(auxtools.disassemble(path, override_id)?)); + } + } } Err(Box::new(GenericError("Not yet implemented"))) diff --git a/src/langserver/debugger/mod.rs b/src/langserver/debugger/mod.rs index 009986f4..efd5fa29 100644 --- a/src/langserver/debugger/mod.rs +++ b/src/langserver/debugger/mod.rs @@ -504,7 +504,10 @@ handle_request! { extools.configuration_done(); } - DebugClient::Auxtools(_) => {} + DebugClient::Auxtools(auxtools) => { + self.stddef_dm_info = auxtools.get_stddef()?.map(|x| StddefDmInfo::new(x)); + auxtools.configured()?; + } } }