Implement GDB/LLDB compatible server #3

Merged
SonicSwordcane merged 33 commits from debugger into main 2025-01-19 00:13:43 +00:00
4 changed files with 69 additions and 14 deletions
Showing only changes of commit 82c3104ab9 - Show all commits

View File

@ -15,8 +15,8 @@ use anyhow::Result;
use egui_toast::{Toast, ToastKind, ToastOptions}; use egui_toast::{Toast, ToastKind, ToastOptions};
use crate::{audio::Audio, graphics::TextureSink}; use crate::{audio::Audio, graphics::TextureSink};
pub use shrooms_vb_core::VBKey;
use shrooms_vb_core::{Sim, EXPECTED_FRAME_SIZE}; use shrooms_vb_core::{Sim, EXPECTED_FRAME_SIZE};
pub use shrooms_vb_core::{VBKey, VBRegister};
mod shrooms_vb_core; mod shrooms_vb_core;
@ -390,6 +390,13 @@ impl Emulator {
} }
} }
} }
EmulatorCommand::ReadRegister(sim_id, register, done) => {
let Some(sim) = self.sims.get_mut(sim_id.to_index()) else {
return;
};
let value = sim.read_register(register);
let _ = done.send(value);
}
EmulatorCommand::SetAudioEnabled(p1, p2) => { EmulatorCommand::SetAudioEnabled(p1, p2) => {
self.audio_on[SimId::Player1.to_index()].store(p1, Ordering::Release); self.audio_on[SimId::Player1.to_index()].store(p1, Ordering::Release);
self.audio_on[SimId::Player2.to_index()].store(p2, Ordering::Release); self.audio_on[SimId::Player2.to_index()].store(p2, Ordering::Release);
@ -447,6 +454,7 @@ pub enum EmulatorCommand {
StopSecondSim, StopSecondSim,
Pause, Pause,
Resume, Resume,
ReadRegister(SimId, VBRegister, oneshot::Sender<u32>),
SetAudioEnabled(bool, bool), SetAudioEnabled(bool, bool),
Link, Link,
Unlink, Unlink,

View File

@ -55,6 +55,13 @@ bitflags! {
} }
} }
#[derive(Clone, Copy, Debug)]
pub enum VBRegister {
Program(u32),
System(u32),
PC,
}
type OnFrame = extern "C" fn(sim: *mut VB) -> c_int; type OnFrame = extern "C" fn(sim: *mut VB) -> c_int;
#[link(name = "vb")] #[link(name = "vb")]
@ -77,6 +84,10 @@ extern "C" {
right_stride_x: c_int, right_stride_x: c_int,
right_stride_y: c_int, right_stride_y: c_int,
); );
#[link_name = "vbGetProgramCounter"]
fn vb_get_program_counter(sim: *mut VB) -> u32;
#[link_name = "vbGetProgramRegister"]
fn vb_get_program_register(sim: *mut VB, index: c_uint) -> i32;
#[link_name = "vbGetSamples"] #[link_name = "vbGetSamples"]
fn vb_get_samples( fn vb_get_samples(
sim: *mut VB, sim: *mut VB,
@ -84,6 +95,8 @@ extern "C" {
capacity: *mut c_uint, capacity: *mut c_uint,
position: *mut c_uint, position: *mut c_uint,
) -> *mut c_void; ) -> *mut c_void;
#[link_name = "vbGetSystemRegister"]
fn vb_get_system_register(sim: *mut VB, index: c_uint) -> i32;
#[link_name = "vbGetUserData"] #[link_name = "vbGetUserData"]
fn vb_get_user_data(sim: *mut VB) -> *mut c_void; fn vb_get_user_data(sim: *mut VB) -> *mut c_void;
#[link_name = "vbInit"] #[link_name = "vbInit"]
@ -291,6 +304,16 @@ impl Sim {
pub fn set_keys(&mut self, keys: VBKey) { pub fn set_keys(&mut self, keys: VBKey) {
unsafe { vb_set_keys(self.sim, keys.bits()) }; unsafe { vb_set_keys(self.sim, keys.bits()) };
} }
pub fn read_register(&mut self, register: VBRegister) -> u32 {
match register {
VBRegister::Program(index) => unsafe {
vb_get_program_register(self.sim, index) as u32
},
VBRegister::System(index) => unsafe { vb_get_system_register(self.sim, index) as u32 },
VBRegister::PC => unsafe { vb_get_program_counter(self.sim) },
}
}
} }
impl Drop for Sim { impl Drop for Sim {

View File

@ -227,12 +227,23 @@ impl GdbConnection {
self.client.send_command(EmulatorCommand::Resume); self.client.send_command(EmulatorCommand::Resume);
// Don't send a response until we hit a breakpoint or get interrupted // Don't send a response until we hit a breakpoint or get interrupted
} else if req.match_str("p") { } else if req.match_str("p") {
let Some(register) = req.match_hex::<u32>() else { let mut read_register = || {
let register_index = req.match_hex::<usize>()?;
let register = REGISTERS.get(register_index)?.to_vb_register();
let (tx, rx) = ::oneshot::channel();
self.client.send_command(EmulatorCommand::ReadRegister(
self.sim_id,
register,
tx,
));
rx.recv().ok()
};
let Some(value) = read_register() else {
let res = self.response(); let res = self.response();
self.send(res).await?; self.send(res).await?;
continue; continue;
}; };
let res = self.response().write_hex(register); let res = self.response().write_hex(value);
self.send(res).await?; self.send(res).await?;
} else if req.match_str("m") { } else if req.match_str("m") {
let mut read_params = || { let mut read_params = || {

View File

@ -1,5 +1,7 @@
use crate::emulator::VBRegister;
pub struct RegisterInfo { pub struct RegisterInfo {
index: usize, dwarf: u32,
name: &'static str, name: &'static str,
set: &'static str, set: &'static str,
alt_name: Option<&'static str>, alt_name: Option<&'static str>,
@ -14,48 +16,59 @@ impl RegisterInfo {
} }
string.push_str(&format!( string.push_str(&format!(
";bitsize:32;offset:{};encoding:uint;format:hex;set:{};dwarf:{}", ";bitsize:32;offset:{};encoding:uint;format:hex;set:{};dwarf:{}",
self.index * 4, self.dwarf * 4,
self.set, self.set,
self.index self.dwarf
)); ));
if let Some(generic) = self.generic { if let Some(generic) = self.generic {
string.push_str(&format!(";generic:{}", generic)); string.push_str(&format!(";generic:{}", generic));
} }
string string
} }
pub fn to_vb_register(&self) -> VBRegister {
match self.dwarf {
0..32 => VBRegister::Program(self.dwarf),
32..40 => VBRegister::System(self.dwarf - 32),
40..42 => VBRegister::System(self.dwarf - 16),
42..45 => VBRegister::System(self.dwarf - 13),
45 => VBRegister::PC,
other => panic!("unexpected DWARF register {other}"),
}
}
} }
macro_rules! register { macro_rules! register {
($set:expr, $index:expr, $name:expr) => { ($set:expr, $dwarf:expr, $name:expr) => {
RegisterInfo { RegisterInfo {
index: $index, dwarf: $dwarf,
name: $name, name: $name,
set: $set, set: $set,
alt_name: None, alt_name: None,
generic: None, generic: None,
} }
}; };
($set:expr, $index:expr, $name:expr, alt: $alt:expr) => { ($set:expr, $dwarf:expr, $name:expr, alt: $alt:expr) => {
RegisterInfo { RegisterInfo {
index: $index, dwarf: $dwarf,
name: $name, name: $name,
set: $set, set: $set,
alt_name: Some($alt), alt_name: Some($alt),
generic: None, generic: None,
} }
}; };
($set:expr, $index:expr, $name:expr, generic: $generic:expr) => { ($set:expr, $dwarf:expr, $name:expr, generic: $generic:expr) => {
RegisterInfo { RegisterInfo {
index: $index, dwarf: $dwarf,
name: $name, name: $name,
set: $set, set: $set,
alt_name: None, alt_name: None,
generic: Some($generic), generic: Some($generic),
} }
}; };
($set:expr, $index:expr, $name:expr, alt: $alt:expr, generic: $generic:expr) => { ($set:expr, $dwarf:expr, $name:expr, alt: $alt:expr, generic: $generic:expr) => {
RegisterInfo { RegisterInfo {
index: $index, dwarf: $dwarf,
name: $name, name: $name,
set: $set, set: $set,
alt_name: Some($alt), alt_name: Some($alt),