1  use crate::protocol::packet::PacketBuf;
2  use crate::target::Target;
3  use paste::paste;
4  
5  /// Common imports used by >50% of all packet parsers.
6  ///
7  /// Do not clutter this prelude with types only used by a few packets.
8  pub mod prelude {
9      pub use crate::protocol::commands::ParseCommand;
10      pub use crate::protocol::common::hex::decode_hex;
11      pub use crate::protocol::common::hex::decode_hex_buf;
12      pub use crate::protocol::packet::PacketBuf;
13      pub use core::convert::TryFrom;
14      pub use core::convert::TryInto;
15  }
16  
17  pub trait ParseCommand<'a>: Sized {
18      /// Try to parse a packet from the packet buffer.
from_packet(buf: PacketBuf<'a>) -> Option<Self>19      fn from_packet(buf: PacketBuf<'a>) -> Option<Self>;
20  }
21  
22  macro_rules! commands {
23      (
24          $(
25              $ext:ident $(use $lt:lifetime)? {
26                  $($name:literal => $mod:ident::$command:ident$(<$lifetime:lifetime>)?,)*
27              }
28          )*
29      ) => {paste! {
30          // Most packets follow a consistent model of "only enabled when a
31          // particular IDET is implemented", but there are some exceptions to
32          // this rule that need to be special-cased:
33          //
34          // # Breakpoint packets (z, Z)
35          //
36          // Breakpoint packets are special-cased, as the "Z" packet is parsed
37          // differently depending on whether or not the target implements the
38          // `Agent` extension.
39          //
40          // While it's entirely possible to eagerly parse the "Z" packet for
41          // bytecode, doing so would unnecessary bloat implementations that do
42          // not support evaluating agent expressions.
43  
44  
45          $($(
46              #[allow(non_snake_case, non_camel_case_types)]
47              pub mod $mod;
48          )*)*
49          pub mod breakpoint;
50  
51          pub mod ext {
52              $(
53                  #[allow(non_camel_case_types, clippy::enum_variant_names)]
54                  pub enum [<$ext:camel>] $(<$lt>)? {
55                      $($command(super::$mod::$command<$($lifetime)?>),)*
56                  }
57              )*
58  
59              use super::breakpoint::{BasicBreakpoint, BytecodeBreakpoint};
60              #[allow(non_camel_case_types)]
61              pub enum Breakpoints<'a> {
62                  z(BasicBreakpoint<'a>),
63                  Z(BasicBreakpoint<'a>),
64                  // Bytecode hasn't yet been plumbed all the way through
65                  #[allow(dead_code)]
66                  ZWithBytecode(BytecodeBreakpoint<'a>),
67              }
68  
69          }
70  
71          /// GDB commands
72          pub enum Command<'a> {
73              $(
74                  [<$ext:camel>](ext::[<$ext:camel>]$(<$lt>)?),
75              )*
76              Breakpoints(ext::Breakpoints<'a>),
77              Unknown(&'a [u8]),
78          }
79  
80          impl<'a> Command<'a> {
81              pub fn from_packet(
82                  target: &mut impl Target,
83                  mut buf: PacketBuf<'a>
84              ) -> Option<Command<'a>> {
85                  // HACK: this locally-scoped trait enables using identifiers
86                  // that aren't top-level `Target` IDETs to split-up the packet
87                  // parsing code.
88                  trait Hack {
89                      fn support_base(&mut self) -> Option<()>;
90                      fn support_target_xml(&mut self) -> Option<()>;
91                      fn support_lldb_register_info(&mut self) -> Option<()>;
92                      fn support_resume(&mut self) -> Option<()>;
93                      fn support_single_register_access(&mut self) -> Option<()>;
94                      fn support_reverse_step(&mut self) -> Option<()>;
95                      fn support_reverse_cont(&mut self) -> Option<()>;
96                      fn support_no_ack_mode(&mut self) -> Option<()>;
97                      fn support_x_upcase_packet(&mut self) -> Option<()>;
98                      fn support_thread_extra_info(&mut self) -> Option<()>;
99                  }
100  
101                  impl<T: Target> Hack for T {
102                      fn support_base(&mut self) -> Option<()> {
103                          Some(())
104                      }
105  
106                      fn support_target_xml(&mut self) -> Option<()> {
107                          use crate::arch::Arch;
108                          if self.use_target_description_xml()
109                              && (T::Arch::target_description_xml().is_some()
110                                  || self.support_target_description_xml_override().is_some())
111                          {
112                              Some(())
113                          } else {
114                              None
115                          }
116                      }
117  
118                      fn support_lldb_register_info(&mut self) -> Option<()> {
119                          use crate::arch::Arch;
120                          if self.use_lldb_register_info()
121                              && (T::Arch::lldb_register_info(usize::MAX).is_some()
122                                  || self.support_lldb_register_info_override().is_some())
123                          {
124                              Some(())
125                          } else {
126                              None
127                          }
128                      }
129  
130                      fn support_resume(&mut self) -> Option<()> {
131                          self.base_ops().resume_ops().map(drop)
132                      }
133  
134                      fn support_single_register_access(&mut self) -> Option<()> {
135                          use crate::target::ext::base::BaseOps;
136                          match self.base_ops() {
137                              BaseOps::SingleThread(ops) => ops.support_single_register_access().map(drop),
138                              BaseOps::MultiThread(ops) => ops.support_single_register_access().map(drop),
139                          }
140                      }
141  
142                      fn support_reverse_step(&mut self) -> Option<()> {
143                          use crate::target::ext::base::ResumeOps;
144                          match self.base_ops().resume_ops()? {
145                              ResumeOps::SingleThread(ops) => ops.support_reverse_step().map(drop),
146                              ResumeOps::MultiThread(ops) => ops.support_reverse_step().map(drop),
147                          }
148                      }
149  
150                      fn support_reverse_cont(&mut self) -> Option<()> {
151                          use crate::target::ext::base::ResumeOps;
152                          match self.base_ops().resume_ops()? {
153                              ResumeOps::SingleThread(ops) => ops.support_reverse_cont().map(drop),
154                              ResumeOps::MultiThread(ops) => ops.support_reverse_cont().map(drop),
155                          }
156                      }
157  
158                      fn support_x_upcase_packet(&mut self) -> Option<()> {
159                          if self.use_x_upcase_packet() {
160                              Some(())
161                          } else {
162                              None
163                          }
164                      }
165  
166                      fn support_no_ack_mode(&mut self) -> Option<()> {
167                          if self.use_no_ack_mode() {
168                              Some(())
169                          } else {
170                              None
171                          }
172                      }
173  
174                      fn support_thread_extra_info(&mut self) -> Option<()> {
175                          use crate::target::ext::base::BaseOps;
176                          match self.base_ops() {
177                              BaseOps::SingleThread(_) => None,
178                              BaseOps::MultiThread(ops) => ops.support_thread_extra_info().map(drop),
179                          }
180                      }
181                  }
182  
183                  // TODO?: use tries for more efficient longest prefix matching
184  
185                  $(
186                  #[allow(clippy::string_lit_as_bytes)]
187                  if target.[< support_ $ext >]().is_some() {
188                      $(
189                      if buf.strip_prefix($name.as_bytes()) {
190                          crate::__dead_code_marker!($name, "prefix_match");
191  
192                          let cmd = $mod::$command::from_packet(buf)?;
193  
194                          return Some(
195                              Command::[<$ext:camel>](
196                                  ext::[<$ext:camel>]::$command(cmd)
197                              )
198                          )
199                      }
200                      )*
201                  }
202                  )*
203  
204                  if let Some(_breakpoint_ops) = target.support_breakpoints() {
205                      use breakpoint::{BasicBreakpoint, BytecodeBreakpoint};
206  
207                      if buf.strip_prefix(b"z") {
208                          let cmd = BasicBreakpoint::from_slice(buf.into_body())?;
209                          return Some(Command::Breakpoints(ext::Breakpoints::z(cmd)))
210                      }
211  
212                      if buf.strip_prefix(b"Z") {
213                          // TODO: agent bytecode currently unimplemented
214                          if true {
215                              let cmd = BasicBreakpoint::from_slice(buf.into_body())?;
216                              return Some(Command::Breakpoints(ext::Breakpoints::Z(cmd)))
217                          } else {
218                              let cmd = BytecodeBreakpoint::from_slice(buf.into_body())?;
219                              return Some(Command::Breakpoints(ext::Breakpoints::ZWithBytecode(cmd)))
220                          }
221                      }
222                  }
223  
224                  Some(Command::Unknown(buf.into_body()))
225              }
226          }
227      }};
228  }
229  
230  commands! {
231      base use 'a {
232          "?" => question_mark::QuestionMark,
233          "D" => _d_upcase::D,
234          "g" => _g::g,
235          "G" => _g_upcase::G<'a>,
236          "H" => _h_upcase::H,
237          "k" => _k::k,
238          "m" => _m::m<'a>,
239          "M" => _m_upcase::M<'a>,
240          "qAttached" => _qAttached::qAttached,
241          "qfThreadInfo" => _qfThreadInfo::qfThreadInfo,
242          "qsThreadInfo" => _qsThreadInfo::qsThreadInfo,
243          "qSupported" => _qSupported::qSupported<'a>,
244          "T" => _t_upcase::T,
245          "vKill" => _vKill::vKill,
246      }
247  
248      target_xml use 'a {
249          "qXfer:features:read" => _qXfer_features_read::qXferFeaturesRead<'a>,
250      }
251  
252      resume use 'a {
253          "c" => _c::c<'a>,
254          "s" => _s::s<'a>,
255          "vCont" => _vCont::vCont<'a>,
256      }
257  
258      x_upcase_packet use 'a {
259          "X" => _x_upcase::X<'a>,
260      }
261  
262      no_ack_mode {
263          "QStartNoAckMode" => _QStartNoAckMode::QStartNoAckMode,
264      }
265  
266      single_register_access use 'a {
267          "p" => _p::p<'a>,
268          "P" => _p_upcase::P<'a>,
269      }
270  
271      extended_mode use 'a {
272          "!" => exclamation_mark::ExclamationMark,
273          "qC" => _qC::qC,
274          "QDisableRandomization" => _QDisableRandomization::QDisableRandomization,
275          "QEnvironmentHexEncoded" => _QEnvironmentHexEncoded::QEnvironmentHexEncoded<'a>,
276          "QEnvironmentReset" => _QEnvironmentReset::QEnvironmentReset,
277          "QEnvironmentUnset" => _QEnvironmentUnset::QEnvironmentUnset<'a>,
278          "QSetWorkingDir" => _QSetWorkingDir::QSetWorkingDir<'a>,
279          "QStartupWithShell" => _QStartupWithShell::QStartupWithShell,
280          "R" => _r_upcase::R,
281          "vAttach" => _vAttach::vAttach,
282          "vRun" => _vRun::vRun<'a>,
283      }
284  
285      monitor_cmd use 'a {
286          "qRcmd" => _qRcmd::qRcmd<'a>,
287      }
288  
289      section_offsets {
290          "qOffsets" => _qOffsets::qOffsets,
291      }
292  
293      reverse_cont {
294          "bc" => _bc::bc,
295      }
296  
297      reverse_step {
298          "bs" => _bs::bs,
299      }
300  
301      memory_map use 'a {
302          "qXfer:memory-map:read" => _qXfer_memory_map::qXferMemoryMapRead<'a>,
303      }
304  
305      auxv use 'a {
306          "qXfer:auxv:read" => _qXfer_auxv_read::qXferAuxvRead<'a>,
307      }
308  
309      exec_file use 'a {
310          "qXfer:exec-file:read" => _qXfer_exec_file::qXferExecFileRead<'a>,
311      }
312  
313      host_io use 'a {
314          "vFile:open" => _vFile_open::vFileOpen<'a>,
315          "vFile:close" => _vFile_close::vFileClose,
316          "vFile:pread" => _vFile_pread::vFilePread<'a>,
317          "vFile:pwrite" => _vFile_pwrite::vFilePwrite<'a>,
318          "vFile:fstat" => _vFile_fstat::vFileFstat,
319          "vFile:unlink" => _vFile_unlink::vFileUnlink<'a>,
320          "vFile:readlink" => _vFile_readlink::vFileReadlink<'a>,
321          "vFile:setfs" => _vFile_setfs::vFileSetfs,
322      }
323  
324      catch_syscalls use 'a {
325          "QCatchSyscalls" => _QCatchSyscalls::QCatchSyscalls<'a>,
326      }
327  
328      thread_extra_info use 'a {
329          "qThreadExtraInfo" => _qThreadExtraInfo::qThreadExtraInfo<'a>,
330      }
331  
332      lldb_register_info {
333          "qRegisterInfo" => _qRegisterInfo::qRegisterInfo,
334      }
335  
336      libraries_svr4 use 'a {
337          "qXfer:libraries-svr4:read" => _qXfer_libraries_svr4_read::qXferLibrariesSvr4Read<'a>,
338      }
339  }
340