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