• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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                 ZWithBytecode(BytecodeBreakpoint<'a>),
65             }
66 
67         }
68 
69         /// GDB commands
70         pub enum Command<'a> {
71             $(
72                 [<$ext:camel>](ext::[<$ext:camel>]$(<$lt>)?),
73             )*
74             Breakpoints(ext::Breakpoints<'a>),
75             Unknown(&'a [u8]),
76         }
77 
78         impl<'a> Command<'a> {
79             pub fn from_packet(
80                 target: &mut impl Target,
81                 mut buf: PacketBuf<'a>
82             ) -> Option<Command<'a>> {
83                 // HACK: this locally-scoped trait enables using identifiers
84                 // that aren't top-level `Target` IDETs to split-up the packet
85                 // parsing code.
86                 trait Hack {
87                     fn support_base(&mut self) -> Option<()>;
88                     fn support_target_xml(&mut self) -> Option<()>;
89                     fn support_lldb_register_info(&mut self) -> Option<()>;
90                     fn support_resume(&mut self) -> Option<()>;
91                     fn support_single_register_access(&mut self) -> Option<()>;
92                     fn support_reverse_step(&mut self) -> Option<()>;
93                     fn support_reverse_cont(&mut self) -> Option<()>;
94                     fn support_no_ack_mode(&mut self) -> Option<()>;
95                     fn support_x_upcase_packet(&mut self) -> Option<()>;
96                     fn support_thread_extra_info(&mut self) -> Option<()>;
97                 }
98 
99                 impl<T: Target> Hack for T {
100                     fn support_base(&mut self) -> Option<()> {
101                         Some(())
102                     }
103 
104                     fn support_target_xml(&mut self) -> Option<()> {
105                         use crate::arch::Arch;
106                         if self.use_target_description_xml()
107                             && (T::Arch::target_description_xml().is_some()
108                                 || self.support_target_description_xml_override().is_some())
109                         {
110                             Some(())
111                         } else {
112                             None
113                         }
114                     }
115 
116                     fn support_lldb_register_info(&mut self) -> Option<()> {
117                         use crate::arch::Arch;
118                         if self.use_lldb_register_info()
119                             && (T::Arch::lldb_register_info(usize::max_value()).is_some()
120                                 || self.support_lldb_register_info_override().is_some())
121                         {
122                             Some(())
123                         } else {
124                             None
125                         }
126                     }
127 
128                     fn support_resume(&mut self) -> Option<()> {
129                         self.base_ops().resume_ops().map(drop)
130                     }
131 
132                     fn support_single_register_access(&mut self) -> Option<()> {
133                         use crate::target::ext::base::BaseOps;
134                         match self.base_ops() {
135                             BaseOps::SingleThread(ops) => ops.support_single_register_access().map(drop),
136                             BaseOps::MultiThread(ops) => ops.support_single_register_access().map(drop),
137                         }
138                     }
139 
140                     fn support_reverse_step(&mut self) -> Option<()> {
141                         use crate::target::ext::base::ResumeOps;
142                         match self.base_ops().resume_ops()? {
143                             ResumeOps::SingleThread(ops) => ops.support_reverse_step().map(drop),
144                             ResumeOps::MultiThread(ops) => ops.support_reverse_step().map(drop),
145                         }
146                     }
147 
148                     fn support_reverse_cont(&mut self) -> Option<()> {
149                         use crate::target::ext::base::ResumeOps;
150                         match self.base_ops().resume_ops()? {
151                             ResumeOps::SingleThread(ops) => ops.support_reverse_cont().map(drop),
152                             ResumeOps::MultiThread(ops) => ops.support_reverse_cont().map(drop),
153                         }
154                     }
155 
156                     fn support_x_upcase_packet(&mut self) -> Option<()> {
157                         if self.use_x_upcase_packet() {
158                             Some(())
159                         } else {
160                             None
161                         }
162                     }
163 
164                     fn support_no_ack_mode(&mut self) -> Option<()> {
165                         if self.use_no_ack_mode() {
166                             Some(())
167                         } else {
168                             None
169                         }
170                     }
171 
172                     fn support_thread_extra_info(&mut self) -> Option<()> {
173                         use crate::target::ext::base::BaseOps;
174                         match self.base_ops() {
175                             BaseOps::SingleThread(_) => None,
176                             BaseOps::MultiThread(ops) => ops.support_thread_extra_info().map(drop),
177                         }
178                     }
179                 }
180 
181                 // TODO?: use tries for more efficient longest prefix matching
182 
183                 $(
184                 #[allow(clippy::string_lit_as_bytes)]
185                 if target.[< support_ $ext >]().is_some() {
186                     $(
187                     if buf.strip_prefix($name.as_bytes()) {
188                         crate::__dead_code_marker!($name, "prefix_match");
189 
190                         let cmd = $mod::$command::from_packet(buf)?;
191 
192                         return Some(
193                             Command::[<$ext:camel>](
194                                 ext::[<$ext:camel>]::$command(cmd)
195                             )
196                         )
197                     }
198                     )*
199                 }
200                 )*
201 
202                 if let Some(_breakpoint_ops) = target.support_breakpoints() {
203                     use breakpoint::{BasicBreakpoint, BytecodeBreakpoint};
204 
205                     if buf.strip_prefix(b"z") {
206                         let cmd = BasicBreakpoint::from_slice(buf.into_body())?;
207                         return Some(Command::Breakpoints(ext::Breakpoints::z(cmd)))
208                     }
209 
210                     if buf.strip_prefix(b"Z") {
211                         // TODO: agent bytecode currently unimplemented
212                         if true {
213                             let cmd = BasicBreakpoint::from_slice(buf.into_body())?;
214                             return Some(Command::Breakpoints(ext::Breakpoints::Z(cmd)))
215                         } else {
216                             let cmd = BytecodeBreakpoint::from_slice(buf.into_body())?;
217                             return Some(Command::Breakpoints(ext::Breakpoints::ZWithBytecode(cmd)))
218                         }
219                     }
220                 }
221 
222                 Some(Command::Unknown(buf.into_body()))
223             }
224         }
225     }};
226 }
227 
228 commands! {
229     base use 'a {
230         "?" => question_mark::QuestionMark,
231         "D" => _d_upcase::D,
232         "g" => _g::g,
233         "G" => _g_upcase::G<'a>,
234         "H" => _h_upcase::H,
235         "k" => _k::k,
236         "m" => _m::m<'a>,
237         "M" => _m_upcase::M<'a>,
238         "qAttached" => _qAttached::qAttached,
239         "qfThreadInfo" => _qfThreadInfo::qfThreadInfo,
240         "qsThreadInfo" => _qsThreadInfo::qsThreadInfo,
241         "qSupported" => _qSupported::qSupported<'a>,
242         "T" => _t_upcase::T,
243         "vKill" => _vKill::vKill,
244     }
245 
246     target_xml use 'a {
247         "qXfer:features:read" => _qXfer_features_read::qXferFeaturesRead<'a>,
248     }
249 
250     resume use 'a {
251         "c" => _c::c<'a>,
252         "s" => _s::s<'a>,
253         "vCont" => _vCont::vCont<'a>,
254     }
255 
256     x_upcase_packet use 'a {
257         "X" => _x_upcase::X<'a>,
258     }
259 
260     no_ack_mode {
261         "QStartNoAckMode" => _QStartNoAckMode::QStartNoAckMode,
262     }
263 
264     single_register_access use 'a {
265         "p" => _p::p<'a>,
266         "P" => _p_upcase::P<'a>,
267     }
268 
269     extended_mode use 'a {
270         "!" => exclamation_mark::ExclamationMark,
271         "qC" => _qC::qC,
272         "QDisableRandomization" => _QDisableRandomization::QDisableRandomization,
273         "QEnvironmentHexEncoded" => _QEnvironmentHexEncoded::QEnvironmentHexEncoded<'a>,
274         "QEnvironmentReset" => _QEnvironmentReset::QEnvironmentReset,
275         "QEnvironmentUnset" => _QEnvironmentUnset::QEnvironmentUnset<'a>,
276         "QSetWorkingDir" => _QSetWorkingDir::QSetWorkingDir<'a>,
277         "QStartupWithShell" => _QStartupWithShell::QStartupWithShell,
278         "R" => _r_upcase::R,
279         "vAttach" => _vAttach::vAttach,
280         "vRun" => _vRun::vRun<'a>,
281     }
282 
283     monitor_cmd use 'a {
284         "qRcmd" => _qRcmd::qRcmd<'a>,
285     }
286 
287     section_offsets {
288         "qOffsets" => _qOffsets::qOffsets,
289     }
290 
291     reverse_cont {
292         "bc" => _bc::bc,
293     }
294 
295     reverse_step {
296         "bs" => _bs::bs,
297     }
298 
299     memory_map use 'a {
300         "qXfer:memory-map:read" => _qXfer_memory_map::qXferMemoryMapRead<'a>,
301     }
302 
303     auxv use 'a {
304         "qXfer:auxv:read" => _qXfer_auxv_read::qXferAuxvRead<'a>,
305     }
306 
307     exec_file use 'a {
308         "qXfer:exec-file:read" => _qXfer_exec_file::qXferExecFileRead<'a>,
309     }
310 
311     host_io use 'a {
312         "vFile:open" => _vFile_open::vFileOpen<'a>,
313         "vFile:close" => _vFile_close::vFileClose,
314         "vFile:pread" => _vFile_pread::vFilePread<'a>,
315         "vFile:pwrite" => _vFile_pwrite::vFilePwrite<'a>,
316         "vFile:fstat" => _vFile_fstat::vFileFstat,
317         "vFile:unlink" => _vFile_unlink::vFileUnlink<'a>,
318         "vFile:readlink" => _vFile_readlink::vFileReadlink<'a>,
319         "vFile:setfs" => _vFile_setfs::vFileSetfs,
320     }
321 
322     catch_syscalls use 'a {
323         "QCatchSyscalls" => _QCatchSyscalls::QCatchSyscalls<'a>,
324     }
325 
326     thread_extra_info use 'a {
327         "qThreadExtraInfo" => _qThreadExtraInfo::qThreadExtraInfo<'a>,
328     }
329 
330     lldb_register_info {
331         "qRegisterInfo" => _qRegisterInfo::qRegisterInfo,
332     }
333 
334     libraries_svr4 use 'a {
335         "qXfer:libraries-svr4:read" => _qXfer_libraries_svr4_read::qXferLibrariesSvr4Read<'a>,
336     }
337 }
338