fixes & improvements
Former-commit-id: 1ddeb07bde78a676201037c0bb269ff8122d29c2 Former-commit-id: f9c0eaa2a1073dba82dfb4d3594fbc0b979ef2e0
This commit is contained in:
parent
838ca43ac4
commit
e4e2c710be
|
@ -13,9 +13,10 @@ pub extern crate gdbstub_arch;
|
|||
/// Wait for tcp connection on port
|
||||
pub fn wait_for_connection(port: u16) -> io::Result<TcpStream> {
|
||||
let bind_addr = format!("0.0.0.0:{port}");
|
||||
info!("waiting for connection on {:?}", bind_addr);
|
||||
|
||||
let sock = TcpListener::bind(bind_addr)?;
|
||||
|
||||
info!("waiting for connection");
|
||||
// Blocks until a GDB client connects via TCP.
|
||||
// i.e: Running `target remote localhost:<port>` from the GDB prompt.
|
||||
let (stream, addr) = sock.accept()?;
|
||||
|
|
|
@ -41,7 +41,7 @@ impl<I: MemoryGdbInterface> SingleThreadBase for Arm7tdmiCore<I> {
|
|||
&mut self,
|
||||
regs: &mut gdbstub_arch::arm::reg::ArmCoreRegs,
|
||||
) -> TargetResult<(), Self> {
|
||||
regs.pc = self.pc;
|
||||
regs.pc = self.get_next_pc();
|
||||
regs.lr = self.get_reg(REG_LR);
|
||||
regs.sp = self.get_reg(REG_SP);
|
||||
regs.r[..].copy_from_slice(&self.gpr[..13]);
|
||||
|
|
|
@ -32,6 +32,7 @@ pub(crate) enum DebuggerRequest {
|
|||
Interrupt,
|
||||
Resume,
|
||||
SingleStep,
|
||||
Reset,
|
||||
Disconnected(DisconnectReason),
|
||||
}
|
||||
|
||||
|
@ -40,7 +41,7 @@ pub(crate) struct DebuggerRequestHandler {
|
|||
request_complete_signal: Arc<(Mutex<bool>, Condvar)>,
|
||||
stop_signal: Arc<(Mutex<Option<SingleThreadStopReason<u32>>>, Condvar)>,
|
||||
thread: JoinHandle<()>,
|
||||
stopped: bool,
|
||||
pub(crate) stopped: bool,
|
||||
}
|
||||
|
||||
impl DebuggerRequestHandler {
|
||||
|
@ -123,6 +124,12 @@ impl DebuggerRequestHandler {
|
|||
self.stopped = false;
|
||||
self.complete_request(None)
|
||||
}
|
||||
Reset => {
|
||||
debug!("Sending reset interrupt to gba");
|
||||
self.stopped = true;
|
||||
gba.cpu.reset();
|
||||
self.complete_request(Some(SingleThreadStopReason::Signal(Signal::SIGTRAP)))
|
||||
}
|
||||
SingleStep => {
|
||||
debug!("Debugger requested single step");
|
||||
self.stopped = true;
|
||||
|
@ -153,6 +160,10 @@ impl DebuggerRequestHandler {
|
|||
let mut finished = lock.lock().unwrap();
|
||||
*finished = true;
|
||||
cvar.notify_one();
|
||||
// wait for the ack
|
||||
while *finished {
|
||||
finished = cvar.wait(finished).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn complete_request(
|
||||
|
|
|
@ -3,9 +3,8 @@ use std::sync::{Arc, Condvar, Mutex};
|
|||
use arm7tdmi::{
|
||||
gdb::wait_for_connection,
|
||||
gdbstub::{
|
||||
common::Signal,
|
||||
conn::ConnectionExt,
|
||||
stub::{GdbStub, SingleThreadStopReason},
|
||||
stub::GdbStub,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -41,14 +40,12 @@ pub(crate) fn start_gdb_server_thread(
|
|||
target.disconnect(disconnect_reason);
|
||||
});
|
||||
|
||||
let mut debugger = DebuggerRequestHandler {
|
||||
let debugger = DebuggerRequestHandler {
|
||||
rx,
|
||||
request_complete_signal,
|
||||
stop_signal,
|
||||
thread,
|
||||
stopped: true,
|
||||
};
|
||||
debugger.notify_stop_reason(SingleThreadStopReason::Signal(Signal::SIGINT));
|
||||
|
||||
Ok(debugger)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::sync::{Arc, Condvar, Mutex};
|
||||
use std::sync::{Arc, Condvar, Mutex, WaitTimeoutResult};
|
||||
use std::time::Duration;
|
||||
|
||||
/// Implementing the Target trait for gdbstub
|
||||
|
@ -12,6 +12,7 @@ use gdbstub::target::ext::base::singlethread::{
|
|||
use gdbstub::target::ext::base::singlethread::{SingleThreadResumeOps, SingleThreadSingleStepOps};
|
||||
use gdbstub::target::ext::base::BaseOps;
|
||||
use gdbstub::target::ext::breakpoints::BreakpointsOps;
|
||||
use gdbstub::target::ext::monitor_cmd::{outputln, ConsoleOutput};
|
||||
use gdbstub::target::{self, Target, TargetError, TargetResult};
|
||||
use gdbstub_arch::arm::reg::ArmCoreRegs;
|
||||
|
||||
|
@ -42,16 +43,15 @@ impl DebuggerTarget {
|
|||
pub fn debugger_request(&mut self, req: DebuggerRequest) {
|
||||
let (lock, cvar) = &*self.request_complete_signal;
|
||||
let mut finished = lock.lock().unwrap();
|
||||
*finished = false;
|
||||
|
||||
// now send the request
|
||||
self.tx.send(req).unwrap();
|
||||
|
||||
// wait for the notification
|
||||
while !*finished {
|
||||
finished = cvar.wait(finished).unwrap();
|
||||
}
|
||||
// ack the other side we got the signal
|
||||
*finished = false;
|
||||
cvar.notify_one();
|
||||
}
|
||||
|
||||
pub fn wait_for_stop_reason_timeout(
|
||||
|
@ -60,24 +60,22 @@ impl DebuggerTarget {
|
|||
) -> Option<SingleThreadStopReason<u32>> {
|
||||
let (lock, cvar) = &*self.stop_signal;
|
||||
let mut stop_reason = lock.lock().unwrap();
|
||||
if let Some(stop_reason) = stop_reason.take() {
|
||||
return Some(stop_reason);
|
||||
}
|
||||
let (mut stop_reason, timeout_result) = cvar.wait_timeout(stop_reason, timeout).unwrap();
|
||||
let mut timeout_result: WaitTimeoutResult;
|
||||
while stop_reason.is_none() {
|
||||
(stop_reason, timeout_result) = cvar.wait_timeout(stop_reason, timeout).unwrap();
|
||||
if timeout_result.timed_out() {
|
||||
None
|
||||
} else {
|
||||
Some(stop_reason.take().expect("None is not expected here"))
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(stop_reason.take().expect("None is not expected here"))
|
||||
}
|
||||
|
||||
pub fn wait_for_stop_reason_blocking(&mut self) -> SingleThreadStopReason<u32> {
|
||||
let (lock, cvar) = &*self.stop_signal;
|
||||
let mut stop_reason = lock.lock().unwrap();
|
||||
if let Some(stop_reason) = stop_reason.take() {
|
||||
return stop_reason;
|
||||
while stop_reason.is_none() {
|
||||
stop_reason = cvar.wait(stop_reason).unwrap();
|
||||
}
|
||||
let mut stop_reason = cvar.wait(stop_reason).unwrap();
|
||||
stop_reason.take().expect("None is not expected here")
|
||||
}
|
||||
|
||||
|
@ -106,6 +104,10 @@ impl Target for DebuggerTarget {
|
|||
fn support_memory_map(&mut self) -> Option<target::ext::memory_map::MemoryMapOps<Self>> {
|
||||
Some(self)
|
||||
}
|
||||
|
||||
fn support_monitor_cmd(&mut self) -> Option<target::ext::monitor_cmd::MonitorCmdOps<'_, Self>> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl SingleThreadBase for DebuggerTarget {
|
||||
|
@ -208,3 +210,31 @@ impl target::ext::breakpoints::SwBreakpoint for DebuggerTarget {
|
|||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
impl target::ext::monitor_cmd::MonitorCmd for DebuggerTarget {
|
||||
fn handle_monitor_cmd(
|
||||
&mut self,
|
||||
cmd: &[u8],
|
||||
mut out: ConsoleOutput<'_>,
|
||||
) -> Result<(), Self::Error> {
|
||||
let cmd = match std::str::from_utf8(cmd) {
|
||||
Ok(cmd) => cmd,
|
||||
Err(_) => {
|
||||
outputln!(out, "command must be valid UTF-8");
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
match cmd {
|
||||
"reset" => {
|
||||
self.debugger_request(DebuggerRequest::Reset);
|
||||
outputln!(out, "sent reset signal");
|
||||
}
|
||||
unk => {
|
||||
outputln!(out, "unknown command: {}", unk);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ use rustboyadvance_core::prelude::*;
|
|||
use rustboyadvance_utils::FpsCounter;
|
||||
|
||||
const LOG_DIR: &str = ".logs";
|
||||
const DEFAULT_GDB_SERVER_PORT: u16 = 1337;
|
||||
|
||||
fn ask_download_bios() {
|
||||
const OPEN_SOURCE_BIOS_URL: &'static str =
|
||||
|
@ -113,7 +112,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
}
|
||||
|
||||
if opts.gdbserver {
|
||||
gba.start_gdbserver(DEFAULT_GDB_SERVER_PORT);
|
||||
gba.start_gdbserver(opts.gdbserver_port);
|
||||
}
|
||||
|
||||
let mut vsync = true;
|
||||
|
@ -144,7 +143,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
.unwrap();
|
||||
info!("ending debugger...")
|
||||
}
|
||||
Scancode::F2 => gba.start_gdbserver(DEFAULT_GDB_SERVER_PORT),
|
||||
Scancode::F2 => gba.start_gdbserver(opts.gdbserver_port),
|
||||
Scancode::F5 => {
|
||||
info!("Saving state ...");
|
||||
let save = gba.save_state()?;
|
||||
|
@ -159,10 +158,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
if opts.savestate_path().is_file() {
|
||||
let save = read_bin_file(&opts.savestate_path())?;
|
||||
info!("Restoring state from {:?}...", opts.savestate_path());
|
||||
let (audio_interface, _sdl_audio_device_new) = audio::create_audio_player(&sdl_context)?;
|
||||
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)?);
|
||||
gba = Box::new(GameBoyAdvance::from_saved_state(
|
||||
&save,
|
||||
bios_bin.clone(),
|
||||
rom,
|
||||
audio_interface,
|
||||
)?);
|
||||
info!("Restored!");
|
||||
} else {
|
||||
info!("Savestate not created, please create one by pressing F5");
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{path::PathBuf, io};
|
||||
use std::{io, path::PathBuf};
|
||||
|
||||
use rustboyadvance_core::{
|
||||
cartridge::{BackupType, GamepakBuilder},
|
||||
|
@ -33,6 +33,9 @@ pub struct Options {
|
|||
#[structopt(short = "d", long)]
|
||||
pub gdbserver: bool,
|
||||
|
||||
#[structopt(long = "port", default_value = "1337")]
|
||||
pub gdbserver_port: u16,
|
||||
|
||||
/// Force emulation of RTC, use for games that have RTC but the emulator fails to detect
|
||||
#[structopt(long)]
|
||||
pub rtc: bool,
|
||||
|
|
Reference in a new issue