Gdb fixes
Former-commit-id: 2940580fc6b3760d77b5598b0faf72a773183304 Former-commit-id: cf3f361178c75d4e39832774bdd052ef8aab6be8
This commit is contained in:
parent
3bb480c120
commit
c8c1cdd57b
|
@ -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 {
|
||||||
|
|
|
@ -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(®s.r);
|
self.gpr[..13].copy_from_slice(®s.r);
|
||||||
self.cpsr.set(regs.cpsr);
|
self.cpsr.set(regs.cpsr);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,105 +53,139 @@ 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,
|
||||||
|
ResumeRequested,
|
||||||
|
StopRequested,
|
||||||
|
Disconnected(DisconnectReason),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebuggerRequestHandler {
|
||||||
|
fn handle_request(
|
||||||
|
&mut self,
|
||||||
|
gba: &mut GameBoyAdvance,
|
||||||
|
req: &mut DebuggerRequest,
|
||||||
|
) -> Result<DebuggerStatus, TargetError<<DebuggerTarget as Target>::Error>> {
|
||||||
|
use DebuggerRequest::*;
|
||||||
|
match req {
|
||||||
|
ReadRegs(regs) => {
|
||||||
|
let mut regs = regs.lock().unwrap();
|
||||||
|
gba.cpu.read_registers(&mut regs)?;
|
||||||
|
debug!("Debugger requested to read regs: {:?}", regs);
|
||||||
|
Ok(DebuggerStatus::RequestComplete)
|
||||||
|
}
|
||||||
|
WriteRegs(regs) => {
|
||||||
|
debug!("Debugger requested to write regs: {:?}", regs);
|
||||||
|
gba.cpu.write_registers(regs)?;
|
||||||
|
Ok(DebuggerStatus::RequestComplete)
|
||||||
|
}
|
||||||
|
ReadAddrs(addr, data) => {
|
||||||
|
let mut data = data.lock().unwrap();
|
||||||
|
debug!(
|
||||||
|
"Debugger requested to read {} bytes from 0x{:08x}",
|
||||||
|
data.len(),
|
||||||
|
addr
|
||||||
|
);
|
||||||
|
gba.cpu.read_addrs(*addr, &mut data)?;
|
||||||
|
Ok(DebuggerStatus::RequestComplete)
|
||||||
|
}
|
||||||
|
WriteAddrs(addr, data) => {
|
||||||
|
debug!(
|
||||||
|
"Debugger requested to write {} bytes at 0x{:08x}",
|
||||||
|
data.len(),
|
||||||
|
addr
|
||||||
|
);
|
||||||
|
gba.cpu.write_addrs(*addr, &data)?;
|
||||||
|
Ok(DebuggerStatus::RequestComplete)
|
||||||
|
}
|
||||||
|
Interrupt => {
|
||||||
|
debug!("Debugger requested stopped");
|
||||||
|
self.notify_stop_reason(SingleThreadStopReason::Signal(Signal::SIGINT));
|
||||||
|
Ok(DebuggerStatus::StopRequested)
|
||||||
|
}
|
||||||
|
Resume => {
|
||||||
|
debug!("Debugger requested resume");
|
||||||
|
self.stopped = false;
|
||||||
|
Ok(DebuggerStatus::ResumeRequested)
|
||||||
|
}
|
||||||
|
SingleStep => {
|
||||||
|
debug!("Debugger requested single step");
|
||||||
|
gba.cpu_step();
|
||||||
|
let stop_reason = SingleThreadStopReason::DoneStep;
|
||||||
|
self.notify_stop_reason(stop_reason);
|
||||||
|
Ok(DebuggerStatus::StopRequested)
|
||||||
|
}
|
||||||
|
AddSwBreakpoint(addr) => {
|
||||||
|
gba.cpu.add_breakpoint(*addr);
|
||||||
|
Ok(DebuggerStatus::RequestComplete)
|
||||||
|
}
|
||||||
|
DelSwBreakpoint(addr) => {
|
||||||
|
gba.cpu.del_breakpoint(*addr);
|
||||||
|
Ok(DebuggerStatus::RequestComplete)
|
||||||
|
}
|
||||||
|
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,
|
mut self,
|
||||||
gba: &mut GameBoyAdvance,
|
gba: &mut GameBoyAdvance,
|
||||||
should_stop: &mut bool,
|
should_interrupt_frame: &mut bool,
|
||||||
) -> Result<Option<DebuggerState>, TargetError<<DebuggerTarget as Target>::Error>> {
|
) -> Option<DebuggerRequestHandler> {
|
||||||
if self.thread.is_finished() {
|
if self.thread.is_finished() {
|
||||||
warn!("gdb server thread unexpectdly died");
|
warn!("gdb server thread unexpectdly died");
|
||||||
*should_stop = true;
|
return self.terminate(should_interrupt_frame);
|
||||||
self.thread.join().unwrap();
|
|
||||||
return Ok(None);
|
|
||||||
}
|
}
|
||||||
if let Ok(msg) = self.rx.try_recv() {
|
while let Ok(mut req) = self.rx.try_recv() {
|
||||||
use DebuggerMessage::*;
|
match self.handle_request(gba, &mut req) {
|
||||||
let mut result = match msg {
|
Ok(DebuggerStatus::RequestComplete) => {
|
||||||
ReadRegs(regs) => {
|
self.notify_request_complete();
|
||||||
let mut regs = regs.lock().unwrap();
|
|
||||||
gba.cpu.read_registers(&mut regs)?;
|
|
||||||
debug!("Debugger requested to read regs: {:?}", regs);
|
|
||||||
Ok(Some(self))
|
|
||||||
}
|
}
|
||||||
WriteRegs(regs) => {
|
Ok(DebuggerStatus::StopRequested) => {
|
||||||
debug!("Debugger requested to write regs: {:?}", regs);
|
|
||||||
gba.cpu.write_registers(®s)?;
|
|
||||||
Ok(Some(self))
|
|
||||||
}
|
|
||||||
ReadAddrs(addr, data) => {
|
|
||||||
let mut data = data.lock().unwrap();
|
|
||||||
debug!(
|
|
||||||
"Debugger requested to read {} bytes from 0x{:08x}",
|
|
||||||
data.len(),
|
|
||||||
addr
|
|
||||||
);
|
|
||||||
gba.cpu.read_addrs(addr, &mut data)?;
|
|
||||||
Ok(Some(self))
|
|
||||||
}
|
|
||||||
WriteAddrs(addr, data) => {
|
|
||||||
debug!(
|
|
||||||
"Debugger requested to write {} bytes at 0x{:08x}",
|
|
||||||
data.len(),
|
|
||||||
addr
|
|
||||||
);
|
|
||||||
gba.cpu.write_addrs(addr, &data)?;
|
|
||||||
Ok(Some(self))
|
|
||||||
}
|
|
||||||
Stop => {
|
|
||||||
debug!("Debugger requested stopped");
|
|
||||||
self.stopped = true;
|
self.stopped = true;
|
||||||
Ok(Some(self))
|
self.notify_request_complete();
|
||||||
}
|
}
|
||||||
Resume => {
|
Ok(DebuggerStatus::ResumeRequested) => {
|
||||||
debug!("Debugger requested resume");
|
|
||||||
self.stopped = false;
|
self.stopped = false;
|
||||||
Ok(Some(self))
|
self.notify_request_complete();
|
||||||
}
|
}
|
||||||
SingleStep => {
|
Ok(DebuggerStatus::Disconnected(reason)) => {
|
||||||
debug!("Debugger requested single step");
|
|
||||||
gba.run::<true>(1);
|
|
||||||
self.notify_stop_reason(SingleThreadStopReason::DoneStep);
|
|
||||||
self.stopped = true;
|
|
||||||
Ok(Some(self))
|
|
||||||
}
|
|
||||||
AddSwBreakpoint(addr) => {
|
|
||||||
gba.cpu.add_breakpoint(addr);
|
|
||||||
Ok(Some(self))
|
|
||||||
}
|
|
||||||
DelSwBreakpoint(addr) => {
|
|
||||||
gba.cpu.del_breakpoint(addr);
|
|
||||||
Ok(Some(self))
|
|
||||||
}
|
|
||||||
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)
|
}
|
||||||
|
|
||||||
|
Err(_) => {
|
||||||
|
error!("An error occured while handling debug request {:?}", req);
|
||||||
|
return self.terminate(should_interrupt_frame);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
if let Ok(Some(result)) = &mut result {
|
|
||||||
let (lock, cvar) = &*result.operation_signal;
|
|
||||||
let mut finished = lock.lock().unwrap();
|
|
||||||
*finished = true;
|
|
||||||
cvar.notify_one();
|
|
||||||
*should_stop = result.stopped;
|
|
||||||
} else {
|
|
||||||
*should_stop = true;
|
|
||||||
}
|
}
|
||||||
result
|
|
||||||
} else {
|
|
||||||
*should_stop = self.stopped;
|
|
||||||
Ok(Some(self))
|
|
||||||
}
|
}
|
||||||
|
*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();
|
||||||
|
*finished = true;
|
||||||
|
cvar.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn notify_stop_reason(&mut self, reason: SingleThreadStopReason<u32>) {
|
pub fn notify_stop_reason(&mut self, reason: SingleThreadStopReason<u32>) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue