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