Separate GDB request and response into structs

This commit is contained in:
2025-01-01 17:02:14 -05:00
parent 24487b21b7
commit 9519897711
3 changed files with 201 additions and 179 deletions
+84
View File
@@ -0,0 +1,84 @@
use anyhow::{bail, Result};
use tokio::io::{AsyncRead, AsyncReadExt as _};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RequestKind {
Signal,
Command,
}
#[derive(Debug)]
pub struct Request<'a> {
pub kind: RequestKind,
body: &'a str,
}
impl<'a> Request<'a> {
pub async fn read<R: AsyncRead + Unpin>(
reader: &mut R,
buffer: &'a mut Vec<u8>,
) -> Result<Self> {
buffer.clear();
let mut char = reader.read_u8().await?;
while char == b'+' {
// just ignore positive acks
char = reader.read_u8().await?;
}
if char == b'-' {
bail!("no support for negative acks");
}
if char == 0x03 {
// This is how the client "cancels an in-flight request"
buffer.push(char);
let body = std::str::from_utf8(buffer)?;
return Ok(Self {
kind: RequestKind::Signal,
body,
});
}
if char != b'$' {
// Messages are supposed to start with a dollar sign
bail!("malformed message");
}
// now read the body
let mut checksum = 0u8;
char = reader.read_u8().await?;
while char != b'#' {
if char == b'}' {
// escape character
checksum = checksum.wrapping_add(char);
char = reader.read_u8().await?;
checksum = checksum.wrapping_add(char);
buffer.push(char ^ 0x20);
} else {
checksum = checksum.wrapping_add(char);
buffer.push(char);
}
char = reader.read_u8().await?;
}
let mut checksum_bytes = [b'0'; 2];
reader.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 body = std::str::from_utf8(buffer)?;
Ok(Self {
kind: RequestKind::Command,
body,
})
}
pub fn match_str(&mut self, prefix: &str) -> bool {
if let Some(new_body) = self.body.strip_prefix(prefix) {
self.body = new_body;
return true;
}
false
}
}
+45
View File
@@ -0,0 +1,45 @@
pub struct Response {
buffer: Vec<u8>,
checksum: u8,
}
impl Response {
pub fn new(mut buffer: Vec<u8>, ack: bool) -> Self {
buffer.clear();
if ack {
buffer.push(b'+');
}
buffer.push(b'$');
Self {
buffer,
checksum: 0,
}
}
pub fn write_str(mut self, str: &str) -> Self {
for char in str.as_bytes() {
self.buffer.push(*char);
self.checksum = self.checksum.wrapping_add(*char);
}
self
}
pub fn write_hex_u8(mut self, value: u8) -> Self {
for digit in [(value >> 4), (value & 0xf)] {
let char = if digit > 9 {
b'a' + digit - 10
} else {
b'0' + digit
};
self.buffer.push(char);
self.checksum = self.checksum.wrapping_add(char);
}
self
}
pub fn finish(mut self) -> Vec<u8> {
let checksum = self.checksum;
self.buffer.push(b'#');
self.write_hex_u8(checksum).buffer
}
}