Implement GDB/LLDB compatible server #3
|
@ -537,6 +537,12 @@ impl Emulator {
|
||||||
let value = sim.read_register(register);
|
let value = sim.read_register(register);
|
||||||
let _ = done.send(value);
|
let _ = done.send(value);
|
||||||
}
|
}
|
||||||
|
EmulatorCommand::WriteRegister(sim_id, register, value) => {
|
||||||
|
let Some(sim) = self.sims.get_mut(sim_id.to_index()) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
sim.write_register(register, value);
|
||||||
|
}
|
||||||
EmulatorCommand::ReadMemory(sim_id, start, length, mut buffer, done) => {
|
EmulatorCommand::ReadMemory(sim_id, start, length, mut buffer, done) => {
|
||||||
let Some(sim) = self.sims.get_mut(sim_id.to_index()) else {
|
let Some(sim) = self.sims.get_mut(sim_id.to_index()) else {
|
||||||
return;
|
return;
|
||||||
|
@ -631,6 +637,7 @@ pub enum EmulatorCommand {
|
||||||
DebugContinue(SimId),
|
DebugContinue(SimId),
|
||||||
DebugStep(SimId),
|
DebugStep(SimId),
|
||||||
ReadRegister(SimId, VBRegister, oneshot::Sender<u32>),
|
ReadRegister(SimId, VBRegister, oneshot::Sender<u32>),
|
||||||
|
WriteRegister(SimId, VBRegister, u32),
|
||||||
ReadMemory(SimId, u32, usize, Vec<u8>, oneshot::Sender<Vec<u8>>),
|
ReadMemory(SimId, u32, usize, Vec<u8>, oneshot::Sender<Vec<u8>>),
|
||||||
AddBreakpoint(SimId, u32),
|
AddBreakpoint(SimId, u32),
|
||||||
RemoveBreakpoint(SimId, u32),
|
RemoveBreakpoint(SimId, u32),
|
||||||
|
|
|
@ -145,6 +145,10 @@ extern "C" {
|
||||||
fn vb_set_option(sim: *mut VB, key: VBOption, value: c_int);
|
fn vb_set_option(sim: *mut VB, key: VBOption, value: c_int);
|
||||||
#[link_name = "vbSetPeer"]
|
#[link_name = "vbSetPeer"]
|
||||||
fn vb_set_peer(sim: *mut VB, peer: *mut VB);
|
fn vb_set_peer(sim: *mut VB, peer: *mut VB);
|
||||||
|
#[link_name = "vbSetProgramCounter"]
|
||||||
|
fn vb_set_program_counter(sim: *mut VB, value: u32) -> u32;
|
||||||
|
#[link_name = "vbSetProgramRegister"]
|
||||||
|
fn vb_set_program_register(sim: *mut VB, index: c_uint, value: i32) -> i32;
|
||||||
#[link_name = "vbSetReadCallback"]
|
#[link_name = "vbSetReadCallback"]
|
||||||
fn vb_set_read_callback(sim: *mut VB, callback: Option<OnRead>) -> Option<OnRead>;
|
fn vb_set_read_callback(sim: *mut VB, callback: Option<OnRead>) -> Option<OnRead>;
|
||||||
#[link_name = "vbSetSamples"]
|
#[link_name = "vbSetSamples"]
|
||||||
|
@ -154,6 +158,8 @@ extern "C" {
|
||||||
typ_: VBDataType,
|
typ_: VBDataType,
|
||||||
capacity: c_uint,
|
capacity: c_uint,
|
||||||
) -> c_int;
|
) -> c_int;
|
||||||
|
#[link_name = "vbSetSystemRegister"]
|
||||||
|
fn vb_set_system_register(sim: *mut VB, index: c_uint, value: u32) -> u32;
|
||||||
#[link_name = "vbSetUserData"]
|
#[link_name = "vbSetUserData"]
|
||||||
fn vb_set_user_data(sim: *mut VB, tag: *mut c_void);
|
fn vb_set_user_data(sim: *mut VB, tag: *mut c_void);
|
||||||
#[link_name = "vbSetWriteCallback"]
|
#[link_name = "vbSetWriteCallback"]
|
||||||
|
@ -447,6 +453,20 @@ impl Sim {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_register(&mut self, register: VBRegister, value: u32) {
|
||||||
|
match register {
|
||||||
|
VBRegister::Program(index) => unsafe {
|
||||||
|
vb_set_program_register(self.sim, index, value as i32);
|
||||||
|
},
|
||||||
|
VBRegister::System(index) => unsafe {
|
||||||
|
vb_set_system_register(self.sim, index, value);
|
||||||
|
},
|
||||||
|
VBRegister::PC => unsafe {
|
||||||
|
vb_set_program_counter(self.sim, value);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read_memory(&mut self, start: u32, length: usize, into: &mut Vec<u8>) {
|
pub fn read_memory(&mut self, start: u32, length: usize, into: &mut Vec<u8>) {
|
||||||
let mut address = start;
|
let mut address = start;
|
||||||
for _ in 0..length {
|
for _ in 0..length {
|
||||||
|
|
|
@ -318,6 +318,32 @@ impl GdbConnection {
|
||||||
} else {
|
} else {
|
||||||
self.response()
|
self.response()
|
||||||
}
|
}
|
||||||
|
} else if req.match_str("P") {
|
||||||
|
let mut write_register = || {
|
||||||
|
let register_index = req.match_hex::<usize>()?;
|
||||||
|
let register = REGISTERS.get(register_index)?.to_vb_register();
|
||||||
|
if !req.match_str("=") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let value = {
|
||||||
|
let mut buffer = [0; 4];
|
||||||
|
if !req.match_hex_bytes(&mut buffer) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
u32::from_le_bytes(buffer)
|
||||||
|
};
|
||||||
|
self.client.send_command(EmulatorCommand::WriteRegister(
|
||||||
|
self.sim_id,
|
||||||
|
register,
|
||||||
|
value,
|
||||||
|
));
|
||||||
|
Some(())
|
||||||
|
};
|
||||||
|
if let Some(()) = write_register() {
|
||||||
|
self.response().write_str("OK")
|
||||||
|
} else {
|
||||||
|
self.response()
|
||||||
|
}
|
||||||
} else if let Some(op) = req.match_some_str(["m", "x"]) {
|
} else if let Some(op) = req.match_some_str(["m", "x"]) {
|
||||||
let mut read_memory = || {
|
let mut read_memory = || {
|
||||||
let start = req.match_hex::<u64>()?;
|
let start = req.match_hex::<u64>()?;
|
||||||
|
|
|
@ -60,6 +60,20 @@ impl Request<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn match_hex_bytes(&mut self, buffer: &mut [u8]) -> bool {
|
||||||
|
if self.buffer.len() < buffer.len() * 2 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (i, item) in buffer.iter_mut().enumerate() {
|
||||||
|
match u8::from_radix_16(&self.buffer[(i * 2)..(i * 2) + 2]) {
|
||||||
|
(byte, 2) => *item = byte,
|
||||||
|
_ => return false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
self.buffer = self.buffer.split_at(buffer.len()).1;
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RequestSource<R> {
|
pub struct RequestSource<R> {
|
||||||
|
|
Loading…
Reference in New Issue