Handle one message
This commit is contained in:
parent
47a05968fb
commit
0a5e223ba7
135
src/gdbserver.rs
135
src/gdbserver.rs
|
@ -1,5 +1,5 @@
|
||||||
|
use anyhow::{bail, Result};
|
||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
thread,
|
thread,
|
||||||
};
|
};
|
||||||
|
@ -126,6 +126,7 @@ struct GdbConnection {
|
||||||
client: EmulatorClient,
|
client: EmulatorClient,
|
||||||
stream_in: BufReader<OwnedReadHalf>,
|
stream_in: BufReader<OwnedReadHalf>,
|
||||||
stream_out: BufWriter<OwnedWriteHalf>,
|
stream_out: BufWriter<OwnedWriteHalf>,
|
||||||
|
ack_messages: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GdbConnection {
|
impl GdbConnection {
|
||||||
|
@ -136,19 +137,143 @@ impl GdbConnection {
|
||||||
client,
|
client,
|
||||||
stream_in: BufReader::new(rx),
|
stream_in: BufReader::new(rx),
|
||||||
stream_out: BufWriter::new(tx),
|
stream_out: BufWriter::new(tx),
|
||||||
|
ack_messages: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async fn run(mut self) -> Result<(), Box<dyn Error>> {
|
async fn run(mut self) -> Result<()> {
|
||||||
println!("Connected for {}", self.sim_id);
|
println!("Connected for {}", self.sim_id);
|
||||||
self.client.send_command(EmulatorCommand::Resume);
|
self.client.send_command(EmulatorCommand::Resume);
|
||||||
loop {
|
loop {
|
||||||
let byte = self.read_byte().await?;
|
let message = self.read_message().await?;
|
||||||
println!("{byte}");
|
println!("received {:?}", message);
|
||||||
self.stream_out.write_u8(byte).await?;
|
|
||||||
|
let mut res = ResponseWriter::new(&mut self.stream_out);
|
||||||
|
res.init(self.ack_messages).await?;
|
||||||
|
|
||||||
|
let body = match &message {
|
||||||
|
Message::String(str) => str.as_str(),
|
||||||
|
Message::Signal => {
|
||||||
|
// TODO: handle this
|
||||||
|
res.send().await?;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if body == "QStartNoAckMode" {
|
||||||
|
self.ack_messages = false;
|
||||||
|
res.send_ok().await?;
|
||||||
|
} else {
|
||||||
|
// unrecognized command
|
||||||
|
res.send().await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn read_message(&mut self) -> Result<Message> {
|
||||||
|
let mut char = self.read_byte().await?;
|
||||||
|
while char == b'+' {
|
||||||
|
// just ignore positive acks
|
||||||
|
char = self.read_byte().await?;
|
||||||
|
}
|
||||||
|
if char == b'-' {
|
||||||
|
bail!("no support for negative acks");
|
||||||
|
}
|
||||||
|
if char == 0x03 {
|
||||||
|
// This is how the client "cancels an in-flight request"
|
||||||
|
return Ok(Message::Signal);
|
||||||
|
}
|
||||||
|
if char != b'$' {
|
||||||
|
// Messages are supposed to start with a dollar sign
|
||||||
|
bail!("malformed message");
|
||||||
|
}
|
||||||
|
|
||||||
|
// now read the body
|
||||||
|
let mut checksum = 0u8;
|
||||||
|
let mut body = vec![];
|
||||||
|
char = self.read_byte().await?;
|
||||||
|
while char != b'#' {
|
||||||
|
if char == b'}' {
|
||||||
|
// escape character
|
||||||
|
checksum = checksum.wrapping_add(char);
|
||||||
|
char = self.read_byte().await?;
|
||||||
|
checksum = checksum.wrapping_add(char);
|
||||||
|
body.push(char ^ 0x20);
|
||||||
|
} else {
|
||||||
|
checksum = checksum.wrapping_add(char);
|
||||||
|
body.push(char);
|
||||||
|
}
|
||||||
|
char = self.read_byte().await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut checksum_bytes = [b'0'; 2];
|
||||||
|
self.stream_in.read_exact(&mut checksum_bytes).await?;
|
||||||
|
let checksum_str = std::str::from_utf8(&checksum_bytes)?;
|
||||||
|
let real_checksum = u8::from_str_radix(checksum_str, 16)?;
|
||||||
|
if checksum != real_checksum {
|
||||||
|
bail!("invalid checksum");
|
||||||
|
}
|
||||||
|
|
||||||
|
let string = String::from_utf8(body)?;
|
||||||
|
Ok(Message::String(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_byte(&mut self) -> std::io::Result<u8> {
|
async fn read_byte(&mut self) -> std::io::Result<u8> {
|
||||||
self.stream_in.read_u8().await
|
self.stream_in.read_u8().await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ResponseWriter<'a> {
|
||||||
|
inner: &'a mut BufWriter<OwnedWriteHalf>,
|
||||||
|
checksum: u8,
|
||||||
|
}
|
||||||
|
impl<'a> ResponseWriter<'a> {
|
||||||
|
fn new(inner: &'a mut BufWriter<OwnedWriteHalf>) -> Self {
|
||||||
|
Self { inner, checksum: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn init(&mut self, ack: bool) -> std::io::Result<()> {
|
||||||
|
if ack {
|
||||||
|
self.inner.write_u8(b'+').await?;
|
||||||
|
}
|
||||||
|
self.inner.write_u8(b'$').await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn write_str(&mut self, str: &str) -> std::io::Result<()> {
|
||||||
|
for byte in str.bytes() {
|
||||||
|
self.checksum = self.checksum.wrapping_add(byte);
|
||||||
|
}
|
||||||
|
self.inner.write_all(str.as_bytes()).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn write_hex_u8(&mut self, value: u8) -> std::io::Result<()> {
|
||||||
|
for digit in [(value >> 4), (value & 0xf)] {
|
||||||
|
let char = if digit > 9 {
|
||||||
|
b'a' + digit - 10
|
||||||
|
} else {
|
||||||
|
b'0' + digit
|
||||||
|
};
|
||||||
|
self.checksum = self.checksum.wrapping_add(char);
|
||||||
|
self.inner.write_u8(char).await?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_ok(mut self) -> std::io::Result<()> {
|
||||||
|
self.write_str("OK").await?;
|
||||||
|
self.send().await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send(mut self) -> std::io::Result<()> {
|
||||||
|
let final_checksum = self.checksum;
|
||||||
|
self.inner.write_u8(b'#').await?;
|
||||||
|
self.write_hex_u8(final_checksum).await?;
|
||||||
|
println!("{:?}", std::str::from_utf8(self.inner.buffer()));
|
||||||
|
self.inner.flush().await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Message {
|
||||||
|
String(String),
|
||||||
|
Signal,
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue