1 use crate::protocol::{commands::Command, common::decode_hex};
2 use crate::target::Target;
3 
4 /// Packet parse error.
5 #[derive(Debug)]
6 pub enum PacketParseError {
7     ChecksumMismatched { checksum: u8, calculated: u8 },
8     EmptyBuf,
9     MissingChecksum,
10     MalformedChecksum,
11     MalformedCommand,
12     NotASCII,
13     UnexpectedHeader(u8),
14 }
15 
16 /// Top-Level GDB packet
17 pub enum Packet<'a> {
18     Ack,
19     Nack,
20     Interrupt,
21     Command(Command<'a>),
22 }
23 
24 pub struct PacketBuf<'a> {
25     buf: &'a mut [u8],
26     body_range: core::ops::Range<usize>,
27 }
28 
29 impl<'a> PacketBuf<'a> {
30     /// Validate the contents of the raw packet buffer, checking for checksum
31     /// consistency, structural correctness, and ASCII validation.
new(pkt_buf: &'a mut [u8]) -> Result<PacketBuf<'a>, PacketParseError>32     pub fn new(pkt_buf: &'a mut [u8]) -> Result<PacketBuf<'a>, PacketParseError> {
33         // validate the packet is valid ASCII
34         if !pkt_buf.is_ascii() {
35             return Err(PacketParseError::NotASCII);
36         }
37 
38         let end_of_body = pkt_buf
39             .iter()
40             .position(|b| *b == b'#')
41             .ok_or(PacketParseError::MissingChecksum)?;
42 
43         // split buffer into body and checksum components
44         let (body, checksum) = pkt_buf.split_at_mut(end_of_body);
45         let body = &mut body[1..]; // skip the '$'
46         let checksum = &mut checksum[1..][..2]; // skip the '#'
47 
48         // validate the checksum
49         let checksum = decode_hex(checksum).map_err(|_| PacketParseError::MalformedChecksum)?;
50         let calculated = body.iter().fold(0u8, |a, x| a.wrapping_add(*x));
51         if calculated != checksum {
52             return Err(PacketParseError::ChecksumMismatched {
53                 checksum,
54                 calculated,
55             });
56         }
57 
58         if log_enabled!(log::Level::Trace) {
59             // SAFETY: body confirmed to be `is_ascii()`
60             let body = unsafe { core::str::from_utf8_unchecked(body) };
61             trace!("<-- ${}#{:02x?}", body, checksum);
62         }
63 
64         Ok(PacketBuf {
65             buf: pkt_buf,
66             body_range: 1..end_of_body,
67         })
68     }
69 
70     /// (used for tests) Create a packet buffer from a raw body buffer, skipping
71     /// the header/checksum trimming stage. ASCII validation is still performed.
72     #[cfg(test)]
new_with_raw_body(body: &'a mut [u8]) -> Result<PacketBuf<'a>, PacketParseError>73     pub fn new_with_raw_body(body: &'a mut [u8]) -> Result<PacketBuf<'a>, PacketParseError> {
74         // validate the packet is valid ASCII
75         if !body.is_ascii() {
76             return Err(PacketParseError::NotASCII);
77         }
78 
79         let len = body.len();
80         Ok(PacketBuf {
81             buf: body,
82             body_range: 0..len,
83         })
84     }
85 
trim_start_body_bytes(self, n: usize) -> Self86     pub fn trim_start_body_bytes(self, n: usize) -> Self {
87         PacketBuf {
88             buf: self.buf,
89             body_range: (self.body_range.start + n)..self.body_range.end,
90         }
91     }
92 
as_body(&'a self) -> &'a [u8]93     pub fn as_body(&'a self) -> &'a [u8] {
94         &self.buf[self.body_range.clone()]
95     }
96 
97     /// Return a mut reference to slice of the packet buffer corresponding to
98     /// the current body.
into_body(self) -> &'a mut [u8]99     pub fn into_body(self) -> &'a mut [u8] {
100         &mut self.buf[self.body_range]
101     }
102 
into_body_str(self) -> &'a str103     pub fn into_body_str(self) -> &'a str {
104         // SAFETY: buffer confirmed to be `is_ascii()` in `new`, and no other PacketBuf
105         // member allow arbitrary modification of `self.buf`.
106         unsafe { core::str::from_utf8_unchecked(&self.buf[self.body_range]) }
107     }
108 
109     /// Return a mut reference to the _entire_ underlying packet buffer, and the
110     /// current body's range.
111     #[allow(dead_code)]
into_raw_buf(self) -> (&'a mut [u8], core::ops::Range<usize>)112     pub fn into_raw_buf(self) -> (&'a mut [u8], core::ops::Range<usize>) {
113         (self.buf, self.body_range)
114     }
115 }
116 
117 impl<'a> Packet<'a> {
from_buf( target: &mut impl Target, buf: &'a mut [u8], ) -> Result<Packet<'a>, PacketParseError>118     pub fn from_buf(
119         target: &mut impl Target,
120         buf: &'a mut [u8],
121     ) -> Result<Packet<'a>, PacketParseError> {
122         // cannot have empty packet
123         if buf.is_empty() {
124             return Err(PacketParseError::EmptyBuf);
125         }
126 
127         match buf[0] {
128             b'$' => Ok(Packet::Command(
129                 Command::from_packet(target, PacketBuf::new(buf)?)
130                     // TODO?: preserve command parse error context
131                     .map_err(|_| PacketParseError::MalformedCommand)?,
132             )),
133             b'+' => Ok(Packet::Ack),
134             b'-' => Ok(Packet::Nack),
135             0x03 => Ok(Packet::Interrupt),
136             _ => Err(PacketParseError::UnexpectedHeader(buf[0])),
137         }
138     }
139 }
140