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

macro_rules! doc_comment {
    ($x:expr, $($tt:tt)*) => {
        #[doc = $x]
        $($tt)*
    };
}

macro_rules! define_ext {
    ($extname:ident, $exttrait:ident) => {
        doc_comment! {
            concat!("See [`", stringify!($exttrait), "`](trait.", stringify!($exttrait), ".html)."),
            pub type $extname<'a, T> =
                &'a mut dyn $exttrait<Arch = <T as Target>::Arch, Error = <T as Target>::Error>;
        }
    };
}

pub mod base;
pub mod breakpoints;
pub mod extended_mode;
pub mod monitor_cmd;
pub mod section_offsets;