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