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