1use crate::protocol::packet::PacketBuf;
2use crate::target::Target;
3use paste::paste;
4
5pub 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
17pub trait ParseCommand<'a>: Sized {
18 fn from_packet(buf: PacketBuf<'a>) -> Option<Self>;
20}
21
22macro_rules! commands {
23 (
24 $(
25 $ext:ident $(use $lt:lifetime)? {
26 $($name:literal => $mod:ident::$command:ident$(<$lifetime:lifetime>)?,)*
27 }
28 )*
29 ) => {paste! {
30 $($(
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, clippy::upper_case_acronyms)]
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 #[allow(dead_code)]
66 ZWithBytecode(BytecodeBreakpoint<'a>),
67 }
68
69 }
70
71 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 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 $(
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 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
230commands! {
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 flash_operations use 'a {
306 "vFlashErase" => _vFlashErase::vFlashErase<'a>,
307 "vFlashWrite" => _vFlashWrite::vFlashWrite<'a>,
308 "vFlashDone" => _vFlashDone::vFlashDone,
309 }
310
311 auxv use 'a {
312 "qXfer:auxv:read" => _qXfer_auxv_read::qXferAuxvRead<'a>,
313 }
314
315 exec_file use 'a {
316 "qXfer:exec-file:read" => _qXfer_exec_file::qXferExecFileRead<'a>,
317 }
318
319 host_io use 'a {
320 "vFile:open" => _vFile_open::vFileOpen<'a>,
321 "vFile:close" => _vFile_close::vFileClose,
322 "vFile:pread" => _vFile_pread::vFilePread<'a>,
323 "vFile:pwrite" => _vFile_pwrite::vFilePwrite<'a>,
324 "vFile:fstat" => _vFile_fstat::vFileFstat,
325 "vFile:unlink" => _vFile_unlink::vFileUnlink<'a>,
326 "vFile:readlink" => _vFile_readlink::vFileReadlink<'a>,
327 "vFile:setfs" => _vFile_setfs::vFileSetfs,
328 }
329
330 catch_syscalls use 'a {
331 "QCatchSyscalls" => _QCatchSyscalls::QCatchSyscalls<'a>,
332 }
333
334 thread_extra_info use 'a {
335 "qThreadExtraInfo" => _qThreadExtraInfo::qThreadExtraInfo<'a>,
336 }
337
338 lldb_register_info {
339 "qRegisterInfo" => _qRegisterInfo::qRegisterInfo,
340 }
341
342 libraries_svr4 use 'a {
343 "qXfer:libraries-svr4:read" => _qXfer_libraries_svr4_read::qXferLibrariesSvr4Read<'a>,
344 }
345
346 tracepoints use 'a {
347 "QTDPsrc" => _QTDPsrc::QTDPsrc<'a>,
348 "QTDP" => _QTDP::QTDP<'a>,
349 "QTinit" => _QTinit::QTinit,
350 "QTBuffer" => _QTBuffer_upcase::QTBuffer,
351 "QTStart" => _QTStart::QTStart,
352 "QTStop" => _QTStop::QTStop,
353 "QTFrame" => _QTFrame::QTFrame<'a>,
354
355 "qTBuffer" => _qTBuffer::qTBuffer,
356 "qTStatus" => _qTStatus::qTStatus,
357 "qTP" => _qTP::qTP<'a>,
358 "qTfP" => _qTfP::qTfP,
359 "qTsP" => _qTsP::qTsP,
360
361 "qTfV" => _qTfV::qTfV,
363 "qTsV" => _qTsV::qTsV,
364 }
365}