• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Everything related to the [`Target`] trait + associated extension traits.
2 //!
3 //! The [`Target`] trait describes how to control and modify a system's
4 //! execution state during a GDB debugging session, and serves as the
5 //! primary bridge between `gdbstub`'s generic protocol implementation and a
6 //! target's project/platform-specific code.
7 //!
8 //! **`Target` is the most important trait in `gdbstub`, and must be implemented
9 //! by all consumers of the library!**
10 //!
11 //! # Implementing `Target`
12 //!
13 //! `gdbstub` uses a technique called "Inlineable Dyn Extension Traits" (IDETs)
14 //! to expose an ergonomic and extensible interface to the GDB protocol. It's
15 //! not a very common pattern, and can seem a little "weird" at first glance,
16 //! but it's actually very straightforward to use!
17 //!
18 //! Please refer to the [documentation in the `ext` module](ext) for more
19 //! information on IDETs, and how they're used to implement `Target` and it's
20 //! various extension traits.
21 //!
22 //! **TL;DR:** Whenever you see a method that has `Option<FooOps>` in the return
23 //! type, that method should return `Some(self)` if the extension is
24 //! implemented, or `None` if it's unimplemented / disabled.
25 //!
26 //! ## Associated Types
27 //!
28 //! - The [`Target::Arch`](trait.Target.html#associatedtype.Arch) associated
29 //!   type encodes information about the target's architecture, such as it's
30 //!   pointer size, register layout, etc... `gdbstub` comes with several
31 //!   built-in architecture definitions, which can be found under the
32 //!   [`arch`](../arch/index.html) module.
33 //!
34 //! - The [`Target::Error`](trait.Target.html#associatedtype.Error) associated
35 //!   type allows implementors to plumb-through their own project-specific fatal
36 //!   error type into the `Target` trait. This is a big-boost to library
37 //!   ergonomics, as it enables consumers of `gdbstub` to preserve
38 //!   target-specific context while using `gdbstub`, without having to do any
39 //!   "error-stashing".
40 //!
41 //! For example: consider an emulated target where certain devices might return
42 //! a `MyEmuError::ContractViolation` error whenever they're accessed
43 //! "improperly" (e.g: setting registers in the wrong order). By setting `type
44 //! Error = MyEmuError`, the method signature of the `Target`'s `resume` method
45 //! becomes `fn resume(&mut self, ...) -> Result<_, MyEmuError>`, which makes it
46 //! possible to preserve the target-specific error while using `gdbstub`!
47 //!
48 //! ## Required Methods
49 //!
50 //! The [`Target::base_ops`](trait.Target.html#tymethod.base_ops) method
51 //! describes the base debugging operations that must be implemented by any
52 //! target. These are things such as starting/stopping execution,
53 //! reading/writing memory, etc..
54 //!
55 //! All other methods are entirely optional! Check out the
56 //! [`target_ext`](../target_ext/index.html) module for a full list of currently
57 //! supported protocol extensions.
58 //!
59 //! ## Example: A Bare-Minimum Single Threaded `Target`
60 //!
61 //! ```rust,ignore
62 //! use gdbstub::target::Target;
63 //! use gdbstub::target::ext::base::singlethread::SingleThreadOps;
64 //!
65 //! impl SingleThreadOps for MyTarget {
66 //!     // ... omitted for brevity
67 //! }
68 //!
69 //! impl Target for MyTarget {
70 //!     fn base_ops(&mut self) -> base::BaseOps<Self::Arch, Self::Error> {
71 //!         base::BaseOps::SingleThread(self)
72 //!     }
73 //! }
74 //! ```
75 
76 use crate::arch::Arch;
77 
78 pub mod ext;
79 
80 /// The error type for various methods on `Target` and it's assorted associated
81 /// extension traits.
82 ///
83 /// # Error Handling over the GDB Remote Serial Protocol
84 ///
85 /// The GDB Remote Serial Protocol has less-than-stellar support for error
86 /// handling, typically taking the form of a single-byte
87 /// [`errno`-style error codes](https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html).
88 /// Moreover, often times the GDB client will simply _ignore_ the specific error
89 /// code returned by the stub, and print a generic failure message instead.
90 ///
91 /// As such, while it's certainly better to use appropriate error codes when
92 /// possible (e.g: returning a `EFAULT` (14) when reading from invalid memory),
93 /// it's often fine to simply return the more general `TargetError::NonFatal`
94 /// instead, and avoid the headache of picking a "descriptive" error code. Under
95 /// the good, `TargetError::NonFatal` is sent to the GDB client as a generic
96 /// `EREMOTEIO` (121) error.
97 ///
98 /// # `From` and `Into` implementations
99 ///
100 /// - `From<()>` -> `TargetError::NonFatal`
101 /// - `From<io::Error>` -> `TargetError::Io(io::Error)` (requires `std` feature)
102 ///
103 /// When using a custom target-specific fatal error type, users are encouraged
104 /// to write the following impl to simplify error handling in `Target` methods:
105 ///
106 /// ```rust,ignore
107 /// type MyTargetFatalError = ...; // Target-specific Fatal Error
108 /// impl From<MyTargetFatalError> for TargetError<MyTargetFatalError> {
109 ///     fn from(e: MyTargetFatalError) -> Self {
110 ///         TargetError::Fatal(e)
111 ///     }
112 /// }
113 /// ```
114 ///
115 /// Unfortunately, a blanket impl such as `impl<T: Target> From<T::Error> for
116 /// TargetError<T::Error>` isn't possible, as it could result in impl conflicts.
117 /// For example, if a Target decided to use `()` as it's fatal error type, then
118 /// there would be conflict with the existing `From<()>` impl.
119 #[non_exhaustive]
120 pub enum TargetError<E> {
121     /// A non-specific, non-fatal error has occurred.
122     NonFatal,
123     /// I/O Error.
124     ///
125     /// At the moment, this is just shorthand for
126     /// `TargetError::NonFatal(e.raw_os_err().unwrap_or(121))`. Error code `121`
127     /// corresponds to `EREMOTEIO`.
128     ///
129     /// In the future, `gdbstub` may add support for the "QEnableErrorStrings"
130     /// LLDB protocol extension, which would allow sending additional error
131     /// context (in the form of an ASCII string) when an I/O error occurs. If
132     /// this is something you're interested in, consider opening a PR!
133     ///
134     /// Only available when the `std` feature is enabled.
135     #[cfg(feature = "std")]
136     Io(std::io::Error),
137     /// An operation-specific non-fatal error code.
138     Errno(u8),
139     /// A target-specific fatal error.
140     ///
141     /// **WARNING:** Returning this error will immediately halt the target's
142     /// execution and return a `GdbStubError::TargetError` from `GdbStub::run`!
143     /// Note that the debugging session will will _not_ be terminated, and can
144     /// be resumed by calling `GdbStub::run` after resolving the error and/or
145     /// setting up a post-mortem debugging environment.
146     Fatal(E),
147 }
148 
149 /// Converts a `()` into a `TargetError::NonFatal`.
150 impl<E> From<()> for TargetError<E> {
from(_: ()) -> TargetError<E>151     fn from(_: ()) -> TargetError<E> {
152         TargetError::NonFatal
153     }
154 }
155 
156 /// Converts a `std::io::Error` into a `TargetError::Io`.
157 #[cfg(feature = "std")]
158 impl<E> From<std::io::Error> for TargetError<E> {
from(e: std::io::Error) -> TargetError<E>159     fn from(e: std::io::Error) -> TargetError<E> {
160         TargetError::Io(e)
161     }
162 }
163 
164 /// A specialized `Result` type for `Target` operations.
165 ///
166 /// _Note:_ While it's typically parameterized as `TargetResult<T, Self>`, the
167 /// error value is in-fact `TargetError<Self::Error>` (not `Self`).
168 pub type TargetResult<T, Tgt> = Result<T, TargetError<<Tgt as Target>::Error>>;
169 
170 /// Describes the architecture and capabilities of a target which can be
171 /// debugged by [`GdbStub`](../struct.GdbStub.html).
172 ///
173 /// The [`Target`](trait.Target.html) trait describes how to control and modify
174 /// a system's execution state during a GDB debugging session, and serves as the
175 /// primary bridge between `gdbstub`'s generic protocol implementation and a
176 /// target's project/platform-specific code.
177 ///
178 /// **`Target` is the most important trait in `gdbstub`, and must be implemented
179 /// by anyone who uses the library!**
180 ///
181 /// Please refer to the the documentation in the [`target` module](index.html)
182 /// for more information on how to implement and work with `Target` and it's
183 /// various extension traits.
184 pub trait Target {
185     /// The target's architecture.
186     type Arch: Arch;
187 
188     /// A target-specific **fatal** error.
189     type Error;
190 
191     /// Base operations such as reading/writing from memory/registers,
192     /// stopping/resuming the target, etc....
193     ///
194     /// For example, on a single-threaded target:
195     ///
196     /// ```rust,ignore
197     /// use gdbstub::target::Target;
198     /// use gdbstub::target::base::singlethread::SingleThreadOps;
199     ///
200     /// impl SingleThreadOps for MyTarget {
201     ///     // ...
202     /// }
203     ///
204     /// impl Target for MyTarget {
205     ///     fn base_ops(&mut self) -> base::BaseOps<Self::Arch, Self::Error> {
206     ///         base::BaseOps::SingleThread(self)
207     ///     }
208     /// }
209     /// ```
base_ops(&mut self) -> ext::base::BaseOps<Self::Arch, Self::Error>210     fn base_ops(&mut self) -> ext::base::BaseOps<Self::Arch, Self::Error>;
211 
212     /// Set/Remote software breakpoints.
sw_breakpoint(&mut self) -> Option<ext::breakpoints::SwBreakpointOps<Self>>213     fn sw_breakpoint(&mut self) -> Option<ext::breakpoints::SwBreakpointOps<Self>> {
214         None
215     }
216 
217     /// Set/Remote hardware breakpoints.
hw_breakpoint(&mut self) -> Option<ext::breakpoints::HwBreakpointOps<Self>>218     fn hw_breakpoint(&mut self) -> Option<ext::breakpoints::HwBreakpointOps<Self>> {
219         None
220     }
221 
222     /// Set/Remote hardware watchpoints.
hw_watchpoint(&mut self) -> Option<ext::breakpoints::HwWatchpointOps<Self>>223     fn hw_watchpoint(&mut self) -> Option<ext::breakpoints::HwWatchpointOps<Self>> {
224         None
225     }
226 
227     /// Handle custom GDB `monitor` commands.
monitor_cmd(&mut self) -> Option<ext::monitor_cmd::MonitorCmdOps<Self>>228     fn monitor_cmd(&mut self) -> Option<ext::monitor_cmd::MonitorCmdOps<Self>> {
229         None
230     }
231 
232     /// Support for Extended Mode operations.
extended_mode(&mut self) -> Option<ext::extended_mode::ExtendedModeOps<Self>>233     fn extended_mode(&mut self) -> Option<ext::extended_mode::ExtendedModeOps<Self>> {
234         None
235     }
236 
237     /// Handle requests to get the target's current section (or segment)
238     /// offsets.
section_offsets(&mut self) -> Option<ext::section_offsets::SectionOffsetsOps<Self>>239     fn section_offsets(&mut self) -> Option<ext::section_offsets::SectionOffsetsOps<Self>> {
240         None
241     }
242 
243     /// Override the target description XML specified by `Target::Arch`.
target_description_xml_override( &mut self, ) -> Option<ext::target_description_xml_override::TargetDescriptionXmlOverrideOps<Self>>244     fn target_description_xml_override(
245         &mut self,
246     ) -> Option<ext::target_description_xml_override::TargetDescriptionXmlOverrideOps<Self>> {
247         None
248     }
249 }
250 
251 macro_rules! impl_dyn_target {
252     ($type:ty) => {
253         #[allow(clippy::type_complexity)]
254         impl<A, E> Target for $type
255         where
256             A: Arch,
257         {
258             type Arch = A;
259             type Error = E;
260 
261             fn base_ops(&mut self) -> ext::base::BaseOps<Self::Arch, Self::Error> {
262                 (**self).base_ops()
263             }
264 
265             fn sw_breakpoint(&mut self) -> Option<ext::breakpoints::SwBreakpointOps<Self>> {
266                 (**self).sw_breakpoint()
267             }
268 
269             fn hw_breakpoint(&mut self) -> Option<ext::breakpoints::HwBreakpointOps<Self>> {
270                 (**self).hw_breakpoint()
271             }
272 
273             fn hw_watchpoint(&mut self) -> Option<ext::breakpoints::HwWatchpointOps<Self>> {
274                 (**self).hw_watchpoint()
275             }
276 
277             fn monitor_cmd(&mut self) -> Option<ext::monitor_cmd::MonitorCmdOps<Self>> {
278                 (**self).monitor_cmd()
279             }
280 
281             fn extended_mode(&mut self) -> Option<ext::extended_mode::ExtendedModeOps<Self>> {
282                 (**self).extended_mode()
283             }
284 
285             fn section_offsets(&mut self) -> Option<ext::section_offsets::SectionOffsetsOps<Self>> {
286                 (**self).section_offsets()
287             }
288 
289             fn target_description_xml_override(
290                 &mut self,
291             ) -> Option<ext::target_description_xml_override::TargetDescriptionXmlOverrideOps<Self>>
292             {
293                 (**self).target_description_xml_override()
294             }
295         }
296     };
297 }
298 
299 impl_dyn_target!(&mut dyn Target<Arch = A, Error = E>);
300 #[cfg(feature = "alloc")]
301 impl_dyn_target!(alloc::boxed::Box<dyn Target<Arch = A, Error = E>>);
302