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