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