mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-25 15:16:53 +01:00
Removed GDB support / added text encoding selection
This commit is contained in:
parent
f2edbb6d16
commit
79033bc648
@ -2,23 +2,23 @@ use crate::sc64;
|
|||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use encoding_rs::EUC_JP;
|
use encoding_rs::EUC_JP;
|
||||||
use panic_message::panic_message;
|
|
||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{stdin, ErrorKind, Read, Write},
|
io::{stdin, Read, Write},
|
||||||
net::{TcpListener, TcpStream},
|
|
||||||
panic,
|
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::mpsc::{channel, Receiver, Sender},
|
sync::mpsc::{channel, Receiver, Sender},
|
||||||
thread::{sleep, spawn},
|
thread::spawn,
|
||||||
time::Duration,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub enum Encoding {
|
||||||
|
UTF8,
|
||||||
|
EUCJP,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Handler {
|
pub struct Handler {
|
||||||
header: Option<Vec<u8>>,
|
header: Option<Vec<u8>>,
|
||||||
line_rx: Receiver<String>,
|
line_rx: Receiver<String>,
|
||||||
gdb_tx: Sender<Vec<u8>>,
|
encoding: Encoding,
|
||||||
gdb_rx: Receiver<Vec<u8>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DataType {
|
enum DataType {
|
||||||
@ -26,7 +26,6 @@ enum DataType {
|
|||||||
RawBinary,
|
RawBinary,
|
||||||
Header,
|
Header,
|
||||||
Screenshot,
|
Screenshot,
|
||||||
GDB,
|
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +36,6 @@ impl From<u8> for DataType {
|
|||||||
0x02 => Self::RawBinary,
|
0x02 => Self::RawBinary,
|
||||||
0x03 => Self::Header,
|
0x03 => Self::Header,
|
||||||
0x04 => Self::Screenshot,
|
0x04 => Self::Screenshot,
|
||||||
0xDB => Self::GDB,
|
|
||||||
_ => Self::Unknown,
|
_ => Self::Unknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,7 +48,6 @@ impl From<DataType> for u8 {
|
|||||||
DataType::RawBinary => 0x02,
|
DataType::RawBinary => 0x02,
|
||||||
DataType::Header => 0x03,
|
DataType::Header => 0x03,
|
||||||
DataType::Screenshot => 0x04,
|
DataType::Screenshot => 0x04,
|
||||||
DataType::GDB => 0xDB,
|
|
||||||
DataType::Unknown => 0xFF,
|
DataType::Unknown => 0xFF,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,6 +136,10 @@ macro_rules! stop {
|
|||||||
const MAX_PACKET_LENGTH: usize = 8 * 1024 * 1024;
|
const MAX_PACKET_LENGTH: usize = 8 * 1024 * 1024;
|
||||||
|
|
||||||
impl Handler {
|
impl Handler {
|
||||||
|
pub fn set_text_encoding(&mut self, encoding: Encoding) {
|
||||||
|
self.encoding = encoding;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn process_user_input(&self) -> Option<sc64::DebugPacket> {
|
pub fn process_user_input(&self) -> Option<sc64::DebugPacket> {
|
||||||
let line = match self.line_rx.try_recv() {
|
let line = match self.line_rx.try_recv() {
|
||||||
Ok(line) => {
|
Ok(line) => {
|
||||||
@ -219,13 +220,12 @@ impl Handler {
|
|||||||
DataType::RawBinary => self.handle_datatype_raw_binary(&data),
|
DataType::RawBinary => self.handle_datatype_raw_binary(&data),
|
||||||
DataType::Header => self.handle_datatype_header(&data),
|
DataType::Header => self.handle_datatype_header(&data),
|
||||||
DataType::Screenshot => self.handle_datatype_screenshot(&data),
|
DataType::Screenshot => self.handle_datatype_screenshot(&data),
|
||||||
DataType::GDB => self.handle_datatype_gdb(&data),
|
|
||||||
_ => error!("Received unknown debug packet datatype: 0x{datatype:02X}"),
|
_ => error!("Received unknown debug packet datatype: 0x{datatype:02X}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_is_viewer_64(&self, message: Vec<u8>) {
|
pub fn handle_is_viewer_64(&self, data: &[u8]) {
|
||||||
print!("{}", EUC_JP.decode(&message).0)
|
self.print_text(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_save_writeback(
|
pub fn handle_save_writeback(
|
||||||
@ -259,19 +259,8 @@ impl Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn receive_gdb_packet(&self) -> Option<sc64::DebugPacket> {
|
|
||||||
if let Some(data) = self.gdb_rx.try_recv().ok() {
|
|
||||||
Some(sc64::DebugPacket {
|
|
||||||
datatype: DataType::GDB.into(),
|
|
||||||
data,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_datatype_text(&self, data: &[u8]) {
|
fn handle_datatype_text(&self, data: &[u8]) {
|
||||||
print!("{}", String::from_utf8_lossy(data));
|
self.print_text(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_datatype_raw_binary(&self, data: &[u8]) {
|
fn handle_datatype_raw_binary(&self, data: &[u8]) {
|
||||||
@ -330,8 +319,21 @@ impl Handler {
|
|||||||
success!("Wrote {width}x{height} pixels to [{filename}]");
|
success!("Wrote {width}x{height} pixels to [{filename}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_datatype_gdb(&self, data: &[u8]) {
|
fn print_text(&self, data: &[u8]) {
|
||||||
self.gdb_tx.send(data.to_vec()).ok();
|
match self.encoding {
|
||||||
|
Encoding::UTF8 => print!("{}", String::from_utf8_lossy(&data)),
|
||||||
|
Encoding::EUCJP => print!("{}", EUC_JP.decode(&data).0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new() -> Handler {
|
||||||
|
let (line_tx, line_rx) = channel::<String>();
|
||||||
|
spawn(move || stdin_thread(line_tx));
|
||||||
|
Handler {
|
||||||
|
header: None,
|
||||||
|
line_rx,
|
||||||
|
encoding: Encoding::UTF8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,30 +366,6 @@ fn generate_filename(prefix: &str, extension: &str) -> String {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(gdb_port: Option<u16>) -> Result<Handler, sc64::Error> {
|
|
||||||
let (line_tx, line_rx) = channel::<String>();
|
|
||||||
let (gdb_tx, gdb_loop_rx) = channel::<Vec<u8>>();
|
|
||||||
let (gdb_loop_tx, gdb_rx) = channel::<Vec<u8>>();
|
|
||||||
|
|
||||||
spawn(move || stdin_thread(line_tx));
|
|
||||||
|
|
||||||
if let Some(port) = gdb_port {
|
|
||||||
let listener = TcpListener::bind(format!("0.0.0.0:{port}"))
|
|
||||||
.map_err(|_| sc64::Error::new("Couldn't open GDB TCP socket port"))?;
|
|
||||||
listener.set_nonblocking(true).map_err(|_| {
|
|
||||||
sc64::Error::new("Couldn't set GDB TCP socket listener as non-blocking")
|
|
||||||
})?;
|
|
||||||
spawn(move || gdb_thread(listener, gdb_loop_tx, gdb_loop_rx));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Handler {
|
|
||||||
header: None,
|
|
||||||
line_rx,
|
|
||||||
gdb_tx,
|
|
||||||
gdb_rx,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stdin_thread(line_tx: Sender<String>) {
|
fn stdin_thread(line_tx: Sender<String>) {
|
||||||
loop {
|
loop {
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
@ -398,77 +376,3 @@ fn stdin_thread(line_tx: Sender<String>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gdb_thread(listener: TcpListener, gdb_tx: Sender<Vec<u8>>, gdb_rx: Receiver<Vec<u8>>) {
|
|
||||||
match panic::catch_unwind(|| gdb_loop(listener, gdb_tx, gdb_rx)) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(payload) => {
|
|
||||||
eprintln!("{}", panic_message(&payload).red());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gdb_loop(listener: TcpListener, gdb_tx: Sender<Vec<u8>>, gdb_rx: Receiver<Vec<u8>>) {
|
|
||||||
for tcp_stream in listener.incoming() {
|
|
||||||
match tcp_stream {
|
|
||||||
Ok(mut stream) => {
|
|
||||||
handle_gdb_connection(&mut stream, &gdb_tx, &gdb_rx);
|
|
||||||
}
|
|
||||||
Err(error) => {
|
|
||||||
if error.kind() == ErrorKind::WouldBlock {
|
|
||||||
sleep(Duration::from_millis(1));
|
|
||||||
} else {
|
|
||||||
panic!("{error}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_gdb_connection(
|
|
||||||
stream: &mut TcpStream,
|
|
||||||
gdb_tx: &Sender<Vec<u8>>,
|
|
||||||
gdb_rx: &Receiver<Vec<u8>>,
|
|
||||||
) {
|
|
||||||
const GDB_DATA_BUFFER: usize = 64 * 1024;
|
|
||||||
|
|
||||||
let mut buffer = vec![0u8; GDB_DATA_BUFFER];
|
|
||||||
|
|
||||||
let peer = stream.peer_addr().unwrap();
|
|
||||||
|
|
||||||
println!("[GDB]: New connection ({peer})");
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match stream.read(&mut buffer) {
|
|
||||||
Ok(length) => {
|
|
||||||
if length > 0 {
|
|
||||||
gdb_tx.send(buffer[0..length].to_vec()).ok();
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
println!("[GDB]: Connection closed ({peer})");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
if e.kind() != ErrorKind::WouldBlock {
|
|
||||||
println!("[GDB]: Connection closed ({peer}), read IO error: {e}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(data) = gdb_rx.try_recv() {
|
|
||||||
match stream.write_all(&data) {
|
|
||||||
Ok(()) => {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
println!("[GDB]: Connection closed ({peer}), write IO error: {e}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sleep(Duration::from_millis(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -154,9 +154,9 @@ struct DebugArgs {
|
|||||||
#[arg(long, value_name = "offset", value_parser = |s: &str| maybe_hex_range::<u32>(s, 0x00000004, 0x03FF0000))]
|
#[arg(long, value_name = "offset", value_parser = |s: &str| maybe_hex_range::<u32>(s, 0x00000004, 0x03FF0000))]
|
||||||
isv: Option<u32>,
|
isv: Option<u32>,
|
||||||
|
|
||||||
/// Expose TCP socket port for GDB debugging
|
/// Use EUC-JP encoding for text printing
|
||||||
#[arg(long, value_name = "port", value_parser = clap::value_parser!(u16).range(1..))]
|
#[arg(long)]
|
||||||
gdb: Option<u16>,
|
euc_jp: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
@ -575,7 +575,11 @@ fn handle_64dd_command(connection: Connection, args: &_64DDArgs) -> Result<(), s
|
|||||||
fn handle_debug_command(connection: Connection, args: &DebugArgs) -> Result<(), sc64::Error> {
|
fn handle_debug_command(connection: Connection, args: &DebugArgs) -> Result<(), sc64::Error> {
|
||||||
let mut sc64 = init_sc64(connection, true)?;
|
let mut sc64 = init_sc64(connection, true)?;
|
||||||
|
|
||||||
let mut debug_handler = debug::new(args.gdb)?;
|
let mut debug_handler = debug::new();
|
||||||
|
|
||||||
|
if args.euc_jp {
|
||||||
|
debug_handler.set_text_encoding(debug::Encoding::EUCJP);
|
||||||
|
}
|
||||||
|
|
||||||
if args.isv.is_some() {
|
if args.isv.is_some() {
|
||||||
sc64.configure_is_viewer_64(args.isv)?;
|
sc64.configure_is_viewer_64(args.isv)?;
|
||||||
@ -599,15 +603,13 @@ fn handle_debug_command(connection: Connection, args: &DebugArgs) -> Result<(),
|
|||||||
debug_handler.handle_debug_packet(debug_packet);
|
debug_handler.handle_debug_packet(debug_packet);
|
||||||
}
|
}
|
||||||
sc64::DataPacket::IsViewer64(message) => {
|
sc64::DataPacket::IsViewer64(message) => {
|
||||||
debug_handler.handle_is_viewer_64(message);
|
debug_handler.handle_is_viewer_64(&message);
|
||||||
}
|
}
|
||||||
sc64::DataPacket::SaveWriteback(save_writeback) => {
|
sc64::DataPacket::SaveWriteback(save_writeback) => {
|
||||||
debug_handler.handle_save_writeback(save_writeback, &args.save);
|
debug_handler.handle_save_writeback(save_writeback, &args.save);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
} else if let Some(gdb_packet) = debug_handler.receive_gdb_packet() {
|
|
||||||
sc64.send_debug_packet(gdb_packet)?;
|
|
||||||
} else if let Some(debug_packet) = debug_handler.process_user_input() {
|
} else if let Some(debug_packet) = debug_handler.process_user_input() {
|
||||||
sc64.send_debug_packet(debug_packet)?;
|
sc64.send_debug_packet(debug_packet)?;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user