1 #[cfg(feature = "trace-pkt")] 2 use alloc::string::String; 3 #[cfg(feature = "trace-pkt")] 4 use alloc::vec::Vec; 5 6 use num_traits::identities::one; 7 use num_traits::{CheckedRem, PrimInt}; 8 9 use crate::conn::Connection; 10 use crate::internal::BeBytes; 11 use crate::protocol::{SpecificIdKind, SpecificThreadId}; 12 13 /// Newtype around a Connection error. Having a newtype allows implementing a 14 /// `From<ResponseWriterError<C>> for crate::Error<T, C>`, which greatly 15 /// simplifies some of the error handling in the main gdbstub. 16 #[derive(Debug, Clone)] 17 pub struct Error<C>(pub C); 18 19 /// A wrapper around [`Connection`] that computes the single-byte checksum of 20 /// incoming / outgoing data. 21 pub struct ResponseWriter<'a, C: Connection> { 22 inner: &'a mut C, 23 started: bool, 24 checksum: u8, 25 26 rle_enabled: bool, 27 rle_char: u8, 28 rle_repeat: u8, 29 30 // buffer to log outgoing packets. only allocates if logging is enabled. 31 #[cfg(feature = "trace-pkt")] 32 msg: Vec<u8>, 33 } 34 35 impl<'a, C: Connection + 'a> ResponseWriter<'a, C> { 36 /// Creates a new ResponseWriter new(inner: &'a mut C, rle_enabled: bool) -> Self37 pub fn new(inner: &'a mut C, rle_enabled: bool) -> Self { 38 Self { 39 inner, 40 started: false, 41 checksum: 0, 42 43 rle_enabled, 44 rle_char: 0, 45 rle_repeat: 0, 46 47 #[cfg(feature = "trace-pkt")] 48 msg: Vec::new(), 49 } 50 } 51 52 /// Consumes self, writing out the final '#' and checksum flush(mut self) -> Result<(), Error<C::Error>>53 pub fn flush(mut self) -> Result<(), Error<C::Error>> { 54 // don't include the '#' in checksum calculation 55 let checksum = if self.rle_enabled { 56 self.write(b'#')?; 57 // (note: even though `self.write` was called, the the '#' char hasn't been 58 // added to the checksum, and is just sitting in the RLE buffer) 59 self.checksum 60 } else { 61 let checksum = self.checksum; 62 self.write(b'#')?; 63 checksum 64 }; 65 66 self.write_hex(checksum)?; 67 68 // HACK: "write" a dummy char to force an RLE flush 69 if self.rle_enabled { 70 self.write(0)?; 71 } 72 73 #[cfg(feature = "trace-pkt")] 74 trace!("--> ${}", String::from_utf8_lossy(&self.msg)); 75 76 self.inner.flush().map_err(Error)?; 77 78 Ok(()) 79 } 80 81 /// Get a mutable reference to the underlying connection. as_conn(&mut self) -> &mut C82 pub fn as_conn(&mut self) -> &mut C { 83 self.inner 84 } 85 inner_write(&mut self, byte: u8) -> Result<(), Error<C::Error>>86 fn inner_write(&mut self, byte: u8) -> Result<(), Error<C::Error>> { 87 #[cfg(feature = "trace-pkt")] 88 if log_enabled!(log::Level::Trace) { 89 if self.rle_enabled { 90 match self.msg.as_slice() { 91 [.., c, b'*'] => { 92 let c = *c; 93 self.msg.pop(); 94 for _ in 0..(byte - 29) { 95 self.msg.push(c); 96 } 97 } 98 _ => self.msg.push(byte), 99 } 100 } else { 101 self.msg.push(byte) 102 } 103 } 104 105 if !self.started { 106 self.started = true; 107 self.inner.write(b'$').map_err(Error)?; 108 } 109 110 self.checksum = self.checksum.wrapping_add(byte); 111 self.inner.write(byte).map_err(Error) 112 } 113 write(&mut self, byte: u8) -> Result<(), Error<C::Error>>114 fn write(&mut self, byte: u8) -> Result<(), Error<C::Error>> { 115 if !self.rle_enabled { 116 return self.inner_write(byte); 117 } 118 119 const ASCII_FIRST_PRINT: u8 = b' '; 120 const ASCII_LAST_PRINT: u8 = b'~'; 121 122 // handle RLE 123 let rle_printable = (ASCII_FIRST_PRINT - 4 + (self.rle_repeat + 1)) <= ASCII_LAST_PRINT; 124 if byte == self.rle_char && rle_printable { 125 self.rle_repeat += 1; 126 Ok(()) 127 } else { 128 loop { 129 match self.rle_repeat { 130 0 => {} // happens once, after the first char is written 131 // RLE doesn't win, just output the byte 132 1 | 2 | 3 => { 133 for _ in 0..self.rle_repeat { 134 self.inner_write(self.rle_char)? 135 } 136 } 137 // RLE would output an invalid char ('#' or '$') 138 6 | 7 => { 139 self.inner_write(self.rle_char)?; 140 self.rle_repeat -= 1; 141 continue; 142 } 143 // RLE wins for repetitions >4 144 _ => { 145 self.inner_write(self.rle_char)?; 146 self.inner_write(b'*')?; 147 self.inner_write(ASCII_FIRST_PRINT - 4 + self.rle_repeat)?; 148 } 149 } 150 151 self.rle_char = byte; 152 self.rle_repeat = 1; 153 154 break Ok(()); 155 } 156 } 157 } 158 159 /// Write an entire string over the connection. write_str(&mut self, s: &str) -> Result<(), Error<C::Error>>160 pub fn write_str(&mut self, s: &str) -> Result<(), Error<C::Error>> { 161 for b in s.as_bytes().iter() { 162 self.write(*b)?; 163 } 164 Ok(()) 165 } 166 167 /// Write a single byte as a hex string (two ascii chars) write_hex(&mut self, byte: u8) -> Result<(), Error<C::Error>>168 fn write_hex(&mut self, byte: u8) -> Result<(), Error<C::Error>> { 169 for &digit in [(byte & 0xf0) >> 4, byte & 0x0f].iter() { 170 let c = match digit { 171 0..=9 => b'0' + digit, 172 10..=15 => b'a' + digit - 10, 173 // This match arm is unreachable, but the compiler isn't smart enough to optimize 174 // out the branch. As such, using `unreachable!` here would introduce panicking 175 // code to `gdbstub`. 176 // 177 // In this case, it'd be totally reasonable to use 178 // `unsafe { core::hint::unreachable_unchecked() }`, but i'll be honest, using some 179 // spooky unsafe compiler hints just to eek out a smidge more performance here just 180 // isn't worth the cognitive overhead. 181 // 182 // Moreover, I've played around with this code in godbolt.org, and it turns out that 183 // leaving this match arm as `=> digit` ends up generating the _exact same code_ as 184 // using `unreachable_unchecked` (at least on x86_64 targets compiled using the 185 // latest Rust compiler). YMMV on other platforms. 186 _ => digit, 187 }; 188 self.write(c)?; 189 } 190 Ok(()) 191 } 192 193 /// 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>>194 pub fn write_hex_buf(&mut self, data: &[u8]) -> Result<(), Error<C::Error>> { 195 for b in data.iter() { 196 self.write_hex(*b)?; 197 } 198 Ok(()) 199 } 200 201 /// Write data using the binary protocol. write_binary(&mut self, data: &[u8]) -> Result<(), Error<C::Error>>202 pub fn write_binary(&mut self, data: &[u8]) -> Result<(), Error<C::Error>> { 203 for &b in data.iter() { 204 match b { 205 b'#' | b'$' | b'}' | b'*' => { 206 self.write(b'}')?; 207 self.write(b ^ 0x20)? 208 } 209 _ => self.write(b)?, 210 } 211 } 212 Ok(()) 213 } 214 215 /// Write a number as a big-endian hex string using the most compact 216 /// representation possible (i.e: trimming leading zeros). write_num<D: BeBytes + PrimInt>(&mut self, digit: D) -> Result<(), Error<C::Error>>217 pub fn write_num<D: BeBytes + PrimInt>(&mut self, digit: D) -> Result<(), Error<C::Error>> { 218 if digit.is_zero() { 219 return self.write_hex(0); 220 } 221 222 let mut buf = [0; 16]; 223 // infallible (unless digit is a >128 bit number) 224 let len = digit.to_be_bytes(&mut buf).unwrap(); 225 let buf = &buf[..len]; 226 for b in buf.iter().copied().skip_while(|&b| b == 0) { 227 self.write_hex(b)? 228 } 229 Ok(()) 230 } 231 232 /// Write a number as a decimal string, converting every digit to an ascii 233 /// char. write_dec<D: PrimInt + CheckedRem>( &mut self, mut digit: D, ) -> Result<(), Error<C::Error>>234 pub fn write_dec<D: PrimInt + CheckedRem>( 235 &mut self, 236 mut digit: D, 237 ) -> Result<(), Error<C::Error>> { 238 if digit.is_zero() { 239 return self.write(b'0'); 240 } 241 242 let one: D = one(); 243 let ten = (one << 3) + (one << 1); 244 let mut d = digit; 245 let mut pow_10 = one; 246 // Get the number of digits in digit 247 while d >= ten { 248 d = d / ten; 249 pow_10 = pow_10 * ten; 250 } 251 252 // Write every digit from left to right as an ascii char 253 while !pow_10.is_zero() { 254 let mut byte = 0; 255 // We have a single digit here which uses up to 4 bit 256 for i in 0..4 { 257 if !((digit / pow_10) & (one << i)).is_zero() { 258 byte += 1 << i; 259 } 260 } 261 self.write(b'0' + byte)?; 262 digit = digit % pow_10; 263 pow_10 = pow_10 / ten; 264 } 265 Ok(()) 266 } 267 268 #[inline] write_specific_id_kind(&mut self, tid: SpecificIdKind) -> Result<(), Error<C::Error>>269 fn write_specific_id_kind(&mut self, tid: SpecificIdKind) -> Result<(), Error<C::Error>> { 270 match tid { 271 SpecificIdKind::All => self.write_str("-1")?, 272 SpecificIdKind::WithId(id) => self.write_num(id.get())?, 273 }; 274 Ok(()) 275 } 276 write_specific_thread_id( &mut self, tid: SpecificThreadId, ) -> Result<(), Error<C::Error>>277 pub fn write_specific_thread_id( 278 &mut self, 279 tid: SpecificThreadId, 280 ) -> Result<(), Error<C::Error>> { 281 if let Some(pid) = tid.pid { 282 self.write_str("p")?; 283 self.write_specific_id_kind(pid)?; 284 self.write_str(".")?; 285 } 286 self.write_specific_id_kind(tid.tid)?; 287 Ok(()) 288 } 289 } 290