• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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