1 use super::prelude::*; 2 use crate::arch::Arch; 3 use crate::internal::BeBytes; 4 use crate::protocol::commands::_QTDPsrc::QTDPsrc; 5 use crate::protocol::commands::_qTBuffer::qTBuffer; 6 use crate::protocol::commands::ext::Tracepoints; 7 use crate::protocol::commands::prelude::decode_hex; 8 use crate::protocol::commands::prelude::decode_hex_buf; 9 use crate::protocol::commands::_QTDP::CreateTDP; 10 use crate::protocol::commands::_QTDP::ExtendTDP; 11 use crate::protocol::commands::_QTDP::QTDP; 12 use crate::protocol::ResponseWriterError; 13 use crate::target::ext::tracepoints::ExperimentExplanation; 14 use crate::target::ext::tracepoints::ExperimentStatus; 15 use crate::target::ext::tracepoints::FrameDescription; 16 use crate::target::ext::tracepoints::FrameRequest; 17 use crate::target::ext::tracepoints::NewTracepoint; 18 use crate::target::ext::tracepoints::SourceTracepoint; 19 use crate::target::ext::tracepoints::Tracepoint; 20 use crate::target::ext::tracepoints::TracepointAction; 21 use crate::target::ext::tracepoints::TracepointEnumerateCursor; 22 use crate::target::ext::tracepoints::TracepointEnumerateStep; 23 use crate::target::ext::tracepoints::TracepointSourceType; 24 use crate::target::ext::tracepoints::TracepointStatus; 25 use managed::ManagedSlice; 26 use num_traits::PrimInt; 27 28 impl<U: BeBytes> NewTracepoint<U> { 29 /// Parse from a raw CreateTDP packet. from_tdp(ctdp: CreateTDP<'_>) -> Option<(Self, bool)>30 fn from_tdp(ctdp: CreateTDP<'_>) -> Option<(Self, bool)> { 31 Some(( 32 Self { 33 number: ctdp.number, 34 addr: U::from_be_bytes(ctdp.addr)?, 35 enabled: ctdp.enable, 36 pass_count: ctdp.pass, 37 step_count: ctdp.step, 38 }, 39 ctdp.more, 40 )) 41 } 42 } 43 44 impl<U: crate::internal::BeBytes + num_traits::Zero + PrimInt> NewTracepoint<U> { 45 /// Write this as a qTfP/qTsP response write<T: Target, C: Connection>( &self, res: &mut ResponseWriter<'_, C>, ) -> Result<(), Error<T::Error, C::Error>>46 pub(crate) fn write<T: Target, C: Connection>( 47 &self, 48 res: &mut ResponseWriter<'_, C>, 49 ) -> Result<(), Error<T::Error, C::Error>> { 50 res.write_str("T")?; 51 res.write_num(self.number.0)?; 52 res.write_str(":")?; 53 res.write_num(self.addr)?; 54 res.write_str(":")?; 55 res.write_str(if self.enabled { "E" } else { "D" })?; 56 res.write_str(":")?; 57 res.write_num(self.step_count)?; 58 res.write_str(":")?; 59 res.write_num(self.pass_count)?; 60 61 Ok(()) 62 } 63 } 64 65 /// A list of actions that a tracepoint should be extended with. 66 #[derive(Debug)] 67 pub(crate) struct ExtendTracepoint<'a, U> { 68 /// The tracepoint that is having actions appended to its definition. 69 pub number: Tracepoint, 70 /// The PC address of the tracepoint that is being extended. 71 /// This is currently unused information sent as part of the packet by GDB, 72 /// but may be required for implementing while-stepping actions later. 73 #[allow(dead_code)] 74 pub addr: U, 75 /// The unparsed action data. 76 pub data: ManagedSlice<'a, u8>, 77 } 78 79 impl<'a, U: BeBytes> ExtendTracepoint<'a, U> { 80 /// Parse from a raw ExtendTDP packet. from_tdp(dtdp: ExtendTDP<'a>) -> Option<Self>81 fn from_tdp(dtdp: ExtendTDP<'a>) -> Option<Self> { 82 Some(Self { 83 number: dtdp.number, 84 addr: U::from_be_bytes(dtdp.addr)?, 85 data: ManagedSlice::Borrowed(dtdp.actions), 86 }) 87 } 88 89 /// Parse the actions that should be added to the definition of this 90 /// tracepoint, calling `f` on each action. 91 /// 92 /// Returns `Err` if parsing of actions failed, or hit unsupported actions. 93 /// Return `Ok(more)` on success, where more indicates if more actions are 94 /// expect in later packets. If the actions weren't from a GDB packet, more 95 /// is None. actions<T, C>( mut self, f: impl FnMut(&TracepointAction<'_, U>), ) -> Result<Option<bool>, Error<T, C>>96 pub(crate) fn actions<T, C>( 97 mut self, 98 f: impl FnMut(&TracepointAction<'_, U>), 99 ) -> Result<Option<bool>, Error<T, C>> { 100 Self::parse_raw_actions(&mut self.data, f) 101 } 102 parse_raw_actions<T, C>( actions: &mut [u8], mut f: impl FnMut(&TracepointAction<'_, U>), ) -> Result<Option<bool>, Error<T, C>>103 fn parse_raw_actions<T, C>( 104 actions: &mut [u8], 105 mut f: impl FnMut(&TracepointAction<'_, U>), 106 ) -> Result<Option<bool>, Error<T, C>> { 107 let (actions, more) = match actions { 108 [rest @ .., b'-'] => (rest, true), 109 x => (x, false), 110 }; 111 // TODO: There's no "packet unsupported", so for now we stub out unimplemented 112 // functionality by reporting the commands malformed instead. 113 use crate::protocol::PacketParseError::MalformedCommand; 114 let mut unparsed: Option<&mut [u8]> = Some(actions); 115 loop { 116 match unparsed { 117 Some([b'S', ..]) => { 118 // TODO: how can gdbstub even implement this? it changes how 119 // future packets should be interpreted, but as a trait we 120 // can't keep a flag around for that (unless we specifically 121 // have a `mark_while_stepping` callback for the target to 122 // keep track future tracepoint_extends should be treated different). 123 // If we go that route we also would need to return two vectors 124 // here, "normal" actions and "while stepping" actions...but 125 // "normals" actions may still be "while stepping" actions, 126 // just continued from the previous packet, which we forgot 127 // about! 128 // 129 // We use 'W' to indicate "while-stepping", since we're already 130 // using 'S' elsewhere for static tracepoints. 131 return Err(Error::TracepointFeatureUnimplemented(b'W')); 132 } 133 Some([b'R', mask @ ..]) => { 134 let mask_end = mask 135 .iter() 136 .enumerate() 137 .find(|(_i, b)| matches!(b, b'S' | b'R' | b'M' | b'X')); 138 // We may or may not have another action after our mask 139 let mask = if let Some(mask_end) = mask_end { 140 let (mask_bytes, next) = mask.split_at_mut(mask_end.0); 141 unparsed = Some(next); 142 decode_hex_buf(mask_bytes).or(Err(Error::PacketParse(MalformedCommand)))? 143 } else { 144 unparsed = None; 145 decode_hex_buf(mask).or(Err(Error::PacketParse(MalformedCommand)))? 146 }; 147 (f)(&TracepointAction::Registers { 148 mask: ManagedSlice::Borrowed(mask), 149 }); 150 } 151 Some([b'M', _mem_args @ ..]) => { 152 // Unimplemented: even simple actions like `collect *(int*)0x0` 153 // are actually assembled as `X` bytecode actions 154 return Err(Error::TracepointFeatureUnimplemented(b'M')); 155 } 156 Some([b'X', eval_args @ ..]) => { 157 let mut len_end = eval_args.splitn_mut(2, |b| *b == b','); 158 let (len_bytes, rem) = ( 159 len_end.next().ok_or(Error::PacketParse(MalformedCommand))?, 160 len_end.next().ok_or(Error::PacketParse(MalformedCommand))?, 161 ); 162 let len: usize = 163 decode_hex(len_bytes).or(Err(Error::PacketParse(MalformedCommand)))?; 164 if rem.len() < len * 2 { 165 return Err(Error::PacketParse(MalformedCommand)); 166 } 167 let (expr_bytes, next_bytes) = rem.split_at_mut(len * 2); 168 let expr = 169 decode_hex_buf(expr_bytes).or(Err(Error::PacketParse(MalformedCommand)))?; 170 (f)(&TracepointAction::Expression { 171 expr: ManagedSlice::Borrowed(expr), 172 }); 173 unparsed = Some(next_bytes); 174 } 175 Some([]) | None => { 176 break; 177 } 178 _ => return Err(Error::PacketParse(MalformedCommand)), 179 } 180 } 181 182 Ok(Some(more)) 183 } 184 } 185 186 impl<'a, U: BeBytes> SourceTracepoint<'a, U> { 187 /// Parse from a raw CreateTDP packet. from_src(src: QTDPsrc<'a>) -> Option<Self>188 fn from_src(src: QTDPsrc<'a>) -> Option<Self> { 189 Some(Self { 190 number: src.number, 191 addr: U::from_be_bytes(src.addr)?, 192 kind: src.kind, 193 start: src.start, 194 slen: src.slen, 195 bytes: ManagedSlice::Borrowed(src.bytes), 196 }) 197 } 198 } 199 impl<U: crate::internal::BeBytes + num_traits::Zero + PrimInt> SourceTracepoint<'_, U> { 200 /// Write this as a qTfP/qTsP response write<T: Target, C: Connection>( &self, res: &mut ResponseWriter<'_, C>, ) -> Result<(), Error<T::Error, C::Error>>201 pub(crate) fn write<T: Target, C: Connection>( 202 &self, 203 res: &mut ResponseWriter<'_, C>, 204 ) -> Result<(), Error<T::Error, C::Error>> { 205 res.write_str("Z")?; 206 res.write_num(self.number.0)?; 207 res.write_str(":")?; 208 res.write_num(self.addr)?; 209 res.write_str(":")?; 210 res.write_str(match self.kind { 211 TracepointSourceType::At => "at", 212 TracepointSourceType::Cond => "cond", 213 TracepointSourceType::Cmd => "cmd", 214 })?; 215 res.write_str(":")?; 216 // We use the start and slen from the SourceTracepoint instead of 217 // start=0 slen=bytes.len() because, although we can assume GDB to be able 218 // to handle arbitrary sized packets, the target implementation might still 219 // be giving us chunked source (such as if it's parroting the chunked source 220 // that GDB initially gave us). 221 res.write_num(self.start)?; 222 res.write_str(":")?; 223 res.write_num(self.slen)?; 224 res.write_str(":")?; 225 res.write_hex_buf(self.bytes.as_ref())?; 226 227 Ok(()) 228 } 229 } 230 231 impl<U: crate::internal::BeBytes + num_traits::Zero + PrimInt> TracepointAction<'_, U> { 232 /// Write this as a qTfP/qTsP response write<T: Target, C: Connection>( &self, tp: Tracepoint, addr: U, res: &mut ResponseWriter<'_, C>, ) -> Result<(), Error<T::Error, C::Error>>233 pub(crate) fn write<T: Target, C: Connection>( 234 &self, 235 tp: Tracepoint, 236 addr: U, 237 res: &mut ResponseWriter<'_, C>, 238 ) -> Result<(), Error<T::Error, C::Error>> { 239 res.write_str("A")?; 240 res.write_num(tp.0)?; 241 res.write_str(":")?; 242 res.write_num(addr)?; 243 res.write_str(":")?; 244 245 match self { 246 TracepointAction::Registers { mask } => { 247 res.write_str("R")?; 248 res.write_hex_buf(mask)?; 249 } 250 TracepointAction::Memory { 251 basereg, 252 offset, 253 length, 254 } => { 255 res.write_str("M")?; 256 match basereg { 257 Some(r) => res.write_num(*r), 258 None => res.write_str("-1"), 259 }?; 260 res.write_str(",")?; 261 res.write_num(*offset)?; 262 res.write_str(",")?; 263 res.write_num(*length)?; 264 } 265 TracepointAction::Expression { expr } => { 266 res.write_str("X")?; 267 res.write_num(expr.len())?; 268 res.write_str(",")?; 269 res.write_hex_buf(expr)?; 270 } 271 } 272 Ok(()) 273 } 274 } 275 276 impl ExperimentStatus<'_> { write<C: Connection>( &self, res: &mut ResponseWriter<'_, C>, ) -> Result<(), ResponseWriterError<C::Error>>277 pub(crate) fn write<C: Connection>( 278 &self, 279 res: &mut ResponseWriter<'_, C>, 280 ) -> Result<(), ResponseWriterError<C::Error>> { 281 use crate::target::ext::tracepoints::ExperimentStatus::*; 282 if let Running = self { 283 return res.write_str("T1"); 284 } 285 // We're stopped for some reason, and may have an explanation for why 286 res.write_str("T0")?; 287 match self { 288 Running => { /* unreachable */ } 289 NotRunning => { /* no information */ } 290 NotRun => res.write_str(";tnotrun:0")?, 291 Stop(ref t) => match t { 292 Some(text) => { 293 res.write_str(";tstop:")?; 294 res.write_hex_buf(text)?; 295 res.write_str(":0")?; 296 } 297 None => res.write_str(";tstop:0")?, 298 }, 299 Full => res.write_str(";tfull:0")?, 300 Disconnected => res.write_str(";tdisconnected:0")?, 301 PassCount(tpnum) => { 302 res.write_str(";tpasscount:")?; 303 res.write_num(tpnum.0)?; 304 } 305 Error(text, tpnum) => { 306 res.write_str(";terror:")?; 307 res.write_hex_buf(text)?; 308 res.write_str(":")?; 309 res.write_num(tpnum.0)?; 310 } 311 Unknown => res.write_str(";tunknown:0")?, 312 } 313 314 Ok(()) 315 } 316 } 317 318 impl ExperimentExplanation<'_> { write<T: Target, C: Connection>( &self, res: &mut ResponseWriter<'_, C>, ) -> Result<(), Error<T::Error, C::Error>>319 pub(crate) fn write<T: Target, C: Connection>( 320 &self, 321 res: &mut ResponseWriter<'_, C>, 322 ) -> Result<(), Error<T::Error, C::Error>> { 323 use ExperimentExplanation::*; 324 match self { 325 Frames(u) => { 326 res.write_str("tframes:")?; 327 res.write_num(*u)?; 328 } 329 Created(u) => { 330 res.write_str("tcreated:")?; 331 res.write_num(*u)?; 332 } 333 Size(u) => { 334 res.write_str("tsize:")?; 335 res.write_num(*u)?; 336 } 337 Free(u) => { 338 res.write_str("tfree:")?; 339 res.write_num(*u)?; 340 } 341 Circular(u) => { 342 res.write_str("circular:")?; 343 res.write_num(if *u { 1 } else { 0 })?; 344 } 345 DisconnectedTracing(dis) => match dis { 346 true => res.write_str("disconn:1")?, 347 false => res.write_str("disconn:0")?, 348 }, 349 Other(body) => res.write_str(body.as_ref())?, 350 }; 351 352 Ok(()) 353 } 354 } 355 356 impl<'a, U: crate::internal::BeBytes> From<FrameRequest<&'a mut [u8]>> for Option<FrameRequest<U>> { from(s: FrameRequest<&'a mut [u8]>) -> Self357 fn from(s: FrameRequest<&'a mut [u8]>) -> Self { 358 Some(match s { 359 FrameRequest::Select(u) => FrameRequest::Select(u), 360 FrameRequest::AtPC(u) => FrameRequest::AtPC(U::from_be_bytes(u)?), 361 FrameRequest::Hit(tp) => FrameRequest::Hit(tp), 362 FrameRequest::Between(s, e) => { 363 FrameRequest::Between(U::from_be_bytes(s)?, U::from_be_bytes(e)?) 364 } 365 FrameRequest::Outside(s, e) => { 366 FrameRequest::Outside(U::from_be_bytes(s)?, U::from_be_bytes(e)?) 367 } 368 }) 369 } 370 } 371 372 impl<T: Target, C: Connection> GdbStubImpl<T, C> { handle_tracepoints( &mut self, res: &mut ResponseWriter<'_, C>, target: &mut T, command: Tracepoints<'_>, ) -> Result<HandlerStatus, Error<T::Error, C::Error>>373 pub(crate) fn handle_tracepoints( 374 &mut self, 375 res: &mut ResponseWriter<'_, C>, 376 target: &mut T, 377 command: Tracepoints<'_>, 378 ) -> Result<HandlerStatus, Error<T::Error, C::Error>> { 379 let ops = match target.support_tracepoints() { 380 Some(ops) => ops, 381 None => return Ok(HandlerStatus::Handled), 382 }; 383 384 crate::__dead_code_marker!("tracepoints", "impl"); 385 386 match command { 387 Tracepoints::QTinit(_) => { 388 ops.tracepoints_init().handle_error()?; 389 // GDB documentation doesn't say it, but this requires "OK" in order 390 // to signify we support tracepoints. 391 return Ok(HandlerStatus::NeedsOk); 392 } 393 Tracepoints::qTStatus(_) => { 394 let mut err: Option<Error<T::Error, C::Error>> = None; 395 let mut has_status = false; 396 ops.trace_experiment_status(&mut |status: ExperimentStatus<'_>| { 397 // If the target implementation calls us multiple times, then 398 // we would erroneously serialize an invalid response. Guard 399 // against it in the simplest way. 400 if has_status { 401 return; 402 } 403 if let Err(e) = status.write(res) { 404 err = Some(e.into()) 405 } else { 406 has_status = true; 407 } 408 }) 409 .handle_error()?; 410 if has_status { 411 // Only bother trying to get info if we also have a status 412 ops.trace_experiment_info(&mut |explanation: ExperimentExplanation<'_>| { 413 if let Err(e) = res 414 .write_str(";") 415 .map_err(|e| e.into()) 416 .and_then(|()| explanation.write::<T, C>(res)) 417 { 418 err = Some(e) 419 } 420 }) 421 .handle_error()?; 422 } 423 424 if let Some(e) = err { 425 return Err(e); 426 } 427 } 428 Tracepoints::qTP(qtp) => { 429 let addr = <T::Arch as Arch>::Usize::from_be_bytes(qtp.addr) 430 .ok_or(Error::TargetMismatch)?; 431 let TracepointStatus { 432 hit_count, 433 bytes_used, 434 } = ops.tracepoint_status(qtp.tracepoint, addr).handle_error()?; 435 res.write_str("V")?; 436 res.write_num(hit_count)?; 437 res.write_str(":")?; 438 res.write_num(bytes_used)?; 439 } 440 Tracepoints::QTDP(q) => { 441 match q { 442 QTDP::Create(ctdp) => { 443 if let Some(feat) = ctdp.unsupported_option { 444 // We have some options we don't know how to process, so bail out. 445 return Err(Error::TracepointFeatureUnimplemented(feat)); 446 } 447 448 let (new_tracepoint, more) = 449 NewTracepoint::<<T::Arch as Arch>::Usize>::from_tdp(ctdp) 450 .ok_or(Error::TargetMismatch)?; 451 let tp = new_tracepoint.number; 452 ops.tracepoint_create_begin(new_tracepoint).handle_error()?; 453 if !more { 454 ops.tracepoint_create_complete(tp).handle_error()?; 455 } 456 } 457 QTDP::Extend(dtdp) => { 458 let extend_tracepoint = 459 ExtendTracepoint::<<T::Arch as Arch>::Usize>::from_tdp(dtdp) 460 .ok_or(Error::TargetMismatch)?; 461 let tp = extend_tracepoint.number; 462 let mut err: Option<Error<T::Error, C::Error>> = None; 463 let more = extend_tracepoint.actions(|action| { 464 if let Err(e) = 465 ops.tracepoint_create_continue(tp, action).handle_error() 466 { 467 err = Some(e) 468 } 469 }); 470 if let Some(e) = err { 471 return Err(e); 472 } 473 match more { 474 Ok(Some(true)) => { 475 // We expect additional QTDP packets, so don't 476 // complete it yet. 477 } 478 Ok(None) | Ok(Some(false)) => { 479 ops.tracepoint_create_complete(tp).handle_error()?; 480 } 481 Err(e) => { 482 return Err(e); 483 } 484 } 485 } 486 }; 487 // TODO: support qRelocInsn? 488 return Ok(HandlerStatus::NeedsOk); 489 } 490 Tracepoints::QTDPsrc(src) => { 491 if let Some(supports_sources) = ops.support_tracepoint_source() { 492 let source = SourceTracepoint::<<T::Arch as Arch>::Usize>::from_src(src) 493 .ok_or(Error::TargetMismatch)?; 494 supports_sources 495 .tracepoint_attach_source(source) 496 .handle_error()?; 497 // Documentation doesn't mention this, but it needs OK 498 return Ok(HandlerStatus::NeedsOk); 499 } 500 } 501 Tracepoints::qTBuffer(buf) => { 502 let qTBuffer { offset, length } = buf; 503 let mut wrote: Result<bool, Error<T::Error, C::Error>> = Ok(false); 504 ops.trace_buffer_request(offset, length, &mut |data| { 505 if let Err(e) = res.write_hex_buf(data) { 506 wrote = Err(e.into()) 507 } else { 508 wrote = Ok(true) 509 } 510 }) 511 .handle_error()?; 512 if !wrote? { 513 res.write_str("l")?; 514 } 515 } 516 Tracepoints::QTBuffer(conf) => { 517 ops.trace_buffer_configure(conf.0).handle_error()?; 518 // Documentation doesn't mention this, but it needs OK 519 return Ok(HandlerStatus::NeedsOk); 520 } 521 Tracepoints::QTStart(_) => { 522 ops.trace_experiment_start().handle_error()?; 523 // Documentation doesn't mention this, but it needs OK 524 // TODO: qRelocInsn reply support? 525 return Ok(HandlerStatus::NeedsOk); 526 } 527 Tracepoints::QTStop(_) => { 528 ops.trace_experiment_stop().handle_error()?; 529 // Documentation doesn't mention this, but it needs OK 530 return Ok(HandlerStatus::NeedsOk); 531 } 532 Tracepoints::QTFrame(req) => { 533 let parsed_qtframe: Option<FrameRequest<<T::Arch as Arch>::Usize>> = req.0.into(); 534 let parsed_req = parsed_qtframe.ok_or(Error::TargetMismatch)?; 535 let mut err: Result<_, Error<T::Error, C::Error>> = Ok(()); 536 let mut any_results = false; 537 ops.select_frame(parsed_req, &mut |desc| { 538 let e = (|| -> Result<_, _> { 539 match desc { 540 FrameDescription::FrameNumber(n) => { 541 res.write_str("F")?; 542 res.write_num(n)?; 543 any_results = true; 544 } 545 FrameDescription::Hit(tdp) => { 546 res.write_str("T")?; 547 res.write_num(tdp.0)?; 548 } 549 } 550 Ok(()) 551 })(); 552 if let Err(e) = e { 553 err = Err(e) 554 } 555 }) 556 .handle_error()?; 557 if !any_results { 558 res.write_str("F-1")?; 559 } 560 } 561 // The GDB protocol for this is very weird: it sends this first packet 562 // to initialize a state machine on our stub, and then sends the subsequent 563 // packets N times in order to drive the state machine to the end in 564 // order to ask for all our tracepoints and their actions. gdbstub 565 // uses a target allocated state machine that it drives in response 566 // to these packets, so that it can provide a nice typed API. 567 Tracepoints::qTfP(_) => { 568 // Reset our state machine 569 let state = ops.tracepoint_enumerate_state(); 570 state.cursor = None; 571 572 let mut err: Option<Error<T::Error, C::Error>> = None; 573 let mut started = None; 574 let step = ops 575 .tracepoint_enumerate_start(None, &mut |ctp| { 576 // We need to know what tracepoint to begin stepping, since the 577 // target will just tell us there's TracepointEnumerateStep::More 578 // otherwise. 579 started = Some((ctp.number, ctp.addr)); 580 let e = ctp.write::<T, C>(res); 581 if let Err(e) = e { 582 err = Some(e) 583 } 584 }) 585 .handle_error()?; 586 if let Some(e) = err { 587 return Err(e); 588 } 589 if let Some((tp, addr)) = started { 590 ops.tracepoint_enumerate_state().cursor = 591 Some(TracepointEnumerateCursor::New { tp, addr }); 592 } 593 self.handle_tracepoint_state_machine_step(target, step)?; 594 } 595 Tracepoints::qTsP(_) => { 596 let state = ops.tracepoint_enumerate_state(); 597 let mut err: Option<Error<T::Error, C::Error>> = None; 598 let step = match state.cursor { 599 None => { 600 // If we don't have a cursor, than the last 601 // packet responded 602 // with a TracepointEnumerateStep::Done. We don't have 603 // anything else to report. 604 None 605 } 606 Some(TracepointEnumerateCursor::New { tp, .. }) => { 607 // If we don't have any progress, the last packet was 608 // a Next(tp) and we need to start reporting a new tracepoint 609 Some( 610 ops.tracepoint_enumerate_start(Some(tp), &mut |ctp| { 611 let e = ctp.write::<T, C>(res); 612 if let Err(e) = e { 613 err = Some(e) 614 } 615 }) 616 .handle_error()?, 617 ) 618 } 619 Some(TracepointEnumerateCursor::Action { tp, addr, step }) => { 620 // Otherwise we should be continuing the advance the current tracepoint. 621 Some( 622 ops.tracepoint_enumerate_action(tp, step, &mut |action| { 623 let e = action.write::<T, C>(tp, addr, res); 624 if let Err(e) = e { 625 err = Some(e) 626 } 627 }) 628 .handle_error()?, 629 ) 630 } 631 Some(TracepointEnumerateCursor::Source { tp, step, .. }) => { 632 if let Some(supports_sources) = ops.support_tracepoint_source() { 633 Some( 634 supports_sources 635 .tracepoint_enumerate_source(tp, step, &mut |src| { 636 let e = src.write::<T, C>(res); 637 if let Err(e) = e { 638 err = Some(e) 639 } 640 }) 641 .handle_error()?, 642 ) 643 } else { 644 // If the target doesn't support tracepoint sources but told 645 // us to enumerate one anyways, then the target has an error. 646 return Err(Error::TracepointUnsupportedSourceEnumeration); 647 } 648 } 649 }; 650 651 if let Some(e) = err { 652 return Err(e); 653 } 654 if let Some(step) = step { 655 self.handle_tracepoint_state_machine_step(target, step)?; 656 } 657 } 658 659 // Likewise, the same type of driven state machine is used for trace 660 // state variables 661 Tracepoints::qTfV(_) => { 662 // TODO: State variables 663 } 664 Tracepoints::qTsV(_) => { 665 // TODO: State variables 666 } 667 }; 668 669 Ok(HandlerStatus::Handled) 670 } 671 handle_tracepoint_state_machine_step( &mut self, target: &mut T, step: TracepointEnumerateStep<<T::Arch as Arch>::Usize>, ) -> Result<(), Error<T::Error, C::Error>>672 fn handle_tracepoint_state_machine_step( 673 &mut self, 674 target: &mut T, 675 step: TracepointEnumerateStep<<T::Arch as Arch>::Usize>, 676 ) -> Result<(), Error<T::Error, C::Error>> { 677 let ops = match target.support_tracepoints() { 678 Some(ops) => ops, 679 None => return Ok(()), 680 }; 681 let state = ops.tracepoint_enumerate_state(); 682 let next = match (state.cursor.as_ref(), step) { 683 (None, _) => None, 684 (Some(_), TracepointEnumerateStep::Done) => None, 685 686 // Transition to enumerating actions 687 ( 688 Some(&TracepointEnumerateCursor::New { tp, addr }), 689 TracepointEnumerateStep::Action, 690 ) => Some(TracepointEnumerateCursor::Action { tp, addr, step: 0 }), 691 ( 692 Some(&TracepointEnumerateCursor::Source { tp, addr, .. }), 693 TracepointEnumerateStep::Action, 694 ) => Some(TracepointEnumerateCursor::Action { tp, addr, step: 0 }), 695 ( 696 Some(&TracepointEnumerateCursor::Action { tp, addr, step }), 697 TracepointEnumerateStep::Action, 698 ) => Some(TracepointEnumerateCursor::Action { 699 tp, 700 addr, 701 step: step + 1, 702 }), 703 704 // Transition to enumerating sources 705 ( 706 Some( 707 &TracepointEnumerateCursor::New { tp, addr } 708 | &TracepointEnumerateCursor::Action { tp, addr, .. }, 709 ), 710 TracepointEnumerateStep::Source, 711 ) => Some(TracepointEnumerateCursor::Source { tp, addr, step: 0 }), 712 ( 713 Some(&TracepointEnumerateCursor::Source { tp, addr, step }), 714 TracepointEnumerateStep::Source, 715 ) => Some(TracepointEnumerateCursor::Source { 716 tp, 717 addr, 718 step: step + 1, 719 }), 720 721 // Transition to the next tracepoint 722 (Some(_), TracepointEnumerateStep::Next { tp, addr }) => { 723 Some(TracepointEnumerateCursor::New { tp, addr }) 724 } 725 }; 726 state.cursor = next; 727 728 Ok(()) 729 } 730 } 731