Gdb fixes

Former-commit-id: 2940580fc6b3760d77b5598b0faf72a773183304
Former-commit-id: cf3f361178c75d4e39832774bdd052ef8aab6be8
This commit is contained in:
Michel Heily 2022-09-19 00:10:55 +03:00
parent 3bb480c120
commit c8c1cdd57b
9 changed files with 205 additions and 130 deletions

View file

@ -1,11 +1,18 @@
use std::fmt;
use log::debug; use log::debug;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use bit::BitIndex;
use num::FromPrimitive;
use ansi_term::{Colour, Style};
use rustboyadvance_utils::{Shared, WeakPointer};
pub use super::exception::Exception; pub use super::exception::Exception;
use super::reg_string;
use super::{arm::ArmCond, psr::RegPSR, Addr, CpuMode, CpuState}; use super::{arm::ArmCond, psr::RegPSR, Addr, CpuMode, CpuState};
use rustboyadvance_utils::{Shared, WeakPointer};
use super::memory::{MemoryAccess, MemoryInterface}; use super::memory::{MemoryAccess, MemoryInterface};
use MemoryAccess::*; use MemoryAccess::*;
@ -37,18 +44,12 @@ cfg_if! {
use super::DecodedInstruction; use super::DecodedInstruction;
use super::arm::ArmInstruction; use super::arm::ArmInstruction;
use super::thumb::ThumbInstruction; use super::thumb::ThumbInstruction;
use super::reg_string;
use std::fmt;
use ansi_term::{Colour, Style};
} else { } else {
} }
} }
use bit::BitIndex;
use num::FromPrimitive;
pub enum CpuAction { pub enum CpuAction {
AdvancePC(MemoryAccess), AdvancePC(MemoryAccess),
PipelineFlushed, PipelineFlushed,
@ -104,7 +105,7 @@ impl Default for DebuggerState {
} }
} }
#[derive(Clone, Debug)] #[derive(Clone)]
pub struct Arm7tdmiCore<I: MemoryInterface> { pub struct Arm7tdmiCore<I: MemoryInterface> {
pub pc: u32, pub pc: u32,
pub bus: Shared<I>, pub bus: Shared<I>,
@ -506,6 +507,29 @@ impl<I: MemoryInterface> Arm7tdmiCore<I> {
} }
} }
impl<I: MemoryInterface> fmt::Debug for Arm7tdmiCore<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "ARM7TDMI Core Status:")?;
writeln!(f, "\tCPSR: {}", self.cpsr)?;
writeln!(f, "\tGeneral Purpose Registers:")?;
let reg_normal_style = Style::new().bold();
let gpr = self.copy_registers();
for i in 0..15 {
let mut reg_name = reg_string(i).to_string();
reg_name.make_ascii_uppercase();
let entry = format!("\t{:-3} = 0x{:08x}", reg_name, gpr[i]);
write!(
f,
"{}{}",
reg_normal_style.paint(entry),
if (i + 1) % 4 == 0 { "\n" } else { "" }
)?;
}
let pc = format!("\tPC = 0x{:08x}", self.get_next_pc());
writeln!(f, "{}", reg_normal_style.paint(pc))
}
}
#[cfg(feature = "debugger")] #[cfg(feature = "debugger")]
impl<I: MemoryInterface> fmt::Display for Core<I> { impl<I: MemoryInterface> fmt::Display for Core<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

View file

@ -41,7 +41,7 @@ impl<I: MemoryGdbInterface> SingleThreadBase for Arm7tdmiCore<I> {
&mut self, &mut self,
regs: &mut gdbstub_arch::arm::reg::ArmCoreRegs, regs: &mut gdbstub_arch::arm::reg::ArmCoreRegs,
) -> TargetResult<(), Self> { ) -> TargetResult<(), Self> {
regs.pc = self.get_next_pc(); regs.pc = self.pc;
regs.lr = self.get_reg(REG_LR); regs.lr = self.get_reg(REG_LR);
regs.sp = self.get_reg(REG_SP); regs.sp = self.get_reg(REG_SP);
regs.r[..].copy_from_slice(&self.gpr[..13]); regs.r[..].copy_from_slice(&self.gpr[..13]);
@ -56,7 +56,7 @@ impl<I: MemoryGdbInterface> SingleThreadBase for Arm7tdmiCore<I> {
self.set_reg(REG_PC, regs.pc); self.set_reg(REG_PC, regs.pc);
self.set_reg(REG_LR, regs.lr); self.set_reg(REG_LR, regs.lr);
self.set_reg(REG_SP, regs.sp); self.set_reg(REG_SP, regs.sp);
self.gpr.copy_from_slice(&regs.r); self.gpr[..13].copy_from_slice(&regs.r);
self.cpsr.set(regs.cpsr); self.cpsr.set(regs.cpsr);
Ok(()) Ok(())
} }

View file

@ -6,7 +6,7 @@ use arm7tdmi::gdbstub::stub::SingleThreadStopReason;
use bincode; use bincode;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::gdb_support::{gdb_thread::start_gdb_server_thread, DebuggerState}; use crate::gdb_support::{gdb_thread::start_gdb_server_thread, DebuggerRequestHandler};
use super::cartridge::Cartridge; use super::cartridge::Cartridge;
use super::dma::DmaController; use super::dma::DmaController;
@ -24,13 +24,13 @@ use arm7tdmi::{self, Arm7tdmiCore};
use rustboyadvance_utils::Shared; use rustboyadvance_utils::Shared;
pub struct GameBoyAdvance { pub struct GameBoyAdvance {
pub(crate) cpu: Box<Arm7tdmiCore<SysBus>>, pub cpu: Box<Arm7tdmiCore<SysBus>>,
pub(crate) sysbus: Shared<SysBus>, pub(crate) sysbus: Shared<SysBus>,
pub(crate) io_devs: Shared<IoDevices>, pub(crate) io_devs: Shared<IoDevices>,
pub(crate) scheduler: SharedScheduler, pub(crate) scheduler: SharedScheduler,
interrupt_flags: SharedInterruptFlags, interrupt_flags: SharedInterruptFlags,
audio_interface: DynAudioInterface, audio_interface: DynAudioInterface,
pub(crate) debugger: Option<DebuggerState>, pub(crate) debugger: Option<DebuggerRequestHandler>,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -251,17 +251,12 @@ impl GameBoyAdvance {
/// Recv & handle messages from the debugger, and return if we are stopped or not /// Recv & handle messages from the debugger, and return if we are stopped or not
pub fn debugger_run(&mut self) { pub fn debugger_run(&mut self) {
let mut should_stop = false; let mut should_interrupt_frame = false;
let debugger = self.debugger.take().expect("debugger should be None here"); let debugger = self.debugger.take().expect("debugger should be None here");
let debugger = debugger self.debugger = debugger.handle_incoming_requests(self, &mut should_interrupt_frame);
.handle_message(self, &mut should_stop)
.map_err(|_| "Failed to handle message")
.unwrap();
self.debugger = debugger;
if let Some(debugger) = &mut self.debugger { if let Some(debugger) = &mut self.debugger {
if should_stop { if should_interrupt_frame {
debugger.notify_stop_reason(SingleThreadStopReason::DoneStep); debugger.notify_stop_reason(SingleThreadStopReason::DoneStep);
} else { } else {
self.frame_interruptible(); self.frame_interruptible();
@ -277,7 +272,7 @@ impl GameBoyAdvance {
} }
#[inline] #[inline]
pub fn cpu_step(&mut self) { pub(crate) fn cpu_step(&mut self) {
if self.io_devs.intc.irq_pending() { if self.io_devs.intc.irq_pending() {
self.cpu.irq(); self.cpu.irq();
self.io_devs.haltcnt = HaltState::Running; self.io_devs.haltcnt = HaltState::Running;

View file

@ -1,9 +1,9 @@
use std::result;
use std::sync::{Arc, Condvar, Mutex}; use std::sync::{Arc, Condvar, Mutex};
use std::thread::JoinHandle; use std::thread::JoinHandle;
type SendSync<T> = Arc<Mutex<T>>; type SendSync<T> = Arc<Mutex<T>>;
use arm7tdmi::gdbstub::common::Signal;
use arm7tdmi::gdbstub::stub::{DisconnectReason, SingleThreadStopReason}; use arm7tdmi::gdbstub::stub::{DisconnectReason, SingleThreadStopReason};
use arm7tdmi::gdbstub::target::TargetError; use arm7tdmi::gdbstub::target::TargetError;
use arm7tdmi::gdbstub::target::{ext::base::singlethread::SingleThreadBase, Target}; use arm7tdmi::gdbstub::target::{ext::base::singlethread::SingleThreadBase, Target};
@ -20,7 +20,7 @@ mod target;
use crate::GameBoyAdvance; use crate::GameBoyAdvance;
#[derive(Debug)] #[derive(Debug)]
pub(crate) enum DebuggerMessage { pub(crate) enum DebuggerRequest {
ReadRegs(SendSync<ArmCoreRegs>), ReadRegs(SendSync<ArmCoreRegs>),
WriteRegs(ArmCoreRegs), WriteRegs(ArmCoreRegs),
ReadAddrs(Addr, SendSync<Box<[u8]>>), ReadAddrs(Addr, SendSync<Box<[u8]>>),
@ -28,15 +28,15 @@ pub(crate) enum DebuggerMessage {
WriteAddrs(Addr, Box<[u8]>), WriteAddrs(Addr, Box<[u8]>),
AddSwBreakpoint(Addr), AddSwBreakpoint(Addr),
DelSwBreakpoint(Addr), DelSwBreakpoint(Addr),
Stop, Interrupt,
Resume, Resume,
SingleStep, SingleStep,
Disconnected(DisconnectReason), Disconnected(DisconnectReason),
} }
pub struct DebuggerTarget { pub struct DebuggerTarget {
tx: Sender<DebuggerMessage>, tx: Sender<DebuggerRequest>,
operation_signal: Arc<(Mutex<bool>, Condvar)>, request_complete_signal: Arc<(Mutex<bool>, Condvar)>,
stop_signal: Arc<(Mutex<SingleThreadStopReason<u32>>, Condvar)>, stop_signal: Arc<(Mutex<SingleThreadStopReason<u32>>, Condvar)>,
memory_map: String, memory_map: String,
} }
@ -44,7 +44,7 @@ pub struct DebuggerTarget {
impl DebuggerTarget { impl DebuggerTarget {
#[inline] #[inline]
pub fn wait_for_operation(&mut self) { pub fn wait_for_operation(&mut self) {
let (lock, cvar) = &*self.operation_signal; let (lock, cvar) = &*self.request_complete_signal;
let mut finished = lock.lock().unwrap(); let mut finished = lock.lock().unwrap();
while !*finished { while !*finished {
finished = cvar.wait(finished).unwrap(); finished = cvar.wait(finished).unwrap();
@ -53,39 +53,39 @@ impl DebuggerTarget {
} }
} }
pub(crate) struct DebuggerState { pub(crate) struct DebuggerRequestHandler {
rx: Receiver<DebuggerMessage>, rx: Receiver<DebuggerRequest>,
operation_signal: Arc<(Mutex<bool>, Condvar)>, request_complete_signal: Arc<(Mutex<bool>, Condvar)>,
stop_signal: Arc<(Mutex<SingleThreadStopReason<u32>>, Condvar)>, stop_signal: Arc<(Mutex<SingleThreadStopReason<u32>>, Condvar)>,
thread: JoinHandle<()>, thread: JoinHandle<()>,
stopped: bool, stopped: bool,
} }
impl DebuggerState { enum DebuggerStatus {
pub fn handle_message( RequestComplete,
mut self, ResumeRequested,
gba: &mut GameBoyAdvance, StopRequested,
should_stop: &mut bool, Disconnected(DisconnectReason),
) -> Result<Option<DebuggerState>, TargetError<<DebuggerTarget as Target>::Error>> {
if self.thread.is_finished() {
warn!("gdb server thread unexpectdly died");
*should_stop = true;
self.thread.join().unwrap();
return Ok(None);
} }
if let Ok(msg) = self.rx.try_recv() {
use DebuggerMessage::*; impl DebuggerRequestHandler {
let mut result = match msg { fn handle_request(
&mut self,
gba: &mut GameBoyAdvance,
req: &mut DebuggerRequest,
) -> Result<DebuggerStatus, TargetError<<DebuggerTarget as Target>::Error>> {
use DebuggerRequest::*;
match req {
ReadRegs(regs) => { ReadRegs(regs) => {
let mut regs = regs.lock().unwrap(); let mut regs = regs.lock().unwrap();
gba.cpu.read_registers(&mut regs)?; gba.cpu.read_registers(&mut regs)?;
debug!("Debugger requested to read regs: {:?}", regs); debug!("Debugger requested to read regs: {:?}", regs);
Ok(Some(self)) Ok(DebuggerStatus::RequestComplete)
} }
WriteRegs(regs) => { WriteRegs(regs) => {
debug!("Debugger requested to write regs: {:?}", regs); debug!("Debugger requested to write regs: {:?}", regs);
gba.cpu.write_registers(&regs)?; gba.cpu.write_registers(regs)?;
Ok(Some(self)) Ok(DebuggerStatus::RequestComplete)
} }
ReadAddrs(addr, data) => { ReadAddrs(addr, data) => {
let mut data = data.lock().unwrap(); let mut data = data.lock().unwrap();
@ -94,8 +94,8 @@ impl DebuggerState {
data.len(), data.len(),
addr addr
); );
gba.cpu.read_addrs(addr, &mut data)?; gba.cpu.read_addrs(*addr, &mut data)?;
Ok(Some(self)) Ok(DebuggerStatus::RequestComplete)
} }
WriteAddrs(addr, data) => { WriteAddrs(addr, data) => {
debug!( debug!(
@ -103,55 +103,89 @@ impl DebuggerState {
data.len(), data.len(),
addr addr
); );
gba.cpu.write_addrs(addr, &data)?; gba.cpu.write_addrs(*addr, &data)?;
Ok(Some(self)) Ok(DebuggerStatus::RequestComplete)
} }
Stop => { Interrupt => {
debug!("Debugger requested stopped"); debug!("Debugger requested stopped");
self.stopped = true; self.notify_stop_reason(SingleThreadStopReason::Signal(Signal::SIGINT));
Ok(Some(self)) Ok(DebuggerStatus::StopRequested)
} }
Resume => { Resume => {
debug!("Debugger requested resume"); debug!("Debugger requested resume");
self.stopped = false; self.stopped = false;
Ok(Some(self)) Ok(DebuggerStatus::ResumeRequested)
} }
SingleStep => { SingleStep => {
debug!("Debugger requested single step"); debug!("Debugger requested single step");
gba.run::<true>(1); gba.cpu_step();
self.notify_stop_reason(SingleThreadStopReason::DoneStep); let stop_reason = SingleThreadStopReason::DoneStep;
self.stopped = true; self.notify_stop_reason(stop_reason);
Ok(Some(self)) Ok(DebuggerStatus::StopRequested)
} }
AddSwBreakpoint(addr) => { AddSwBreakpoint(addr) => {
gba.cpu.add_breakpoint(addr); gba.cpu.add_breakpoint(*addr);
Ok(Some(self)) Ok(DebuggerStatus::RequestComplete)
} }
DelSwBreakpoint(addr) => { DelSwBreakpoint(addr) => {
gba.cpu.del_breakpoint(addr); gba.cpu.del_breakpoint(*addr);
Ok(Some(self)) Ok(DebuggerStatus::RequestComplete)
} }
Disconnected(reason) => { Disconnected(reason) => Ok(DebuggerStatus::Disconnected(*reason)),
}
}
fn terminate(mut self, should_interrupt_frame: &mut bool) -> Option<DebuggerRequestHandler> {
self.notify_stop_reason(SingleThreadStopReason::Exited(1));
self.thread.join().unwrap();
self.stopped = true;
*should_interrupt_frame = true;
None
}
pub fn handle_incoming_requests(
mut self,
gba: &mut GameBoyAdvance,
should_interrupt_frame: &mut bool,
) -> Option<DebuggerRequestHandler> {
if self.thread.is_finished() {
warn!("gdb server thread unexpectdly died");
return self.terminate(should_interrupt_frame);
}
while let Ok(mut req) = self.rx.try_recv() {
match self.handle_request(gba, &mut req) {
Ok(DebuggerStatus::RequestComplete) => {
self.notify_request_complete();
}
Ok(DebuggerStatus::StopRequested) => {
self.stopped = true;
self.notify_request_complete();
}
Ok(DebuggerStatus::ResumeRequested) => {
self.stopped = false;
self.notify_request_complete();
}
Ok(DebuggerStatus::Disconnected(reason)) => {
debug!("Debugger disconnected due to {:?}", reason); debug!("Debugger disconnected due to {:?}", reason);
debug!("closing gdbserver thread"); debug!("closing gdbserver thread");
self.thread.join().unwrap(); return self.terminate(should_interrupt_frame);
Ok(None)
} }
};
if let Ok(Some(result)) = &mut result { Err(_) => {
let (lock, cvar) = &*result.operation_signal; error!("An error occured while handling debug request {:?}", req);
return self.terminate(should_interrupt_frame);
}
}
}
*should_interrupt_frame = self.stopped;
Some(self)
}
fn notify_request_complete(&mut self) {
let (lock, cvar) = &*self.request_complete_signal;
let mut finished = lock.lock().unwrap(); let mut finished = lock.lock().unwrap();
*finished = true; *finished = true;
cvar.notify_one(); cvar.notify_one();
*should_stop = result.stopped;
} else {
*should_stop = true;
}
result
} else {
*should_stop = self.stopped;
Ok(Some(self))
}
} }
pub fn notify_stop_reason(&mut self, reason: SingleThreadStopReason<u32>) { pub fn notify_stop_reason(&mut self, reason: SingleThreadStopReason<u32>) {

View file

@ -6,7 +6,7 @@ use arm7tdmi::gdb::gdbstub::{
target::Target, target::Target,
}; };
use super::{DebuggerMessage, DebuggerTarget}; use super::{DebuggerRequest, DebuggerTarget};
pub struct DebuggerEventLoop {} pub struct DebuggerEventLoop {}
@ -54,7 +54,7 @@ impl run_blocking::BlockingEventLoop for DebuggerEventLoop {
target: &mut DebuggerTarget, target: &mut DebuggerTarget,
) -> Result<Option<SingleThreadStopReason<u32>>, <DebuggerTarget as Target>::Error> { ) -> Result<Option<SingleThreadStopReason<u32>>, <DebuggerTarget as Target>::Error> {
info!("on_interrupt: sending stop message"); info!("on_interrupt: sending stop message");
target.tx.send(DebuggerMessage::Stop).unwrap(); target.tx.send(DebuggerRequest::Interrupt).unwrap();
target.wait_for_operation(); target.wait_for_operation();
info!("Waiting for target to stop <blocking>"); info!("Waiting for target to stop <blocking>");
let (lock, cvar) = &*target.stop_signal; let (lock, cvar) = &*target.stop_signal;

View file

@ -11,21 +11,23 @@ use arm7tdmi::{
use crate::{GBAError, GameBoyAdvance}; use crate::{GBAError, GameBoyAdvance};
use super::{event_loop::DebuggerEventLoop, DebuggerMessage, DebuggerState, DebuggerTarget}; use super::{
event_loop::DebuggerEventLoop, DebuggerRequest, DebuggerRequestHandler, DebuggerTarget,
};
/// Starts a gdbserver thread /// Starts a gdbserver thread
pub(crate) fn start_gdb_server_thread( pub(crate) fn start_gdb_server_thread(
gba: &mut GameBoyAdvance, gba: &mut GameBoyAdvance,
port: u16, port: u16,
) -> Result<DebuggerState, GBAError> { ) -> Result<DebuggerRequestHandler, GBAError> {
let (tx, rx) = crossbeam::channel::unbounded(); let (tx, rx) = crossbeam::channel::unbounded();
let operation_signal = Arc::new((Mutex::new(false), Condvar::new())); let request_complete_signal = Arc::new((Mutex::new(false), Condvar::new()));
let stop_signal = Arc::new(( let stop_signal = Arc::new((
Mutex::new(SingleThreadStopReason::Signal(Signal::SIGINT)), Mutex::new(SingleThreadStopReason::Signal(Signal::SIGINT)),
Condvar::new(), Condvar::new(),
)); ));
let stop_signal_2 = stop_signal.clone(); let stop_signal_2 = stop_signal.clone();
let operation_signal_2 = operation_signal.clone(); let request_complete_signal_2 = request_complete_signal.clone();
let memory_map = gba.sysbus.generate_memory_map_xml().unwrap(); let memory_map = gba.sysbus.generate_memory_map_xml().unwrap();
let conn = wait_for_connection(port)?; let conn = wait_for_connection(port)?;
@ -35,7 +37,7 @@ pub(crate) fn start_gdb_server_thread(
let mut target = DebuggerTarget { let mut target = DebuggerTarget {
tx, tx,
operation_signal: operation_signal_2, request_complete_signal: request_complete_signal_2,
stop_signal: stop_signal_2, stop_signal: stop_signal_2,
memory_map, memory_map,
}; };
@ -46,13 +48,13 @@ pub(crate) fn start_gdb_server_thread(
.unwrap(); .unwrap();
target target
.tx .tx
.send(DebuggerMessage::Disconnected(disconnect_reason)) .send(DebuggerRequest::Disconnected(disconnect_reason))
.unwrap(); .unwrap();
}); });
let mut debugger = DebuggerState { let mut debugger = DebuggerRequestHandler {
rx, rx,
operation_signal, request_complete_signal,
stop_signal, stop_signal,
thread, thread,
stopped: true, stopped: true,

View file

@ -12,7 +12,7 @@ use gdbstub::target::ext::breakpoints::BreakpointsOps;
use gdbstub::target::{self, Target, TargetError, TargetResult}; use gdbstub::target::{self, Target, TargetError, TargetResult};
use gdbstub_arch::arm::reg::ArmCoreRegs; use gdbstub_arch::arm::reg::ArmCoreRegs;
use super::{DebuggerMessage, DebuggerTarget}; use super::{DebuggerRequest, DebuggerTarget};
impl Target for DebuggerTarget { impl Target for DebuggerTarget {
type Error = (); type Error = ();
@ -38,7 +38,7 @@ impl SingleThreadBase for DebuggerTarget {
fn read_registers(&mut self, regs: &mut ArmCoreRegs) -> TargetResult<(), Self> { fn read_registers(&mut self, regs: &mut ArmCoreRegs) -> TargetResult<(), Self> {
let regs_copy = Arc::new(Mutex::new(ArmCoreRegs::default())); let regs_copy = Arc::new(Mutex::new(ArmCoreRegs::default()));
self.tx self.tx
.send(DebuggerMessage::ReadRegs(regs_copy.clone())) .send(DebuggerRequest::ReadRegs(regs_copy.clone()))
.unwrap(); .unwrap();
self.wait_for_operation(); self.wait_for_operation();
regs_copy.lock().unwrap().clone_into(regs); regs_copy.lock().unwrap().clone_into(regs);
@ -47,7 +47,7 @@ impl SingleThreadBase for DebuggerTarget {
fn write_registers(&mut self, regs: &ArmCoreRegs) -> TargetResult<(), Self> { fn write_registers(&mut self, regs: &ArmCoreRegs) -> TargetResult<(), Self> {
self.tx self.tx
.send(DebuggerMessage::WriteRegs(regs.clone())) .send(DebuggerRequest::WriteRegs(regs.clone()))
.unwrap(); .unwrap();
self.wait_for_operation(); self.wait_for_operation();
Ok(()) Ok(())
@ -56,7 +56,7 @@ impl SingleThreadBase for DebuggerTarget {
fn read_addrs(&mut self, start_addr: u32, data: &mut [u8]) -> TargetResult<(), Self> { fn read_addrs(&mut self, start_addr: u32, data: &mut [u8]) -> TargetResult<(), Self> {
let buffer = Arc::new(Mutex::new(vec![0; data.len()].into_boxed_slice())); let buffer = Arc::new(Mutex::new(vec![0; data.len()].into_boxed_slice()));
self.tx self.tx
.send(DebuggerMessage::ReadAddrs(start_addr, buffer.clone())) .send(DebuggerRequest::ReadAddrs(start_addr, buffer.clone()))
.unwrap(); .unwrap();
self.wait_for_operation(); self.wait_for_operation();
data.copy_from_slice(&buffer.lock().unwrap()); data.copy_from_slice(&buffer.lock().unwrap());
@ -78,7 +78,7 @@ impl SingleThreadBase for DebuggerTarget {
impl SingleThreadResume for DebuggerTarget { impl SingleThreadResume for DebuggerTarget {
fn resume(&mut self, _signal: Option<Signal>) -> Result<(), Self::Error> { fn resume(&mut self, _signal: Option<Signal>) -> Result<(), Self::Error> {
self.tx.send(DebuggerMessage::Resume).unwrap(); self.tx.send(DebuggerRequest::Resume).unwrap();
self.wait_for_operation(); self.wait_for_operation();
Ok(()) Ok(())
} }
@ -94,9 +94,7 @@ impl SingleThreadResume for DebuggerTarget {
impl SingleThreadSingleStep for DebuggerTarget { impl SingleThreadSingleStep for DebuggerTarget {
fn step(&mut self, _signal: Option<Signal>) -> Result<(), Self::Error> { fn step(&mut self, _signal: Option<Signal>) -> Result<(), Self::Error> {
self.tx.send(DebuggerMessage::SingleStep).unwrap(); self.tx.send(DebuggerRequest::SingleStep).unwrap();
self.wait_for_operation();
self.tx.send(DebuggerMessage::Stop).unwrap();
self.wait_for_operation(); self.wait_for_operation();
Ok(()) Ok(())
} }
@ -135,7 +133,7 @@ impl target::ext::breakpoints::SwBreakpoint for DebuggerTarget {
_kind: gdbstub_arch::arm::ArmBreakpointKind, _kind: gdbstub_arch::arm::ArmBreakpointKind,
) -> TargetResult<bool, Self> { ) -> TargetResult<bool, Self> {
self.tx self.tx
.send(DebuggerMessage::AddSwBreakpoint(addr)) .send(DebuggerRequest::AddSwBreakpoint(addr))
.unwrap(); .unwrap();
self.wait_for_operation(); self.wait_for_operation();
Ok(true) Ok(true)
@ -147,7 +145,7 @@ impl target::ext::breakpoints::SwBreakpoint for DebuggerTarget {
_kind: gdbstub_arch::arm::ArmBreakpointKind, _kind: gdbstub_arch::arm::ArmBreakpointKind,
) -> TargetResult<bool, Self> { ) -> TargetResult<bool, Self> {
self.tx self.tx
.send(DebuggerMessage::DelSwBreakpoint(addr)) .send(DebuggerRequest::DelSwBreakpoint(addr))
.unwrap(); .unwrap();
self.wait_for_operation(); self.wait_for_operation();
Ok(true) Ok(true)

View file

@ -95,12 +95,26 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
audio_interface, audio_interface,
)); ));
// let gba_raw_ptr = Box::into_raw(gba) as usize;
// static mut gba_raw: usize = 0;
// unsafe { gba_raw = gba_raw_ptr };
// let mut gba = unsafe {Box::from_raw(gba_raw_ptr as *mut GameBoyAdvance) };
// std::panic::set_hook(Box::new(|panic_info| {
// let gba = unsafe {Box::from_raw(gba_raw as *mut GameBoyAdvance) };
// println!("System crashed Oh No!!! {:?}", gba.cpu);
// let normal_panic = std::panic::take_hook();
// normal_panic(panic_info);
// }));
if opts.skip_bios { if opts.skip_bios {
println!("Skipping bios animation..");
gba.skip_bios(); gba.skip_bios();
} }
if opts.gdbserver { if opts.gdbserver {
todo!("gdb") gba.start_gdbserver(DEFAULT_GDB_SERVER_PORT);
} }
let mut vsync = true; let mut vsync = true;
@ -146,7 +160,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
if opts.savestate_path().is_file() { if opts.savestate_path().is_file() {
let save = read_bin_file(&opts.savestate_path())?; let save = read_bin_file(&opts.savestate_path())?;
info!("Restoring state from {:?}...", opts.savestate_path()); info!("Restoring state from {:?}...", opts.savestate_path());
gba.restore_state(&save)?; let (audio_interface, _sdl_audio_device_new) = audio::create_audio_player(&sdl_context)?;
_sdl_audio_device = _sdl_audio_device_new;
let rom = opts.read_rom()?.into_boxed_slice();
gba = Box::new(GameBoyAdvance::from_saved_state(&save, bios_bin.clone(), rom, audio_interface)?);
info!("Restored!"); info!("Restored!");
} else { } else {
info!("Savestate not created, please create one by pressing F5"); info!("Savestate not created, please create one by pressing F5");

View file

@ -1,9 +1,10 @@
use std::path::PathBuf; use std::{path::PathBuf, io};
use rustboyadvance_core::{ use rustboyadvance_core::{
cartridge::{BackupType, GamepakBuilder}, cartridge::{BackupType, GamepakBuilder},
prelude::Cartridge, prelude::Cartridge,
}; };
use rustboyadvance_utils::read_bin_file;
use structopt::StructOpt; use structopt::StructOpt;
const SAVE_TYPE_POSSIBLE_VALUES: &[&str] = const SAVE_TYPE_POSSIBLE_VALUES: &[&str] =
@ -61,4 +62,8 @@ impl Options {
pub fn rom_name(&self) -> &str { pub fn rom_name(&self) -> &str {
self.rom.file_name().unwrap().to_str().unwrap() self.rom.file_name().unwrap().to_str().unwrap()
} }
pub fn read_rom(&self) -> Result<Vec<u8>, std::io::Error> {
read_bin_file(&self.rom)
}
} }