• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Extensions to [`Target`](super::Target) which add support for various
2 //! subsets of the GDB Remote Serial Protocol.
3 //!
4 //! On it's own, the [`Target`](super::Target) trait doesn't actually include
5 //! any methods to debug the target. Instead, `Target` uses a collection of
6 //! "Inlineable Dyn Extension Traits" (IDETs) to optionally implement various
7 //! subsets of the GDB protocol. For more details on IDETs, scroll down to the
8 //! [How Protocol Extensions Work - Inlineable Dyn Extension Traits
9 //! (IDETs)](#how-protocol-extensions-work---inlineable-dyn-extension-traits-idets)
10 //! section below.
11 //!
12 //! As a starting point, consider implementing some of the extensions under
13 //! [`breakpoints`]. For example, adding support for Software Breakpoints would
14 //! require implementing the
15 //! [`breakpoints::SwBreakpoint`](breakpoints::SwBreakpoint) extension, and
16 //! overriding the `Target::sw_breakpoint` method to return `Some(self)`.
17 //!
18 //! ### Note: Missing Protocol Extensions
19 //!
20 //! `gdbstub`'s development is guided by the needs of it's contributors, with
21 //! new features being added on an "as-needed" basis.
22 //!
23 //! If there's a GDB feature you need that hasn't been implemented yet, (e.g:
24 //! remote filesystem access, tracepoint support, etc...), consider opening an
25 //! issue / filing a PR on Github!
26 //!
27 //! Check out the [GDB Remote Configuration Docs](https://sourceware.org/gdb/onlinedocs/gdb/Remote-Configuration.html)
28 //! for a table of GDB commands + their corresponding Remote Serial Protocol
29 //! packets.
30 //!
31 //! ### Note: What's with all the `<Self::Arch as Arch>::` syntax?
32 //!
33 //! Many of the method signatures across the `Target` extension traits include
34 //! some pretty gnarly type syntax.
35 //!
36 //! If [rust-lang/rust#38078](https://github.com/rust-lang/rust/issues/38078)
37 //! gets fixed, then types like `<Self::Arch as Arch>::Foo` could be simplified
38 //! to just `Self::Arch::Foo`. Until then, the much more explicit
39 //! [fully qualified syntax](https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name)
40 //! must be used instead.
41 //!
42 //! When you come across this syntax, it's highly recommended to use the
43 //! concrete type instead. e.g: on a 32-bit target, instead of cluttering up
44 //! the implementation with `<Self::Arch as Arch>::Usize`, just use `u32`
45 //! directly.
46 //!
47 //! ## How Protocol Extensions Work - Inlineable Dyn Extension Traits (IDETs)
48 //!
49 //! The GDB protocol is massive, and contains all sorts of optional
50 //! functionality. In previous versions of `gdbstub`, the `Target` trait would
51 //! directly have a method for _every single protocol extension_, resulting in
52 //! literally _hundreds_ of associated methods!
53 //!
54 //! This approach had numerous drawbacks:
55 //!
56 //!  - Implementations that did not implement all available protocol extensions
57 //!    still had to "pay" for the unused packet parsing/handler code, resulting
58 //!    in substantial code bloat, even on `no_std` platforms.
59 //!  - Required the `GdbStub` implementation to include runtime checks to deal
60 //!    with incorrectly implemented `Target`s.
61 //!      - No way to enforce "mutually-dependent" trait methods at compile-time.
62 //!          - e.g: When implementing hardware breakpoint extensions, targets
63 //!            _must_ implement both the `add_breakpoint` and
64 //!            `remove_breakpoints` methods.
65 //!      - No way to enforce "mutually-exclusive" trait methods at compile-time.
66 //!          - e.g: The `resume` method for single-threaded targets has a much
67 //!            simpler API than for multi-threaded targets, but it would be
68 //!            incorrect for a target to implement both.
69 //!
70 //! Starting from version `0.4.0`, `gdbstub` is taking a new approach to
71 //! implementing and enumerating available Target features, using a technique
72 //! called **Inlineable Dyn Extension Traits**.
73 //!
74 //! _Author's note:_ As far as I can tell, this isn't a very well-known trick,
75 //! or at the very least, I've personally never encountered any library that
76 //! uses this sort of API. As such, I've decided to be a bit cheeky and give it
77 //! a name! At some point, I'm hoping to write a standalone blog post which
78 //! further explores this technique, comparing it to other/existing approaches,
79 //! and diving into details of the how the compiler optimizes this sort of code.
80 //!
81 //! So, what are "Inlineable Dyn Extension Traits"? Well, let's break it down:
82 //!
83 //! - **Extension Traits** - A common [Rust convention](https://rust-lang.github.io/rfcs/0445-extension-trait-conventions.html#what-is-an-extension-trait)
84 //!   to extend the functionality of a Trait, _without_ modifying the original
85 //!   trait.
86 //! - **Dyn** - Alludes to the use of Dynamic Dispatch via [Trait Objects](https://doc.rust-lang.org/book/ch17-02-trait-objects.html).
87 //! - **Inlineable** - Alludes to the fact that this approach can be easily
88 //!   inlined, making it a truly zero-cost abstraction.
89 //!
90 //! In a nutshell, Inlineable Dyn Extension Traits (or IDETs) are an abuse of
91 //! the Rust trait system + modern compiler optimizations to emulate zero-cost,
92 //! runtime-query-able optional trait methods!
93 //!
94 //! #### Technical overview
95 //!
96 //! The basic principles behind Inlineable Dyn Extension Traits are best
97 //! explained though example:
98 //!
99 //! Lets say we want to add an optional protocol extension described by an
100 //! `OptExt` trait to the `Target` trait. How would we do that using IDETs?
101 //!
102 //! - (library) Define a `trait OptExt: Target { ... }` with all the optional
103 //!   methods:
104 //!    - Making `OptExt` a subtrait of `Target` enables using `Target`'s
105 //!      associated types.
106 //!
107 //! ```rust,ignore
108 //! /// `foo` and `bar` are mutually-dependent methods.
109 //! trait OptExt: Target {
110 //!     fn foo(&self);
111 //!     // can use associated types in method signature!
112 //!     fn bar(&mut self) -> Result<(), Self::Error>;
113 //! }
114 //! ```
115 //!
116 //! - (library) "Tie" the `OptExt` extension trait to the original `Target`
117 //!   trait by adding a new `Target` method that simply returns `self` cast to a
118 //!   `&mut dyn OptExt`:
119 //!
120 //! ```rust,ignore
121 //! trait Target {
122 //!     // Optional extension
123 //!     fn ext_optfeat(&mut self) -> Option<OptExtOps<Self>> {
124 //!         // disabled by default
125 //!         None
126 //!     }
127 //!     // Mutually-exclusive extensions
128 //!     fn ext_a_or_b(&mut self) -> EitherOrExt<Self::Arch, Self::Error>;
129 //! }
130 //!
131 //! // Using a typedef for readability
132 //! type OptExtOps<T> =
133 //!     &'a mut dyn OptExt<Arch = <T as Target>::Arch, Error = <T as Target>::Error>;
134 //!
135 //! enum EitherOrExt<A, E> {
136 //!     OptExtA(&'a mut dyn OptExtA<Arch = A, Error = E>),
137 //!     OptExtB(&'a mut dyn OptExtB<Arch = A, Error = E>),
138 //! }
139 //! ```
140 //!
141 //! - (user) Implements the `OptExt` extension for their target (just like a
142 //!   normal trait).
143 //!
144 //! ```rust,ignore
145 //! impl OptExt for Target {
146 //!     fn foo(&self) { ... }
147 //!     fn bar(&mut self) -> Result<(), Self::Error> { ... }
148 //! }
149 //! ```
150 //!
151 //! - (user) Implements the base `Target` trait, returning `Some(self)` to
152 //!   "enable" an extension, or `None` to leave it disabled.
153 //!
154 //! ```rust,ignore
155 //! impl Target for MyTarget {
156 //!     // Optional extension - Always enabled
157 //!     fn ext_optfeat(&mut self) -> Option<OptExtOps<Self>> {
158 //!         Some(self) // will not compile unless `MyTarget` also implements `OptExt`
159 //!     }
160 //!     // Mutually-exclusive extensions
161 //!     fn ext_a_or_b(&mut self) -> EitherOrExt<Self::Arch, Self::Error> {
162 //!         EitherOrExt::OptExtA(self)
163 //!     }
164 //! }
165 //! ```
166 //!
167 //! If the user didn't implement `OptExt`, but tried to return `Some(self)`,
168 //! they'll get an error similar to:
169 //!
170 //! ```text
171 //! error[E0277]: the trait bound `MyTarget: OptExt` is not satisfied
172 //!   --> path/to/implementation.rs:44:14
173 //!    |
174 //! 44 |         Some(self)
175 //!    |              ^^^^ the trait `OptExt` is not implemented for `MyTarget`
176 //!    |
177 //!    = note: required for the cast to the object type `dyn OptExt<Arch = ..., Error = ...>`
178 //! ```
179 //!
180 //! - (library) Can now _query_ whether or not the extension is available,
181 //!   _without_ having to actually invoke any method on the target!
182 //! ```rust,ignore
183 //! // in a method that accepts `target: impl Target`
184 //! match target.ext_optfeat() {
185 //!     Some(ops) => ops.cool_feature(),
186 //!     None => { /* do nothing */ }
187 //! }
188 //! ```
189 //!
190 //! Moreover, if you take a look at the generated assembly (e.g: using
191 //! godbolt.org), you'll find that the compiler is able to efficiently inline
192 //! and devirtualize all the single-line `ext_` methods, which in-turn allows
193 //! the dead-code-eliminator to work it's magic, and remove the unused branches
194 //! from the generated code! i.e: If a target didn't implement the `OptExt`
195 //! extension, then that `match` statement would be converted into a noop!
196 //!
197 //! Check out [daniel5151/optional-trait-methods](https://github.com/daniel5151/optional-trait-methods)
198 //! for some sample code that shows off the power of IDETs. It includes code
199 //! snippets which can be pasted into godbolt.org directly to confirm the
200 //! optimizations described above.
201 //!
202 //! Optimizing compilers really are magic!
203 //!
204 //! #### Summary: The Benefits of IDETs
205 //!
206 //! IDETs solve the numerous issues and shortcomings that arise from the
207 //! traditional single trait + "optional" methods approach:
208 //!
209 //! - **Compile-time enforcement of mutually-dependent methods**
210 //!    - By grouping mutually-dependent methods behind a single extension trait
211 //!      and marking them all as required methods, the Rust compiler is able to
212 //!      catch missing mutually-dependent methods at compile time, with no need
213 //!      for any runtime checks!
214 //! - **Compile-time enforcement of mutually-exclusive methods**
215 //!    - By grouping mutually-exclusive methods behind two extension traits, and
216 //!      wrapping those in an `enum`, the API is able to document
217 //!      mutually-exclusive functions _at the type-level_, in-turn enabling the
218 //!      library to omit any runtime checks!
219 //!    - _Note:_ Strictly speaking, this isn't really compile time
220 //!      "enforcement", as there's nothing stopping an "adversarial"
221 //!      implementation from implementing both sets of methods, and then
222 //!      "flipping" between the two at runtime. Nonetheless, it serves as a good
223 //!      guardrail.
224 //! - **Enforce dead-code-elimination _without_ `cargo` feature flags**
225 //!     - This is a really awesome trick: by wrapping code in a `if
226 //!       target.ext_optfeat().is_some()` block, it's possible to specify
227 //!       _arbitrary_ blocks of code to be feature-dependent!
228 //!     - This is used to great effect in `gdbstub` to optimize-out any packet
229 //!       parsing / handler code for unimplemented protocol extensions.
230 
231 macro_rules! doc_comment {
232     ($x:expr, $($tt:tt)*) => {
233         #[doc = $x]
234         $($tt)*
235     };
236 }
237 
238 macro_rules! define_ext {
239     ($extname:ident, $exttrait:ident) => {
240         doc_comment! {
241             concat!("See [`", stringify!($exttrait), "`](trait.", stringify!($exttrait), ".html)."),
242             pub type $extname<'a, T> =
243                 &'a mut dyn $exttrait<Arch = <T as Target>::Arch, Error = <T as Target>::Error>;
244         }
245     };
246 }
247 
248 pub mod base;
249 pub mod breakpoints;
250 pub mod extended_mode;
251 pub mod monitor_cmd;
252 pub mod section_offsets;
253 pub mod target_description_xml_override;
254