Separate GDB request and response into structs
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user