No debugging unless the game is running
This commit is contained in:
parent
f031bb17b2
commit
17d3811124
|
@ -305,6 +305,10 @@ impl Emulator {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_debugging(&mut self, sim_id: SimId, sender: DebugSender) {
|
fn start_debugging(&mut self, sim_id: SimId, sender: DebugSender) {
|
||||||
|
if self.sim_state[sim_id.to_index()].load(Ordering::Acquire) != SimState::Ready {
|
||||||
|
// Can't debug unless a game is connected
|
||||||
|
return;
|
||||||
|
}
|
||||||
let debug = DebugInfo {
|
let debug = DebugInfo {
|
||||||
sender,
|
sender,
|
||||||
stop_reason: Some(DebugStopReason::Trapped),
|
stop_reason: Some(DebugStopReason::Trapped),
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::{
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{AsyncWriteExt as _, BufReader},
|
io::{AsyncWriteExt as _, BufReader},
|
||||||
net::{TcpListener, TcpStream},
|
net::{TcpListener, TcpStream},
|
||||||
select,
|
pin, select,
|
||||||
sync::{mpsc, oneshot},
|
sync::{mpsc, oneshot},
|
||||||
};
|
};
|
||||||
use tracing::{debug, enabled, error, info, Level};
|
use tracing::{debug, enabled, error, info, Level};
|
||||||
|
@ -57,8 +57,9 @@ impl GdbServer {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.block_on(async move {
|
.block_on(async move {
|
||||||
select! {
|
select! {
|
||||||
_ = run_server(sim_id, client, port, &status) => {}
|
_ = run_server(sim_id, client.clone(), port, &status) => {}
|
||||||
_ = rx => {
|
_ = rx => {
|
||||||
|
client.send_command(EmulatorCommand::StopDebugging(sim_id));
|
||||||
*status.lock().unwrap() = GdbServerStatus::Stopped;
|
*status.lock().unwrap() = GdbServerStatus::Stopped;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,19 +74,46 @@ impl GdbServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for GdbServer {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn run_server(
|
async fn run_server(
|
||||||
sim_id: SimId,
|
sim_id: SimId,
|
||||||
client: EmulatorClient,
|
client: EmulatorClient,
|
||||||
port: u16,
|
port: u16,
|
||||||
status: &Mutex<GdbServerStatus>,
|
status: &Mutex<GdbServerStatus>,
|
||||||
) {
|
) {
|
||||||
|
let (debug_sink, mut debug_source) = mpsc::unbounded_channel();
|
||||||
|
client.send_command(EmulatorCommand::StartDebugging(sim_id, debug_sink));
|
||||||
|
|
||||||
info!("Connecting to debugger on port {port}...");
|
info!("Connecting to debugger on port {port}...");
|
||||||
let Some(stream) = try_connect(port, status).await else {
|
let connect_future = try_connect(port, status);
|
||||||
return;
|
pin!(connect_future);
|
||||||
|
|
||||||
|
let stream = loop {
|
||||||
|
select! {
|
||||||
|
stream = &mut connect_future => {
|
||||||
|
if let Some(stream) = stream {
|
||||||
|
break stream;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event = debug_source.recv() => {
|
||||||
|
if event.is_none() {
|
||||||
|
// The sim has stopped (or was never started)
|
||||||
|
*status.lock().unwrap() = GdbServerStatus::Stopped;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
info!("Connected!");
|
info!("Connected!");
|
||||||
let mut connection = GdbConnection::new(sim_id, client);
|
let mut connection = GdbConnection::new(sim_id, client);
|
||||||
match connection.run(stream).await {
|
match connection.run(stream, debug_source).await {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
info!("Finished debugging.");
|
info!("Finished debugging.");
|
||||||
*status.lock().unwrap() = GdbServerStatus::Stopped;
|
*status.lock().unwrap() = GdbServerStatus::Stopped;
|
||||||
|
@ -154,12 +182,13 @@ impl GdbConnection {
|
||||||
memory_buf: None,
|
memory_buf: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async fn run(&mut self, stream: TcpStream) -> Result<()> {
|
async fn run(
|
||||||
let (debug_sink, mut debug_source) = mpsc::unbounded_channel();
|
&mut self,
|
||||||
|
stream: TcpStream,
|
||||||
|
mut debug_source: mpsc::UnboundedReceiver<DebugEvent>,
|
||||||
|
) -> Result<()> {
|
||||||
let (rx, mut tx) = stream.into_split();
|
let (rx, mut tx) = stream.into_split();
|
||||||
let mut request_source = RequestSource::new(BufReader::new(rx));
|
let mut request_source = RequestSource::new(BufReader::new(rx));
|
||||||
self.client
|
|
||||||
.send_command(EmulatorCommand::StartDebugging(self.sim_id, debug_sink));
|
|
||||||
loop {
|
loop {
|
||||||
let response = select! {
|
let response = select! {
|
||||||
maybe_event = debug_source.recv() => {
|
maybe_event = debug_source.recv() => {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
use std::{path::PathBuf, process, time::SystemTime};
|
use std::{path::PathBuf, process, time::SystemTime};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{bail, Result};
|
||||||
use app::Application;
|
use app::Application;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use emulator::EmulatorBuilder;
|
use emulator::EmulatorBuilder;
|
||||||
|
@ -95,10 +95,13 @@ fn main() -> Result<()> {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
let (mut builder, client) = EmulatorBuilder::new();
|
let (mut builder, client) = EmulatorBuilder::new();
|
||||||
if let Some(path) = args.rom {
|
if let Some(path) = &args.rom {
|
||||||
builder = builder.with_rom(&path);
|
builder = builder.with_rom(path);
|
||||||
}
|
}
|
||||||
if args.debug_port.is_some() {
|
if args.debug_port.is_some() {
|
||||||
|
if args.rom.is_none() {
|
||||||
|
bail!("to start debugging, please select a game.");
|
||||||
|
}
|
||||||
builder = builder.start_paused(true);
|
builder = builder.start_paused(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use winit::event_loop::EventLoopProxy;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::UserEvent,
|
app::UserEvent,
|
||||||
emulator::{EmulatorClient, SimId},
|
emulator::{EmulatorClient, SimId, SimState},
|
||||||
gdbserver::{GdbServer, GdbServerStatus},
|
gdbserver::{GdbServer, GdbServerStatus},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ use super::AppWindow;
|
||||||
|
|
||||||
pub struct GdbServerWindow {
|
pub struct GdbServerWindow {
|
||||||
sim_id: SimId,
|
sim_id: SimId,
|
||||||
|
client: EmulatorClient,
|
||||||
port_str: String,
|
port_str: String,
|
||||||
connected: bool,
|
connected: bool,
|
||||||
quit_on_disconnect: bool,
|
quit_on_disconnect: bool,
|
||||||
|
@ -22,6 +23,7 @@ impl GdbServerWindow {
|
||||||
pub fn new(sim_id: SimId, client: EmulatorClient, proxy: EventLoopProxy<UserEvent>) -> Self {
|
pub fn new(sim_id: SimId, client: EmulatorClient, proxy: EventLoopProxy<UserEvent>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
sim_id,
|
sim_id,
|
||||||
|
client: client.clone(),
|
||||||
port_str: (8080 + sim_id.to_index()).to_string(),
|
port_str: (8080 + sim_id.to_index()).to_string(),
|
||||||
connected: false,
|
connected: false,
|
||||||
quit_on_disconnect: false,
|
quit_on_disconnect: false,
|
||||||
|
@ -78,7 +80,9 @@ impl AppWindow for GdbServerWindow {
|
||||||
self.connected = false;
|
self.connected = false;
|
||||||
}
|
}
|
||||||
let start_button = Button::new("Start");
|
let start_button = Button::new("Start");
|
||||||
if ui.add_enabled(port_num.is_some(), start_button).clicked() {
|
let can_start =
|
||||||
|
port_num.is_some() && self.client.sim_state(self.sim_id) == SimState::Ready;
|
||||||
|
if ui.add_enabled(can_start, start_button).clicked() {
|
||||||
let port = port_num.unwrap();
|
let port = port_num.unwrap();
|
||||||
self.server.start(port);
|
self.server.start(port);
|
||||||
self.connected = true;
|
self.connected = true;
|
||||||
|
|
Loading…
Reference in New Issue