• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Support for
2 //! [Tracepoint](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Tracepoints.html)
3 //! extensions.
4 //!
5 //! ## Implementation Status
6 //!
7 //! Most fundamental tracepoint operations are supported, but there quite a few
8 //! packets / APIs that are not yet implemented, such as:
9 //!
10 //! - Fast Tracepoints
11 //! - Tracepoint Conditions
12 //! - Trace State Variables
13 //!
14 //! If you are interested in extending this API to support these additional
15 //! features, please consider opening an Issue / PR on the `gdbstub` GitHub
16 //! repo.
17 
18 use crate::target::Arch;
19 use crate::target::Target;
20 use crate::target::TargetResult;
21 use managed::ManagedSlice;
22 
23 /// A tracepoint, identified by a unique number.
24 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
25 pub struct Tracepoint(pub usize);
26 
27 /// A state variable, identified by a unique number.
28 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
29 pub struct StateVariable(usize);
30 
31 /// Describes a new tracepoint. GDB may ask for the state of current
32 /// tracepoints, which are described with this same structure.
33 #[derive(Debug, Clone)]
34 pub struct NewTracepoint<U> {
35     /// The tracepoint number
36     pub number: Tracepoint,
37     /// If the tracepoint is enabled or not
38     pub enabled: bool,
39     /// The address the tracepoint is set at.
40     pub addr: U,
41     /// The tracepoint's step count
42     pub step_count: u64,
43     /// The tracepoint's pass count.
44     pub pass_count: u64,
45 }
46 
47 /// Describes how to collect information for a trace frame when the tracepoint
48 /// it is attached to is hit. A tracepoint may have more than one action
49 /// attached.
50 #[derive(Debug)]
51 pub enum TracepointAction<'a, U> {
52     /// Collect registers.
53     Registers {
54         /// A bitmask of which registers should be collected. The least
55         /// significant bit is numberered zero. Note that the mask may
56         /// be larger than the word length.
57         mask: ManagedSlice<'a, u8>,
58     },
59     /// Collect memory.`len` bytes of memory starting at the address in register
60     /// number `basereg`, plus `offset`. If `basereg` is None, then treat it
61     /// as a fixed address.
62     Memory {
63         /// If `Some`, then calculate the address of memory to collect relative
64         /// to the value of this register number. If `None` then memory
65         /// should be collected from a fixed address.
66         basereg: Option<u64>,
67         /// The offset used to calculate the address to collect memory from.
68         offset: U,
69         /// How many bytes of memory to collect.
70         length: u64,
71     },
72     /// Collect data according to an agent bytecode program.
73     Expression {
74         /// The GDB agent bytecode program to evaluate.
75         expr: ManagedSlice<'a, u8>,
76     },
77 }
78 
79 /// What type of information a tracepoint source item is about.
80 #[derive(Debug, Clone, Copy)]
81 pub enum TracepointSourceType {
82     /// Describes the location the tracepoint is at.
83     At,
84     /// Describes the conditional expression for a tracepoint.
85     Cond,
86     /// Describes the action command that should be executed when a tracepoint
87     /// is hit.
88     Cmd,
89 }
90 
91 /// Source string fragment for a tracepoint. A tracepoint may have more than one
92 /// source string, such as being describes by one source string for the location
93 /// and another for the actions, or by GDB splitting a larger source string
94 /// into multiple fragments. GDB may ask for the source of current tracepoints,
95 /// which are described by this same structure.
96 #[derive(Debug)]
97 pub struct SourceTracepoint<'a, U> {
98     /// The tracepoint that the source string is specifying.
99     pub number: Tracepoint,
100     /// The PC address of the tracepoint that the source string is specifying.
101     pub addr: U,
102     /// What type of information for this tracepoint the string fragment is
103     /// about.
104     pub kind: TracepointSourceType,
105     /// The offset in bytes within the overall source string this fragment is
106     /// within.
107     pub start: u32,
108     /// The total length of the overall source string this fragment is within.
109     pub slen: u32,
110     /// The data for this source string fragment.
111     pub bytes: ManagedSlice<'a, u8>,
112 }
113 
114 #[cfg(feature = "alloc")]
115 impl<U: Copy> SourceTracepoint<'_, U> {
116     /// Allocate an owned copy of this structure.
get_owned<'b>(&self) -> SourceTracepoint<'b, U>117     pub fn get_owned<'b>(&self) -> SourceTracepoint<'b, U> {
118         SourceTracepoint {
119             number: self.number,
120             addr: self.addr,
121             kind: self.kind,
122             start: self.start,
123             slen: self.slen,
124             bytes: ManagedSlice::Owned(self.bytes.to_owned()),
125         }
126     }
127 }
128 
129 #[cfg(feature = "alloc")]
130 impl<U: Copy> TracepointAction<'_, U> {
131     /// Allocate an owned copy of this structure.
get_owned<'b>(&self) -> TracepointAction<'b, U>132     pub fn get_owned<'b>(&self) -> TracepointAction<'b, U> {
133         use core::ops::Deref;
134         match self {
135             TracepointAction::Registers { mask } => TracepointAction::Registers {
136                 mask: ManagedSlice::Owned(mask.deref().into()),
137             },
138             TracepointAction::Memory {
139                 basereg,
140                 offset,
141                 length,
142             } => TracepointAction::Memory {
143                 basereg: *basereg,
144                 offset: *offset,
145                 length: *length,
146             },
147             TracepointAction::Expression { expr } => TracepointAction::Expression {
148                 expr: ManagedSlice::Owned(expr.deref().into()),
149             },
150         }
151     }
152 }
153 
154 /// The running state of a trace experiment.
155 #[derive(Debug)]
156 pub enum ExperimentStatus<'a> {
157     /// The experiment is currently running
158     Running,
159     /// The experiment is not currently running, with no more information given
160     /// as to why.
161     NotRunning,
162     /// No trace has been ran yet.
163     NotRun,
164     /// The trace was stopped by the user. May contain an optional user-supplied
165     /// stop reason.
166     Stop(Option<&'a [u8]>),
167     /// The trace stopped because the buffer is full.
168     Full,
169     /// The trace stopped because GDB disconnect from the target.
170     Disconnected,
171     /// The trace stopped because the specified tracepoint exceeded its pass
172     /// count.
173     PassCount(Tracepoint),
174     /// The trace stopped because the specified tracepoint had an error.
175     Error(&'a [u8], Tracepoint),
176     /// The trace stopped for some other reason.
177     Unknown,
178 }
179 
180 /// An explanation of some detail of the currently running trace experiment.
181 #[derive(Debug)]
182 pub enum ExperimentExplanation<'a> {
183     /// The number of trace frames in the buffer.
184     Frames(usize),
185     /// The total number of trace frames created during the run. This may be
186     /// larger than the trace frame count, if the buffer is circular.
187     Created(usize),
188     /// The total size of the trace buffer, in bytes.
189     Size(usize),
190     /// The number of bytes still unused in the buffer.
191     Free(usize),
192     /// The value of the circular trace buffer flag. True means the trace buffer
193     /// is circular and old trace frames will be discarded if necessary to
194     /// make room, false means that the trace buffer is linear and may fill
195     /// up.
196     Circular(bool),
197     /// The value of the disconnected tracing flag. True means that tracing will
198     /// continue after GDB disconnects, false means that the trace run will
199     /// stop.
200     DisconnectedTracing(bool),
201 
202     /// Report a raw string as a trace status explanation.
203     Other(&'a str),
204 }
205 
206 /// Shape of the trace buffer
207 #[derive(Debug)]
208 pub enum BufferShape {
209     /// A circular trace buffer
210     Circular,
211     /// A linear trace buffer
212     Linear,
213 }
214 
215 /// Configuration for the trace buffer.
216 #[derive(Debug)]
217 pub enum TraceBufferConfig {
218     /// Set the buffer's shape.
219     Shape(BufferShape),
220     /// Set the buffer's size in bytes. If None, the target should use whatever
221     /// size it prefers.
222     Size(Option<u64>),
223 }
224 
225 /// Request to select a new frame from the trace buffer.
226 #[derive(Debug)]
227 pub enum FrameRequest<U> {
228     /// Select the specified tracepoint frame in the buffer.
229     Select(u64),
230     /// Select a tracepoint frame that has a specified PC after the currently
231     /// selected frame.
232     AtPC(U),
233     /// Select a tracepoint frame that hit a specified tracepoint after the
234     /// currently selected frame.
235     Hit(Tracepoint),
236     /// Select a tramepoint frame that has a PC between a start (inclusive) and
237     /// end (inclusive).
238     Between(U, U),
239     /// Select a tracepoint frame that has a PC outside the range of addresses
240     /// (exclusive).
241     Outside(U, U),
242 }
243 
244 /// Describes a detail of a frame from the trace buffer
245 #[derive(Debug)]
246 pub enum FrameDescription {
247     /// The frame is at the specified index in the trace buffer
248     FrameNumber(u64),
249     /// The frame is a hit of the specified tracepoint
250     Hit(Tracepoint),
251 }
252 
253 /// The state of a tracepoint.
254 #[derive(Debug)]
255 pub struct TracepointStatus {
256     /// The number of times a tracepoint has been hit in a trace run.
257     pub hit_count: u64,
258     /// The number of bytes the tracepoint accounts for in the trace buffer.
259     pub bytes_used: u64,
260 }
261 
262 #[derive(Debug)]
263 pub(crate) enum TracepointEnumerateCursor<U> {
264     New { tp: Tracepoint, addr: U },
265     Action { tp: Tracepoint, addr: U, step: u64 },
266     Source { tp: Tracepoint, addr: U, step: u64 },
267 }
268 
269 /// The current state of enumerating tracepoints. gdbstub uses it as an opaque
270 /// bookkeeping record for what information has already been reported when GDB
271 /// downloads tracepoints on attachment.
272 #[derive(Debug, Default)]
273 pub struct TracepointEnumerateState<U> {
274     pub(crate) cursor: Option<TracepointEnumerateCursor<U>>,
275 }
276 
277 /// How to transition the [`TracepointEnumerateState`] state machine after
278 /// reporting an item for tracepoint enumeration.
279 #[derive(Debug)]
280 pub enum TracepointEnumerateStep<U> {
281     /// The current tracepoint that is being enumerated has more actions.
282     ///
283     /// Increments the step counter if the state machine was already
284     /// enumerating actions, otherwise it is reset to 0 and GDB will start
285     /// enumerating actions.
286     Action,
287     /// The current tracepoint that is being enumerated has more source strings.
288     ///
289     /// Increments the step counter if the state machine was already
290     /// enumerating sources strings, otherwise it is reset to 0 and GDB will
291     /// start enumerating source strings.
292     ///
293     /// Targets should only return this transition if they implement
294     /// [`Tracepoints::support_tracepoint_source`], or else it indicates an
295     /// error and the state machine iteration will stop.
296     Source,
297     /// The current tracepoint is done being enumerated, and GDB should next
298     /// enumerate a different one.
299     Next {
300         /// The next tracepoint to move to.
301         tp: Tracepoint,
302         /// The PC of the next tracepoint.
303         addr: U,
304     },
305     /// All tracepoints have been enumerated, and the state machine is done.
306     Done,
307 }
308 
309 /// Target Extension - Provide tracepoints.
310 pub trait Tracepoints: Target {
311     /// Clear any saved tracepoints and empty the trace frame buffer.
tracepoints_init(&mut self) -> TargetResult<(), Self>312     fn tracepoints_init(&mut self) -> TargetResult<(), Self>;
313 
314     /// Begin creating a new tracepoint according to the description `tdp`.
tracepoint_create_begin( &mut self, tdp: NewTracepoint<<Self::Arch as Arch>::Usize>, ) -> TargetResult<(), Self>315     fn tracepoint_create_begin(
316         &mut self,
317         tdp: NewTracepoint<<Self::Arch as Arch>::Usize>,
318     ) -> TargetResult<(), Self>;
319     /// Configure an existing tracepoint, appending an additional action to its
320     /// definition.
321     ///
322     /// This method will only ever be called in-between
323     /// [`Tracepoints::tracepoint_create_begin`] and
324     /// [`Tracepoints::tracepoint_create_complete`] invocations for a new
325     /// tracepoint.
tracepoint_create_continue( &mut self, tp: Tracepoint, action: &TracepointAction<'_, <Self::Arch as Arch>::Usize>, ) -> TargetResult<(), Self>326     fn tracepoint_create_continue(
327         &mut self,
328         tp: Tracepoint,
329         action: &TracepointAction<'_, <Self::Arch as Arch>::Usize>,
330     ) -> TargetResult<(), Self>;
331     /// Complete the creation of a tracepoint. All of its actions are expected
332     /// to have been received.
333     ///
334     /// This method will only ever be called after all of the
335     /// [`Tracepoints::tracepoint_create_begin`] and
336     /// [`Tracepoints::tracepoint_create_continue`] invocations for a new
337     /// tracepoint.
tracepoint_create_complete(&mut self, tp: Tracepoint) -> TargetResult<(), Self>338     fn tracepoint_create_complete(&mut self, tp: Tracepoint) -> TargetResult<(), Self>;
339     /// Request the status of tracepoint `tp` at address `addr`.
340     ///
341     /// Returns a [`TracepointStatus`] with the requested information.
tracepoint_status( &self, tp: Tracepoint, addr: <Self::Arch as Arch>::Usize, ) -> TargetResult<TracepointStatus, Self>342     fn tracepoint_status(
343         &self,
344         tp: Tracepoint,
345         addr: <Self::Arch as Arch>::Usize,
346     ) -> TargetResult<TracepointStatus, Self>;
347 
348     /// Return the stub's tracepoint enumeration state. gdbstub internally
349     /// uses this state to support GDB downloading tracepoints on attachment,
350     /// but requires the target implementation to provide storage for it.
351     ///
352     /// The state instance that this returns should be the same across multiple
353     /// calls and unmodified, or else gdbstub will be unable to transition the
354     /// state machine during enumeration correctly.
355     ///
356     /// For the average trait implementations, this will look like:
357     ///
358     /// ```rust,ignore
359     /// struct MyTarget {
360     ///    tracepoint_enumerate_state: TracepointEnumerateState,
361     ///    ...
362     /// }
363     ///
364     /// impl MyTarget {
365     ///    fn new() -> Self {
366     ///        MyTarget {
367     ///            tracepoint_enumerate_state: TracepointEnumerateState::default(),
368     ///            ...
369     ///        }
370     ///    }
371     /// }
372     ///
373     /// impl Tracepoints for MyTarget {
374     ///    fn tracepoint_enumerate_state(
375     ///        &mut self,
376     ///    ) -> &mut TracepointEnumerateState<<Self::Arch as Arch>::Usize> {
377     ///        &mut self.tracepoint_enumerate_state
378     ///    }
379     /// }
380     /// ```
tracepoint_enumerate_state( &mut self, ) -> &mut TracepointEnumerateState<<Self::Arch as Arch>::Usize>381     fn tracepoint_enumerate_state(
382         &mut self,
383     ) -> &mut TracepointEnumerateState<<Self::Arch as Arch>::Usize>;
384 
385     /// Begin enumerating a new tracepoint. If `tp` is None, then the first
386     /// tracepoint recorded should be reported via `f`, otherwise the requested
387     /// tracepoint should be.
388     ///
389     /// After reporting a tracepoint, [`TracepointEnumerateStep`] describes what
390     /// information is still available. Unlike tracepoint *creation*, which is
391     /// driven by GDB, for *enumeration* it's the responsibility of the trait
392     /// implementation to correctly sequence the state transitions so that
393     /// GDB is able to enumerate all of the information for the tracepoints the
394     /// implementation has saved via the various `tracepoint_enumerate_*`
395     /// methods.
396     ///
397     /// For the average implementation, it should report the requested
398     /// tracepoint, and then return
399     /// [`TracepointEnumerateStep::Action`] to transition to reporting
400     /// actions for the tracepoint. If the trait implements
401     /// [`TracepointSource`], it can instead return
402     /// [`TracepointEnumerateStep::Source`] to begin reporting source items
403     /// instead.
tracepoint_enumerate_start( &mut self, tp: Option<Tracepoint>, f: &mut dyn FnMut(&NewTracepoint<<Self::Arch as Arch>::Usize>), ) -> TargetResult<TracepointEnumerateStep<<Self::Arch as Arch>::Usize>, Self>404     fn tracepoint_enumerate_start(
405         &mut self,
406         tp: Option<Tracepoint>,
407         f: &mut dyn FnMut(&NewTracepoint<<Self::Arch as Arch>::Usize>),
408     ) -> TargetResult<TracepointEnumerateStep<<Self::Arch as Arch>::Usize>, Self>;
409     /// Enumerate an action attached to a tracepoint. `step` is which action
410     /// item is being asked for, so that the implementation can respond with
411     /// multiple items across multiple function calls. Each action should be
412     /// reported via `f`.
413     ///
414     /// After reporting a tracepoint action, [`TracepointEnumerateStep`]
415     /// describes what information will next be enumerated: this may be
416     /// [`TracepointEnumerateStep::Action`] if there are more actions that
417     /// still need to be reported, for example.
tracepoint_enumerate_action( &mut self, tp: Tracepoint, step: u64, f: &mut dyn FnMut(&TracepointAction<'_, <Self::Arch as Arch>::Usize>), ) -> TargetResult<TracepointEnumerateStep<<Self::Arch as Arch>::Usize>, Self>418     fn tracepoint_enumerate_action(
419         &mut self,
420         tp: Tracepoint,
421         step: u64,
422         f: &mut dyn FnMut(&TracepointAction<'_, <Self::Arch as Arch>::Usize>),
423     ) -> TargetResult<TracepointEnumerateStep<<Self::Arch as Arch>::Usize>, Self>;
424 
425     /// Reconfigure the trace buffer to include or modify an attribute.
trace_buffer_configure(&mut self, config: TraceBufferConfig) -> TargetResult<(), Self>426     fn trace_buffer_configure(&mut self, config: TraceBufferConfig) -> TargetResult<(), Self>;
427 
428     /// Read up to `len` bytes from the trace buffer, starting at `offset`.
429     /// The trace buffer is treated as a contiguous collection of traceframes,
430     /// as per [GDB's trace file format](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Trace-File-Format.html).
431     /// The function `f` should be called to report as many bytes from
432     /// the trace buffer that were requested as possible.
trace_buffer_request( &mut self, offset: u64, len: usize, f: &mut dyn FnMut(&mut [u8]), ) -> TargetResult<(), Self>433     fn trace_buffer_request(
434         &mut self,
435         offset: u64,
436         len: usize,
437         f: &mut dyn FnMut(&mut [u8]),
438     ) -> TargetResult<(), Self>;
439 
440     /// Return the status of the current trace experiment.
trace_experiment_status( &self, report: &mut dyn FnMut(ExperimentStatus<'_>), ) -> TargetResult<(), Self>441     fn trace_experiment_status(
442         &self,
443         report: &mut dyn FnMut(ExperimentStatus<'_>),
444     ) -> TargetResult<(), Self>;
445     /// List any statistical information for the current trace experiment, by
446     /// calling `report` with each [`ExperimentExplanation`] item.
trace_experiment_info( &self, report: &mut dyn FnMut(ExperimentExplanation<'_>), ) -> TargetResult<(), Self>447     fn trace_experiment_info(
448         &self,
449         report: &mut dyn FnMut(ExperimentExplanation<'_>),
450     ) -> TargetResult<(), Self>;
451     /// Start a new trace experiment.
trace_experiment_start(&mut self) -> TargetResult<(), Self>452     fn trace_experiment_start(&mut self) -> TargetResult<(), Self>;
453     /// Stop the currently running trace experiment.
trace_experiment_stop(&mut self) -> TargetResult<(), Self>454     fn trace_experiment_stop(&mut self) -> TargetResult<(), Self>;
455 
456     /// Select a new frame in the trace buffer. The target should attempt to
457     /// fulfill the request according to the [`FrameRequest`]. If it's
458     /// successful it should call `report` with a series of calls describing
459     /// the found frame, and then record it as the currently selected frame.
460     /// Future register and memory requests should be fulfilled from the
461     /// currently selected frame.
select_frame( &mut self, frame: FrameRequest<<Self::Arch as Arch>::Usize>, report: &mut dyn FnMut(FrameDescription), ) -> TargetResult<(), Self>462     fn select_frame(
463         &mut self,
464         frame: FrameRequest<<Self::Arch as Arch>::Usize>,
465         report: &mut dyn FnMut(FrameDescription),
466     ) -> TargetResult<(), Self>;
467 
468     /// Support for setting and enumerating the source strings for tracepoint
469     /// actions.
470     ///
471     /// The GDB client will attempt to download tracepoints when it attaches to
472     /// the stub, which will trigger the
473     /// `Tracepoints::tracepoint_enumerate_*` state machine enumeration
474     /// codepaths. GDB depends on accurately enumerating source strings for
475     /// tracepoints, or else for agent bytecode programs (which are most
476     /// non-trivial `collect` actions) it won't be able to parse them and
477     /// throw away the actions attached to the tracepoint. [`TracepointSource`]
478     /// allows for recording and then reporting action source
479     /// strings for targets that want to fully support GDB tracepoint
480     /// downloading.
481     #[inline(always)]
support_tracepoint_source(&mut self) -> Option<TracepointSourceOps<'_, Self>>482     fn support_tracepoint_source(&mut self) -> Option<TracepointSourceOps<'_, Self>> {
483         None
484     }
485 }
486 
487 /// Target Extension - Support setting and enumerating source strings for
488 /// tracepoint actions.
489 ///
490 /// GDB requires source strings to be accurately reported back to it when it
491 /// attaches to a target in order to download tracepoints, or else it will
492 /// locally not be able to parse them and throw away the attached actions.
493 ///
494 /// Downloading tracepoints is only triggered for new GDB clients attaching to a
495 /// stub that already has tracepoints loaded, however. An example use case would
496 /// be one GDB client attaching, creating tracepoints, disconnecting, and then a
497 /// new GDB client starting and connecting to the stub to download the loaded
498 /// tracepoints. If supporting that behavior is unimportant and you only need to
499 /// work with a single GDB session, it is safe to not implement this extension.
500 pub trait TracepointSource: Tracepoints {
501     /// Configure an existing tracepoint, appending a new source string
502     /// fragment.
tracepoint_attach_source( &mut self, src: SourceTracepoint<'_, <Self::Arch as Arch>::Usize>, ) -> TargetResult<(), Self>503     fn tracepoint_attach_source(
504         &mut self,
505         src: SourceTracepoint<'_, <Self::Arch as Arch>::Usize>,
506     ) -> TargetResult<(), Self>;
507 
508     /// Enumerate the source strings that describe a tracepoint. `step` is which
509     /// source string is being asked for, so that the implementation can
510     /// respond with multiple items across multiple function calls. Each
511     /// source string should be reported via `f`.
512     ///
513     /// After reporting a tracepoint source string, [`TracepointEnumerateStep`]
514     /// describes what source string will next be enumerated.
tracepoint_enumerate_source( &mut self, tp: Tracepoint, step: u64, f: &mut dyn FnMut(&SourceTracepoint<'_, <Self::Arch as Arch>::Usize>), ) -> TargetResult<TracepointEnumerateStep<<Self::Arch as Arch>::Usize>, Self>515     fn tracepoint_enumerate_source(
516         &mut self,
517         tp: Tracepoint,
518         step: u64,
519         f: &mut dyn FnMut(&SourceTracepoint<'_, <Self::Arch as Arch>::Usize>),
520     ) -> TargetResult<TracepointEnumerateStep<<Self::Arch as Arch>::Usize>, Self>;
521 }
522 
523 define_ext!(TracepointsOps, Tracepoints);
524 define_ext!(TracepointSourceOps, TracepointSource);
525