Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC/WIP: Support DAP disassemble request #627

Closed
wants to merge 2 commits into from
Closed
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
5 changes: 4 additions & 1 deletion adapter/src/debug_protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ pub use raw_debug_protocol::{
Breakpoint, BreakpointEventBody, CancelArguments, Capabilities, CapabilitiesEventBody, CompletionItem,
CompletionsArguments, CompletionsResponseBody, ContinueArguments, ContinueResponseBody, ContinuedEventBody,
DataBreakpoint, DataBreakpointAccessType, DataBreakpointInfoArguments, DataBreakpointInfoResponseBody,
DisconnectArguments, EvaluateArguments, EvaluateResponseBody, ExceptionBreakpointsFilter, ExitedEventBody,
DisassembleArguments, DisassembleResponseBody, DisassembledInstruction, DisconnectArguments, EvaluateArguments,
EvaluateResponseBody, ExceptionBreakpointsFilter, ExitedEventBody,
GotoArguments, GotoTarget, GotoTargetsArguments, GotoTargetsResponseBody, InitializeRequestArguments,
InvalidatedAreas, InvalidatedEventBody, Module, ModuleEventBody, NextArguments, OutputEventBody, PauseArguments,
ReadMemoryArguments, ReadMemoryResponseBody, RestartFrameArguments, ReverseContinueArguments,
Expand Down Expand Up @@ -112,6 +113,7 @@ pub enum RequestArguments {
readMemory(ReadMemoryArguments),
terminate(Option<TerminateArguments>),
disconnect(Option<DisconnectArguments>),
disassemble(DisassembleArguments),
// Reverse
runInTerminal(RunInTerminalRequestArguments),
// Custom
Expand Down Expand Up @@ -155,6 +157,7 @@ pub enum ResponseBody {
readMemory(ReadMemoryResponseBody),
terminate,
disconnect,
disassemble(DisassembleResponseBody),
// Reverse
runInTerminal(RunInTerminalResponseBody),
// Custom
Expand Down
26 changes: 26 additions & 0 deletions adapter/src/debug_session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,9 @@ impl DebugSession {
RequestArguments::_symbols(args) =>
self.handle_symbols(args)
.map(|r| ResponseBody::_symbols(r)),
RequestArguments::disassemble(args) =>
self.handle_disassemble(args)
.map(|r| ResponseBody::disassemble(r)),
_=> bail!("Not implemented.")
}
}
Expand Down Expand Up @@ -525,6 +528,7 @@ impl DebugSession {
supports_evaluate_for_hovers: Some(self.evaluate_for_hovers),
supports_completions_request: Some(self.command_completions),
exception_breakpoint_filters: Some(self.get_exception_filters(&self.source_languages)),
supports_disassemble_request: Some(true),
..Default::default()
}
}
Expand Down Expand Up @@ -1076,6 +1080,9 @@ impl DebugSession {
path: Some(local_path.to_string_lossy().into_owned()),
..Default::default()
});
stack_frame.instruction_pointer_reference =
Some(format!("0x{:X}",
pc_address.load_address(&self.target)))
}
}
} else {
Expand All @@ -1089,6 +1096,8 @@ impl DebugSession {
..Default::default()
});
stack_frame.presentation_hint = Some("subtle".to_owned());
stack_frame.instruction_pointer_reference =
Some(format!("0x{:X}", pc_addr ));
}
stack_frames.push(stack_frame);
}
Expand Down Expand Up @@ -1541,6 +1550,23 @@ impl DebugSession {
})
}

fn handle_disassemble(&mut self, args: DisassembleArguments) -> Result<DisassembleResponseBody, Error> {
let mem_ref = parse_int::parse::<i64>(&args.memory_reference)?;
let offset = args.offset.unwrap_or(0);
let count = args.instruction_count as usize;
let address = (mem_ref + offset) as lldb::Address;
if let Ok(dasm) = self.disassembly.from_address_and_max_count( address,
count as u32 ) {
Ok( DisassembleResponseBody {
instructions: dasm.get_disassembled_instructions(),
} )
} else {
Ok( DisassembleResponseBody {
instructions: vec![]
} )
}
}

fn handle_symbols(&mut self, args: SymbolsRequest) -> Result<SymbolsResponse, Error> {
let (mut next_module, mut next_symbol) = match args.continuation_token {
Some(token) => (token.next_module, token.next_symbol),
Expand Down
61 changes: 59 additions & 2 deletions adapter/src/disassembly.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use raw_debug_protocol::DisassembledInstruction;
use crate::prelude::*;
use serde_derive::*;
use std::borrow::Cow;
Expand Down Expand Up @@ -51,6 +52,11 @@ impl AddressSpace {
}

pub fn from_address(&self, load_addr: Address) -> Result<Rc<DisassembledRange>, Error> {
const NO_SYMBOL_INSTRUCTIONS: u32 = 32;
self.from_address_and_max_count( load_addr, NO_SYMBOL_INSTRUCTIONS )
}

pub fn from_address_and_max_count(&self, load_addr: Address, max_count: u32 ) -> Result<Rc<DisassembledRange>,Error> {
if let Some(dasm) = self.find_by_address(load_addr) {
return Ok(dasm);
}
Expand All @@ -69,9 +75,8 @@ impl AddressSpace {
}
None => {
// How many instructions to put into DisassembledRange if the address is not in scope of any symbol.
const NO_SYMBOL_INSTRUCTIONS: u32 = 32;
start_addr = addr.clone();
instructions = self.target.read_instructions(&start_addr, NO_SYMBOL_INSTRUCTIONS + 1);
instructions = self.target.read_instructions(&start_addr, max_count + 1);
end_addr = if instructions.len() > 0 {
let last_instr = instructions.instruction_at_index((instructions.len() - 1) as u32);
last_instr.address()
Expand Down Expand Up @@ -180,6 +185,58 @@ impl DisassembledRange {
.collect()
}

pub fn get_disassembled_instructions(&self) -> Vec<DisassembledInstruction> {
let mut instructions = vec![];

const MAX_INSTR_BYTES: usize = 8;
let mut instr_data = vec![];
let mut dump = String::new();
let mut text = String::new();

for instr in self.instructions.iter() {
let load_addr = instr.address().load_address(&self.target);
instr_data.resize(instr.byte_size(), 0);
instr.data(&self.target).read_raw_data(0, &mut instr_data).unwrap();
dump.clear();
text.clear();

for (i, b) in instr_data.iter().enumerate() {
if i >= MAX_INSTR_BYTES {
let _ = write!(dump, ">");
break;
}
let _ = write!(dump, "{:02X} ", b);
}
let mnemonic = instr.mnemonic(&self.target);
let operands = instr.operands(&self.target);
let comment = instr.comment(&self.target);
let comment_sep = if comment.is_empty() {
""
} else {
" ; "
};
#[rustfmt::skip]
let _ = writeln!(text, "{:08X}: {:<dumpwidth$} {:<6} {}{}{}", //.
load_addr, dump, mnemonic, operands, comment_sep, comment,
dumpwidth=MAX_INSTR_BYTES * 3 + 2
);

instructions.push( DisassembledInstruction {
address: format!("0x{:X}", load_addr),
instruction: text.clone(),
column: None,
end_column: None,
end_line: None,
instruction_bytes: None,
line: None,
location: None,
symbol: None,
} )
}

instructions
}

pub fn get_source_text(&self) -> String {
let source_location: Cow<str> = match self.start_addr.line_entry() {
Some(le) => format!("{}:{}", le.file_spec().path().display(), le.line()).into(),
Expand Down