1 use crate::protocol::commands::Command;
2 use crate::protocol::common::hex::decode_hex;
3 use crate::target::Target;
4 
5 /// Packet parse error.
6 #[derive(Debug)]
7 pub enum PacketParseError {
8     #[allow(dead_code)] // used as part of Debug impl
9     ChecksumMismatched {
10         checksum: u8,
11         calculated: u8,
12     },
13     EmptyBuf,
14     MissingChecksum,
15     MalformedChecksum,
16     MalformedCommand,
17     #[allow(dead_code)] // used as part of Debug impl
18     UnexpectedHeader(u8),
19 }
20 
21 /// Top-Level GDB packet
22 pub enum Packet<'a> {
23     Ack,
24     Nack,
25     Interrupt,
26     Command(Command<'a>),
27 }
28 
29 /// Wrapper around a byte buffer containing a GDB packet, while also tracking
30 /// the range of the buffer containing the packet's "body".
31 ///
32 /// A newly constructed `PacketBuf` will have a body that spans the entire data
33 /// portion of the packet (i.e: `b"$data#checksum"`), but this range can be
34 /// further restricted as part of packet parsing.
35 ///
36 /// Notably, `PacketBuf` will _always_ maintain a mutable reference back to the
37 /// _entire_ underlying packet buffer. This makes it possible to re-use any
38 /// unused buffer space as "scratch" space. One notable example of this use-case
39 /// is the 'm' packet, which recycles unused packet buffer space as a buffer for
40 /// the target's `read_memory` method.
41 pub struct PacketBuf<'a> {
42     buf: &'a mut [u8],
43     body_range: core::ops::Range<usize>,
44 }
45 
46 impl<'a> PacketBuf<'a> {
47     /// Validate the contents of the raw packet buffer, checking for checksum
48     /// consistency and structural correctness.
new(pkt_buf: &'a mut [u8]) -> Result<PacketBuf<'a>, PacketParseError>49     pub fn new(pkt_buf: &'a mut [u8]) -> Result<PacketBuf<'a>, PacketParseError> {
50         if pkt_buf.is_empty() {
51             return Err(PacketParseError::EmptyBuf);
52         }
53 
54         // split buffer into body and checksum components
55         let mut parts = pkt_buf[1..].split(|b| *b == b'#');
56 
57         let body = parts.next().unwrap(); // spit iter always returns at least one element
58         let checksum = parts
59             .next()
60             .ok_or(PacketParseError::MissingChecksum)?
61             .get(..2)
62             .ok_or(PacketParseError::MalformedChecksum)?;
63 
64         // validate the checksum
65         let checksum = decode_hex(checksum).map_err(|_| PacketParseError::MalformedChecksum)?;
66         let calculated = body.iter().fold(0u8, |a, x| a.wrapping_add(*x));
67         if calculated != checksum {
68             return Err(PacketParseError::ChecksumMismatched {
69                 checksum,
70                 calculated,
71             });
72         }
73 
74         let body_range = 1..(body.len() + 1); // compensate for the leading '$'
75 
76         Ok(PacketBuf {
77             buf: pkt_buf,
78             body_range,
79         })
80     }
81 
82     /// (used for tests) Create a packet buffer from a raw body buffer, skipping
83     /// the header/checksum trimming stage.
84     #[cfg(test)]
new_with_raw_body(body: &'a mut [u8]) -> Result<PacketBuf<'a>, PacketParseError>85     pub fn new_with_raw_body(body: &'a mut [u8]) -> Result<PacketBuf<'a>, PacketParseError> {
86         let len = body.len();
87         Ok(PacketBuf {
88             buf: body,
89             body_range: 0..len,
90         })
91     }
92 
93     /// Strip the specified prefix from the packet buffer, returning `true` if
94     /// there was a prefix match.
strip_prefix(&mut self, prefix: &[u8]) -> bool95     pub fn strip_prefix(&mut self, prefix: &[u8]) -> bool {
96         let body = {
97             // SAFETY: The public interface of `PacketBuf` ensures that `self.body_range`
98             // always stays within the bounds of the provided buffer.
99             #[cfg(not(feature = "paranoid_unsafe"))]
100             unsafe {
101                 self.buf.get_unchecked_mut(self.body_range.clone())
102             }
103 
104             #[cfg(feature = "paranoid_unsafe")]
105             &mut self.buf[self.body_range.clone()]
106         };
107 
108         if body.starts_with(prefix) {
109             // SAFETY: if the current buffer range `starts_with` the specified prefix, then
110             // it is safe to bump `body_range.start` by the prefix length.
111             self.body_range = (self.body_range.start + prefix.len())..self.body_range.end;
112             true
113         } else {
114             false
115         }
116     }
117 
118     /// Return a mutable reference to slice of the packet buffer corresponding
119     /// to the current body.
into_body(self) -> &'a mut [u8]120     pub fn into_body(self) -> &'a mut [u8] {
121         // SAFETY: The public interface of `PacketBuf` ensures that `self.body_range`
122         // always stays within the bounds of the provided buffer.
123         #[cfg(not(feature = "paranoid_unsafe"))]
124         unsafe {
125             self.buf.get_unchecked_mut(self.body_range)
126         }
127 
128         #[cfg(feature = "paranoid_unsafe")]
129         &mut self.buf[self.body_range]
130     }
131 
132     /// Return a mutable reference to the _entire_ underlying packet buffer, and
133     /// the current body's range.
into_raw_buf(self) -> (&'a mut [u8], core::ops::Range<usize>)134     pub fn into_raw_buf(self) -> (&'a mut [u8], core::ops::Range<usize>) {
135         (self.buf, self.body_range)
136     }
137 
138     /// Returns the length of the _entire_ underlying packet buffer - not just
139     /// the length of the current range.
140     ///
141     /// This method is used when handing the `qSupported` packet in order to
142     /// obtain the maximum packet size the stub supports.
full_len(&self) -> usize143     pub fn full_len(&self) -> usize {
144         self.buf.len()
145     }
146 }
147 
148 impl<'a> Packet<'a> {
from_buf( target: &mut impl Target, buf: &'a mut [u8], ) -> Result<Packet<'a>, PacketParseError>149     pub fn from_buf(
150         target: &mut impl Target,
151         buf: &'a mut [u8],
152     ) -> Result<Packet<'a>, PacketParseError> {
153         // cannot have empty packet
154         if buf.is_empty() {
155             return Err(PacketParseError::EmptyBuf);
156         }
157 
158         match buf[0] {
159             b'$' => Ok(Packet::Command(
160                 Command::from_packet(target, PacketBuf::new(buf)?)
161                     .ok_or(PacketParseError::MalformedCommand)?,
162             )),
163             b'+' => Ok(Packet::Ack),
164             b'-' => Ok(Packet::Nack),
165             0x03 => Ok(Packet::Interrupt),
166             _ => Err(PacketParseError::UnexpectedHeader(buf[0])),
167         }
168     }
169 }
170