1 use num_traits::PrimInt; 2 3 use crate::internal::BeBytes; 4 use crate::protocol::{SpecificIdKind, SpecificThreadId}; 5 use crate::Connection; 6 7 /// Newtype around a Connection error. Having a newtype allows implementing a 8 /// `From<ResponseWriterError<C>> for crate::Error<T, C>`, which greatly 9 /// simplifies some of the error handling in the main gdbstub. 10 #[derive(Debug, Clone)] 11 pub struct Error<C>(pub C); 12 13 /// A wrapper around [`Connection`] that computes the single-byte checksum of 14 /// incoming / outgoing data. 15 pub struct ResponseWriter<'a, C: Connection + 'a> { 16 // TODO: add `write_all` method to Connection, and allow user to optionally pass outgoing 17 // packet buffer? This could improve performance (instead of writing a single byte at a time) 18 inner: &'a mut C, 19 started: bool, 20 checksum: u8, 21 // TODO?: Make using RLE configurable by the target? 22 // if implemented correctly, targets that disable RLE entirely could have all RLE code 23 // dead-code-eliminated. 24 rle_char: u8, 25 rle_repeat: u8, 26 // buffer to log outgoing packets. only allocates if logging is enabled. 27 #[cfg(feature = "std")] 28 msg: Vec<u8>, 29 } 30 31 impl<'a, C: Connection + 'a> ResponseWriter<'a, C> { 32 /// Creates a new ResponseWriter new(inner: &'a mut C) -> Self33 pub fn new(inner: &'a mut C) -> Self { 34 Self { 35 inner, 36 started: false, 37 checksum: 0, 38 rle_char: 0, 39 rle_repeat: 0, 40 #[cfg(feature = "std")] 41 msg: Vec::new(), 42 } 43 } 44 45 /// Consumes self, writing out the final '#' and checksum flush(mut self) -> Result<(), Error<C::Error>>46 pub fn flush(mut self) -> Result<(), Error<C::Error>> { 47 self.write(b'#')?; 48 49 // don't include the '#' in checksum calculation 50 // (note: even though `self.write` was called, the the '#' char hasn't been 51 // added to the checksum, and is just sitting in the RLE buffer) 52 let checksum = self.checksum; 53 54 #[cfg(feature = "std")] 55 trace!( 56 "--> ${}#{:02x?}", 57 core::str::from_utf8(&self.msg).unwrap(), // buffers are always ascii 58 checksum 59 ); 60 61 self.write_hex(checksum)?; 62 // HACK: "write" a dummy char to force an RLE flush 63 self.write(0)?; 64 65 self.inner.flush().map_err(Error)?; 66 67 Ok(()) 68 } 69 70 /// Get a mutable reference to the underlying connection. as_conn(&mut self) -> &mut C71 pub fn as_conn(&mut self) -> &mut C { 72 self.inner 73 } 74 inner_write(&mut self, byte: u8) -> Result<(), Error<C::Error>>75 fn inner_write(&mut self, byte: u8) -> Result<(), Error<C::Error>> { 76 #[cfg(feature = "std")] 77 if log_enabled!(log::Level::Trace) { 78 match self.msg.as_slice() { 79 [.., c, b'*'] => { 80 let c = *c; 81 self.msg.pop(); 82 for _ in 0..(byte - 29) { 83 self.msg.push(c); 84 } 85 } 86 _ => self.msg.push(byte), 87 } 88 } 89 90 if !self.started { 91 self.started = true; 92 self.inner.write(b'$').map_err(Error)?; 93 } 94 95 self.checksum = self.checksum.wrapping_add(byte); 96 self.inner.write(byte).map_err(Error) 97 } 98 write(&mut self, byte: u8) -> Result<(), Error<C::Error>>99 fn write(&mut self, byte: u8) -> Result<(), Error<C::Error>> { 100 const ASCII_FIRST_PRINT: u8 = b' '; 101 const ASCII_LAST_PRINT: u8 = b'~'; 102 103 // handle RLE 104 let rle_printable = (ASCII_FIRST_PRINT - 4 + (self.rle_repeat + 1)) <= ASCII_LAST_PRINT; 105 if byte == self.rle_char && rle_printable { 106 self.rle_repeat += 1; 107 Ok(()) 108 } else { 109 loop { 110 match self.rle_repeat { 111 0 => {} // happens once, after the first char is written 112 // RLE doesn't win, just output the byte 113 1 | 2 | 3 => { 114 for _ in 0..self.rle_repeat { 115 self.inner_write(self.rle_char)? 116 } 117 } 118 // RLE would output an invalid char ('#' or '$') 119 6 | 7 => { 120 self.inner_write(self.rle_char)?; 121 self.rle_repeat -= 1; 122 continue; 123 } 124 // RLE wins for repetitions >4 125 _ => { 126 self.inner_write(self.rle_char)?; 127 self.inner_write(b'*')?; 128 self.inner_write(ASCII_FIRST_PRINT - 4 + self.rle_repeat)?; 129 } 130 } 131 132 self.rle_char = byte; 133 self.rle_repeat = 1; 134 135 break Ok(()); 136 } 137 } 138 } 139 140 /// Write an entire string over the connection. write_str(&mut self, s: &'static str) -> Result<(), Error<C::Error>>141 pub fn write_str(&mut self, s: &'static str) -> Result<(), Error<C::Error>> { 142 for b in s.as_bytes().iter() { 143 self.write(*b)?; 144 } 145 Ok(()) 146 } 147 148 /// Write a single byte as a hex string (two ascii chars) write_hex(&mut self, byte: u8) -> Result<(), Error<C::Error>>149 fn write_hex(&mut self, byte: u8) -> Result<(), Error<C::Error>> { 150 for digit in [(byte & 0xf0) >> 4, byte & 0x0f].iter() { 151 let c = match digit { 152 0..=9 => b'0' + digit, 153 10..=15 => b'a' + digit - 10, 154 _ => unreachable!(), 155 }; 156 self.write(c)?; 157 } 158 Ok(()) 159 } 160 161 /// Write a byte-buffer as a hex string (i.e: two ascii chars / byte). write_hex_buf(&mut self, data: &[u8]) -> Result<(), Error<C::Error>>162 pub fn write_hex_buf(&mut self, data: &[u8]) -> Result<(), Error<C::Error>> { 163 for b in data.iter() { 164 self.write_hex(*b)?; 165 } 166 Ok(()) 167 } 168 169 /// Write data using the binary protocol. write_binary(&mut self, data: &[u8]) -> Result<(), Error<C::Error>>170 pub fn write_binary(&mut self, data: &[u8]) -> Result<(), Error<C::Error>> { 171 for &b in data.iter() { 172 match b { 173 b'#' | b'$' | b'}' | b'*' => { 174 self.write(b'}')?; 175 self.write(b ^ 0x20)? 176 } 177 _ => self.write(b)?, 178 } 179 } 180 Ok(()) 181 } 182 183 /// Write a number as a big-endian hex string using the most compact 184 /// representation possible (i.e: trimming leading zeros). write_num<D: BeBytes + PrimInt>(&mut self, digit: D) -> Result<(), Error<C::Error>>185 pub fn write_num<D: BeBytes + PrimInt>(&mut self, digit: D) -> Result<(), Error<C::Error>> { 186 if digit.is_zero() { 187 return self.write_hex(0); 188 } 189 190 let mut buf = [0; 16]; 191 // infallible (unless digit is a >128 bit number) 192 let len = digit.to_be_bytes(&mut buf).unwrap(); 193 let buf = &buf[..len]; 194 for b in buf.iter().copied().skip_while(|&b| b == 0) { 195 self.write_hex(b)? 196 } 197 Ok(()) 198 } 199 write_specific_id_kind(&mut self, tid: SpecificIdKind) -> Result<(), Error<C::Error>>200 fn write_specific_id_kind(&mut self, tid: SpecificIdKind) -> Result<(), Error<C::Error>> { 201 match tid { 202 SpecificIdKind::All => self.write_str("-1")?, 203 SpecificIdKind::WithId(id) => self.write_num(id.get())?, 204 }; 205 Ok(()) 206 } 207 write_specific_thread_id( &mut self, tid: SpecificThreadId, ) -> Result<(), Error<C::Error>>208 pub fn write_specific_thread_id( 209 &mut self, 210 tid: SpecificThreadId, 211 ) -> Result<(), Error<C::Error>> { 212 if let Some(pid) = tid.pid { 213 self.write_str("p")?; 214 self.write_specific_id_kind(pid)?; 215 self.write_str(".")?; 216 } 217 self.write_specific_id_kind(tid.tid)?; 218 Ok(()) 219 } 220 } 221