Add scaffolding for multiple threads

This commit is contained in:
Tad Hardesty 2020-09-23 20:07:24 -07:00
parent cd99c8b665
commit 1da4eb3246
3 changed files with 64 additions and 20 deletions

View file

@ -13,10 +13,15 @@ impl Debugger {
let extools = self.extools.get()?;
guard!(let Some(frame_id) = params.frameId else {
return Err(Box::new(GenericError("Must select a stack frame to evaluate in")));
});
let (thread, frame_no) = extools.get_thread_by_frame_id(frame_id)?;
if input.starts_with('#') {
if input == "#dis" || input == "#disassemble" {
let thread = extools.get_default_thread()?;
guard!(let Some(frame) = thread.call_stack.get(params.frameId.unwrap_or(0) as usize) else {
guard!(let Some(frame) = thread.call_stack.get(frame_no) else {
return Err(Box::new(GenericError("Stack frame out of range")));
});

View file

@ -196,8 +196,8 @@ impl Extools {
(extools, thread)
}
pub fn get_default_thread(&self) -> Result<ThreadInfo, Box<dyn Error>> {
self.get_thread(0)
pub fn get_all_threads(&self) -> std::sync::MutexGuard<HashMap<i64, ThreadInfo>> {
self.threads.lock().unwrap()
}
pub fn get_thread(&self, thread_id: i64) -> Result<ThreadInfo, Box<dyn Error>> {
@ -205,6 +205,16 @@ impl Extools {
.ok_or_else(|| Box::new(super::GenericError("Getting call stack failed")) as Box<dyn Error>)
}
pub fn get_thread_by_frame_id(&self, frame_id: i64) -> Result<(ThreadInfo, usize), Box<dyn Error>> {
let frame_id = frame_id as usize;
let threads = self.threads.lock().unwrap();
let thread_id = (frame_id % threads.len()) as i64;
let frame_no = frame_id / threads.len();
let thread = threads.get(&thread_id).cloned()
.ok_or_else(|| Box::new(super::GenericError("Getting call stack failed")) as Box<dyn Error>)?;
Ok((thread, frame_no))
}
pub fn bytecode(&mut self, proc_ref: &str, override_id: usize) -> &[DisassembledInstruction] {
let Extools { bytecode, sender, seq: _seq, bytecode_rx, .. } = self;
bytecode.entry((proc_ref.to_owned(), override_id)).or_insert_with(|| {
@ -402,6 +412,22 @@ impl ExtoolsThread {
debug_output!(in self.seq, "[extools] Dropping {:?}", _e);
}
}
fn stopped(&self, base: dap_types::StoppedEvent) {
for &k in self.threads.lock().unwrap().keys() {
if k != 0 {
self.seq.issue_event(dap_types::StoppedEvent {
reason: "sleep".to_owned(),
threadId: Some(k),
.. Default::default()
});
}
}
self.seq.issue_event(dap_types::StoppedEvent {
threadId: Some(0),
.. base
});
}
}
handle_extools! {
@ -420,25 +446,22 @@ handle_extools! {
on BreakpointHit(&mut self, hit) {
match hit.reason {
BreakpointHitReason::Step => {
self.seq.issue_event(dap_types::StoppedEvent {
self.stopped(dap_types::StoppedEvent {
reason: dap_types::StoppedEvent::REASON_STEP.to_owned(),
threadId: Some(0),
.. Default::default()
});
}
BreakpointHitReason::Pause => {
self.seq.issue_event(dap_types::StoppedEvent {
self.stopped(dap_types::StoppedEvent {
reason: dap_types::StoppedEvent::REASON_PAUSE.to_owned(),
description: Some("Paused by request".to_owned()),
threadId: Some(0),
.. Default::default()
})
}
_ => {
debug_output!(in self.seq, "[extools] {}#{}@{} hit", hit.proc, hit.override_id, hit.offset);
self.seq.issue_event(dap_types::StoppedEvent {
self.stopped(dap_types::StoppedEvent {
reason: dap_types::StoppedEvent::REASON_BREAKPOINT.to_owned(),
threadId: Some(0),
.. Default::default()
});
}
@ -447,10 +470,9 @@ handle_extools! {
on Runtime(&mut self, runtime) {
output!(in self.seq, "[extools] Runtime in {}: {}", runtime.proc, runtime.message);
self.seq.issue_event(dap_types::StoppedEvent {
self.stopped(dap_types::StoppedEvent {
reason: dap_types::StoppedEvent::REASON_EXCEPTION.to_owned(),
text: Some(runtime.message.clone()),
threadId: Some(0),
.. Default::default()
});
self.queue(&self.runtime_tx, runtime);

View file

@ -531,7 +531,7 @@ handle_request! {
for (i, ex_frame) in thread.call_stack.into_iter().enumerate() {
let mut dap_frame = StackFrame {
name: ex_frame.proc.clone(),
id: i as i64,
id: (i * extools.get_all_threads().len()) as i64 + params.threadId,
instructionPointerReference: Some(format!("{}@{}#{}", ex_frame.proc, ex_frame.override_id, ex_frame.offset)),
.. Default::default()
};
@ -588,9 +588,14 @@ handle_request! {
on Scopes(&mut self, ScopesArguments { frameId }) {
let extools = self.extools.get()?;
let thread = extools.get_default_thread()?;
guard!(let Some(frame) = thread.call_stack.get(frameId as usize) else {
return Err(Box::new(GenericError("Stack frame out of range")));
let frame_id = frameId as usize;
let threads = extools.get_all_threads();
let thread_id = (frame_id % threads.len()) as i64;
let frame_no = frame_id / threads.len();
guard!(let Some(frame) = threads[&thread_id].call_stack.get(frame_no) else {
return Err(Box::new(GenericError2(format!("Stack frame out of range: {} (thread {}, depth {})", frameId, thread_id, frame_no))));
});
ScopesResponse {
@ -674,12 +679,11 @@ handle_request! {
}
// Stack frame, arguments or locals
let frame_idx = (params.variablesReference - 1) / 2;
let frame_id = (params.variablesReference - 1) / 2;
let mod2 = params.variablesReference % 2;
// TODO: variablesReference should be different based on thread ID
let thread = extools.get_default_thread()?;
guard!(let Some(frame) = thread.call_stack.get(frame_idx as usize) else {
let (thread, frame_no) = extools.get_thread_by_frame_id(frame_id)?;
guard!(let Some(frame) = thread.call_stack.get(frame_no) else {
return Err(Box::new(GenericError("Stack frame out of range")));
});
@ -944,6 +948,19 @@ impl std::fmt::Display for GenericError {
}
}
#[derive(Debug)]
pub struct GenericError2(String);
impl Error for GenericError2 {
fn description(&self) -> &str { &self.0 }
}
impl std::fmt::Display for GenericError2 {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
fmt.write_str(&self.0)
}
}
// ----------------------------------------------------------------------------
// Implementation-specific DAP extensions.