• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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