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