//! The core [`Target`] trait, and all its various protocol extension traits. //! //! The [`Target`] trait describes how to control and modify a system's //! execution state during a GDB debugging session, and serves as the //! primary bridge between `gdbstub`'s generic protocol implementation and a //! target's project/platform-specific code. //! //! **`Target` is the most important trait in `gdbstub`, and must be implemented //! by all consumers of the library!** //! //! # Implementing `Target` //! //! `gdbstub` uses a technique called ["Inlineable Dyn Extension Traits"](ext) //! (IDETs) to expose an ergonomic and extensible interface to the GDB protocol. //! It's not a very common pattern, and can seem a little "weird" at first //! glance, but IDETs are actually very straightforward to use! //! //! **TL;DR:** Whenever you see a method that returns something that looks like //! `Option`, you can enable that protocol extension by //! implementing the `ProtocolExt` type on your target, and overriding the //! `Option` method to return `Some(self)`. //! //! Please refer to the [documentation in the `ext` module](ext) for more //! information on IDETs, including a more in-depth explanation of how they //! work, and how `Target` leverages them to provide fine grained control over //! enabled protocol features. //! //! ## Associated Types //! //! - The [`Target::Arch`](trait.Target.html#associatedtype.Arch) associated //! type encodes information about the target's architecture, such as its //! pointer size, register layout, etc... `gdbstub` comes with several //! built-in architecture definitions, which can be found under the //! [`arch`](../arch/index.html) module. //! //! - The [`Target::Error`](trait.Target.html#associatedtype.Error) associated //! type allows implementors to plumb-through their own project-specific fatal //! error type into the `Target` trait. This is a big-boost to library //! ergonomics, as it enables consumers of `gdbstub` to preserve //! target-specific context while using `gdbstub`, without having to do any //! "error-stashing". //! //! For example: consider an emulated target where certain devices might return //! a `MyEmuError::ContractViolation` error whenever they're accessed //! "improperly" (e.g: setting registers in the wrong order). By setting `type //! Error = MyEmuError`, the method signature of the `Target`'s `resume` method //! becomes `fn resume(&mut self, ...) -> Result<_, MyEmuError>`, which makes it //! possible to preserve the target-specific error while using `gdbstub`! //! //! ## Required Methods (Base Protocol) //! //! A minimal `Target` implementation only needs to implement a single method: //! [`Target::base_ops`](trait.Target.html#tymethod.base_ops). This method is //! used to select which set of [`base`](crate::target::ext::base) //! debugging operations will be used to control the target. These are //! fundamental operations such as reading/writing memory, etc... //! //! All other methods are entirely optional! Check out the //! [`ext`](ext#modules) module for a full list of currently supported protocol //! extensions. //! //! ## Optional Protocol Extensions //! //! The GDB protocol is _massive_, and there are plenty of optional protocol //! extensions that targets can implement to enhance the base debugging //! experience. //! //! These protocol extensions range from relatively mundane things such as //! setting/removing breakpoints or reading/writing individual registers, but //! also include fancy things such as support for time travel debugging, running //! shell commands remotely, or even performing file IO on the target! //! //! `gdbstub` uses a somewhat unique approach to exposing these many features, //! called **Inlinable Dyn Extension Traits (IDETs)**. While this might sound a //! bit daunting, the API is actually quite straightforward, and described in //! great detail under the [`ext` module's documentation](ext). //! //! After getting the base protocol up and running, do take a moment to skim //! through and familiarize yourself with the [many different protocol //! extensions](ext# modules) that `gdbstub` implements. There are some really //! nifty ones that you might not even realize you need! //! //! As a suggestion on where to start, consider implementing some of the //! breakpoint related extensions under //! [`breakpoints`](crate::target::ext::breakpoints). While setting/removing //! breakpoints is technically an "optional" part of the GDB protocol, I'm sure //! you'd be hard pressed to find a debugger that doesn't support breakpoints. //! //! ### Note: Missing Protocol Extensions //! //! `gdbstub`'s development is guided by the needs of its contributors, with //! new features being added on an "as-needed" basis. //! //! If there's a GDB protocol extensions you're interested in that hasn't been //! implemented in `gdbstub` yet, (e.g: remote filesystem access, tracepoint //! support, etc...), consider opening an issue / filing a PR on the //! [`gdbstub` GitHub repo](https://github.com/daniel5151/gdbstub/). //! //! 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. //! //! ### Example: A fairly minimal Single Threaded `Target` //! //! This example includes a handful of required and optional target features, //! and shows off the basics of how to work with IDETs. //! //! ```rust //! use gdbstub::common::Signal; //! use gdbstub::target::{Target, TargetResult}; //! use gdbstub::target::ext::base::BaseOps; //! use gdbstub::target::ext::base::singlethread::{ //! SingleThreadResumeOps, SingleThreadSingleStepOps //! }; //! use gdbstub::target::ext::base::singlethread::{ //! SingleThreadBase, SingleThreadResume, SingleThreadSingleStep //! }; //! use gdbstub::target::ext::breakpoints::{Breakpoints, SwBreakpoint}; //! use gdbstub::target::ext::breakpoints::{BreakpointsOps, SwBreakpointOps}; //! //! struct MyTarget; //! //! impl Target for MyTarget { //! type Error = (); //! type Arch = gdbstub_arch::arm::Armv4t; // as an example //! //! #[inline(always)] //! fn base_ops(&mut self) -> BaseOps { //! BaseOps::SingleThread(self) //! } //! //! // opt-in to support for setting/removing breakpoints //! #[inline(always)] //! fn support_breakpoints(&mut self) -> Option> { //! Some(self) //! } //! } //! //! impl SingleThreadBase for MyTarget { //! fn read_registers( //! &mut self, //! regs: &mut gdbstub_arch::arm::reg::ArmCoreRegs, //! ) -> TargetResult<(), Self> { todo!() } //! //! fn write_registers( //! &mut self, //! regs: &gdbstub_arch::arm::reg::ArmCoreRegs //! ) -> TargetResult<(), Self> { todo!() } //! //! fn read_addrs( //! &mut self, //! start_addr: u32, //! data: &mut [u8], //! ) -> TargetResult { todo!() } //! //! fn write_addrs( //! &mut self, //! start_addr: u32, //! data: &[u8], //! ) -> TargetResult<(), Self> { todo!() } //! //! // most targets will want to support at resumption as well... //! //! #[inline(always)] //! fn support_resume(&mut self) -> Option> { //! Some(self) //! } //! } //! //! impl SingleThreadResume for MyTarget { //! fn resume( //! &mut self, //! signal: Option, //! ) -> Result<(), Self::Error> { todo!() } //! //! // ...and if the target supports resumption, it'll likely want to support //! // single-step resume as well //! //! #[inline(always)] //! fn support_single_step( //! &mut self //! ) -> Option> { //! Some(self) //! } //! } //! //! impl SingleThreadSingleStep for MyTarget { //! fn step( //! &mut self, //! signal: Option, //! ) -> Result<(), Self::Error> { todo!() } //! } //! //! impl Breakpoints for MyTarget { //! // there are several kinds of breakpoints - this target uses software breakpoints //! #[inline(always)] //! fn support_sw_breakpoint(&mut self) -> Option> { //! Some(self) //! } //! } //! //! impl SwBreakpoint for MyTarget { //! fn add_sw_breakpoint( //! &mut self, //! addr: u32, //! kind: gdbstub_arch::arm::ArmBreakpointKind, //! ) -> TargetResult { todo!() } //! //! fn remove_sw_breakpoint( //! &mut self, //! addr: u32, //! kind: gdbstub_arch::arm::ArmBreakpointKind, //! ) -> TargetResult { todo!() } //! } //! ``` //! //! ## A note on error handling //! //! As you explore the various protocol extension traits, you'll often find that //! functions don't return a typical [`Result`], //! and will instead return a [`TargetResult`]. //! //! At first glance this might look a bit strange, since it looks like the `Err` //! variant of `TargetResult` is `Self` instead of `Self::Error`! //! //! Thankfully, there's a good reason for why that's the case. In a nutshell, //! `TargetResult` wraps a typical `Result` with a few //! additional error types which can be reported back to the GDB client via the //! GDB RSP. //! //! For example, if the GDB client tried to read memory from invalid memory, //! instead of immediately terminating the entire debugging session, it's //! possible to simply return a `Err(TargetError::Errno(14)) // EFAULT`, which //! will notify the GDB client that the operation has failed. //! //! See the [`TargetError`] docs for more details. //! //! ## A note on all the `::` syntax //! //! As you explore `Target` and its many extension traits, you'll enounter //! many method signatures that use this pretty gnarly bit of Rust type syntax. //! //! If [rust-lang/rust#38078](https://github.com/rust-lang/rust/issues/38078) //! gets fixed, then types like `::Foo` could be simplified //! to just `Self::Arch::Foo`, but 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. //! //! To improve the readability and maintainability of your own implementation, //! it'd be best to swap out the fully qualified syntax with whatever concrete //! type is being used. e.g: on a 32-bit target, instead of cluttering up a //! method implementation with a parameter passed as `(addr: ::Usize)`, just write `(addr: u32)` directly. use crate::arch::Arch; pub mod ext; /// The error type for various methods on `Target` and its assorted associated /// extension traits. /// /// # Error Handling over the GDB Remote Serial Protocol /// /// The GDB Remote Serial Protocol has less-than-stellar support for error /// handling, typically taking the form of a single-byte /// [`errno`-style error codes](https://chromium.googlesource.com/chromiumos/docs/+/HEAD/constants/errnos.md). /// Moreover, often times the GDB client will simply _ignore_ the specific error /// code returned by the stub, and print a generic failure message instead. /// /// As such, while it's certainly better to use appropriate error codes when /// possible (e.g: returning a `EFAULT` (14) when reading from invalid memory), /// it's often fine to simply return the more general `TargetError::NonFatal` /// instead, and avoid the headache of picking a "descriptive" error code. Under /// the good, `TargetError::NonFatal` is sent to the GDB client as a generic /// `EREMOTEIO` (121) error. /// /// # `From` and `Into` implementations /// /// - `From<()>` -> `TargetError::NonFatal` /// - `From` -> `TargetError::Io(io::Error)` (requires `std` feature) /// /// When using a custom target-specific fatal error type, users are encouraged /// to write the following impl to simplify error handling in `Target` methods: /// /// ```rust /// use gdbstub::target::TargetError; /// /// /// Target-specific Fatal Error /// enum MyTargetFatalError { /// // ... /// } /// /// impl From for TargetError { /// fn from(e: MyTargetFatalError) -> Self { /// TargetError::Fatal(e) /// } /// } /// ``` /// /// Unfortunately, a blanket impl such as `impl From for /// TargetError` isn't possible, as it could result in impl conflicts. /// For example, if a Target decided to use `()` as its fatal error type, then /// there would be conflict with the existing `From<()>` impl. #[non_exhaustive] pub enum TargetError { /// A non-specific, non-fatal error has occurred. NonFatal, /// Non-fatal I/O Error. Only available when the `std` feature is enabled. /// /// At the moment, this is just shorthand for /// `TargetError::NonFatal(e.raw_os_err().unwrap_or(121))`. Error code `121` /// corresponds to `EREMOTEIO`. /// /// In the future, `gdbstub` may add support for the "QEnableErrorStrings" /// LLDB protocol extension, which would allow sending additional error /// context (in the form of an ASCII string) when an I/O error occurs. If /// this is something you're interested in, consider opening a PR! #[cfg(feature = "std")] Io(std::io::Error), /// An operation-specific non-fatal error code. Errno(u8), /// A target-specific fatal error. /// /// **WARNING:** Returning this error will immediately terminate the GDB /// debugging session, and return a /// [`GdbStubError`](crate::stub::GdbStubError)! Fatal(E), } /// Converts a `()` into a `TargetError::NonFatal`. impl From<()> for TargetError { fn from(_: ()) -> TargetError { TargetError::NonFatal } } /// Converts a `std::io::Error` into a `TargetError::Io`. #[cfg(feature = "std")] impl From for TargetError { fn from(e: std::io::Error) -> TargetError { TargetError::Io(e) } } /// A specialized `Result` type for `Target` operations. Supports reporting /// non-fatal errors back to the GDB client. /// /// See [`TargetError`] for more details. /// /// _Note:_ While it's typically parameterized as `TargetResult`, the /// error value is in-fact `TargetError` (not `Self`). pub type TargetResult = Result::Error>>; /// Describes the architecture and capabilities of a target which can be /// debugged by [`GdbStub`](../struct.GdbStub.html). /// /// The [`Target`](trait.Target.html) trait describes how to control and modify /// a system's execution state during a GDB debugging session, and serves as the /// primary bridge between `gdbstub`'s generic protocol implementation and a /// target's project/platform-specific code. /// /// **`Target` is the most important trait in `gdbstub`, and must be implemented /// by anyone who uses the library!** /// /// Please refer to the the documentation in the [`target` module](self) /// for more information on how to implement and work with `Target` and its /// various extension traits. pub trait Target { /// The target's architecture. type Arch: Arch; /// A target-specific **fatal** error. type Error; /// Base operations such as reading/writing from memory/registers, /// stopping/resuming the target, etc.... /// /// For example, on a single-threaded target: /// /// ```rust /// use gdbstub::target::Target; /// use gdbstub::target::ext::base::BaseOps; /// use gdbstub::target::ext::base::singlethread::SingleThreadBase; /// # use gdbstub::target::TargetResult; /// # struct MyTarget; /// /// impl Target for MyTarget { /// // ... /// # type Arch = gdbstub_arch::arm::Armv4t; /// # type Error = (); /// /// fn base_ops(&mut self) -> BaseOps { /// BaseOps::SingleThread(self) /// } /// } /// /// // ...and then implement the associated base IDET /// impl SingleThreadBase for MyTarget { /// // ... /// # fn read_registers( /// # &mut self, /// # regs: &mut gdbstub_arch::arm::reg::ArmCoreRegs, /// # ) -> TargetResult<(), Self> { todo!() } /// # /// # fn write_registers( /// # &mut self, /// # regs: &gdbstub_arch::arm::reg::ArmCoreRegs /// # ) -> TargetResult<(), Self> { todo!() } /// # /// # fn read_addrs( /// # &mut self, /// # start_addr: u32, /// # data: &mut [u8], /// # ) -> TargetResult { todo!() } /// # /// # fn write_addrs( /// # &mut self, /// # start_addr: u32, /// # data: &[u8], /// # ) -> TargetResult<(), Self> { todo!() } /// } /// ``` fn base_ops(&mut self) -> ext::base::BaseOps<'_, Self::Arch, Self::Error>; /// If the target supports resumption, but hasn't implemented explicit /// support for software breakpoints (via /// [`SwBreakpoints`](ext::breakpoints::SwBreakpoint)), notify the user /// that the GDB client may set "implicit" software breakpoints by /// rewriting the target's instruction stream. /// /// Targets that wish to use the GDB client's implicit software breakpoint /// handler must explicitly **opt-in** to this somewhat surprising GDB /// feature by overriding this method to return `true`. /// /// # Context /// /// An "implicit" software breakpoint is set by the GDB client by manually /// writing a software breakpoint instruction into target memory via the /// target's `write_addrs` implementation. i.e: the GDB client will /// overwrite the target's instruction stream with a software breakpoint /// instruction, with the expectation that the target has a implemented a /// breakpoint exception handler. /// /// # Implications /// /// While this is a reasonable (and useful!) bit of behavior when targeting /// many classes of remote stub (e.g: bare-metal, separate process), there /// are many `gdbstub` implementations that do _not_ implement "software /// breakpoints" by naively rewriting the target's instruction stream. /// /// - e.g: a `gdbstub` implemented in an emulator is unlikely to implement /// "software breakpoints" by hooking into the emulated hardware's /// breakpoint handler, and would likely implement "breakpoints" by /// maintaining a list of addresses to stop at as part of its core /// interpreter loop. /// - e.g: a `gdbstub` implemented in a hypervisor would require special /// coordination with the guest kernel to support software breakpoints, as /// there would need to be some way to distinguish between "in-guest" /// debugging, and "hypervisor" debugging. /// /// As such, `gdbstub` includes this `guard_rail_implicit_sw_breakpoints` /// method. /// /// As the name suggests, this method acts as a "guard rail" that /// warns users from accidentally opting into this "implicit" breakpoint /// functionality, and being exceptionally confused as to why their /// target is acting weird. /// /// If `gdbstub` detects that the target has not implemented a software /// breakpoint handler, it will check if /// `guard_rail_implicit_sw_breakpoints()` has been enabled, and if it /// has not, it will trigger a runtime error that points the user at this /// very documentation. /// /// # A note on breakpoints /// /// Aside from setting breakpoints at the explicit behest of the user (e.g: /// when setting breakpoints via the `b` command in GDB), the GDB client may /// also set/remove _temporary breakpoints_ as part of other commands. /// /// e.g: On targets without native support for hardware single-stepping, /// calling `stepi` in GDB will result in the GDB client setting a temporary /// breakpoint on the next instruction + resuming via `continue` instead. #[inline(always)] fn guard_rail_implicit_sw_breakpoints(&self) -> bool { false } /// Enable/disable support for activating "no ack mode". /// /// By default, this method returns `true`. /// /// _Author's note:_ Unless you're using `gdbstub` with a truly unreliable /// transport line (e.g: a noisy serial connection), it's best to support /// "no ack mode", as it can substantially improve debugging latency. /// /// **Warning:** `gdbstub` doesn't currently implement all necessary /// features for running correctly over a unreliable transport! See issue /// [\#137](https://github.com/daniel5151/gdbstub/issues/137) for details. /// /// # What is "No Ack Mode"? /// /// From the [GDB RSP docs](https://sourceware.org/gdb/onlinedocs/gdb/Packet-Acknowledgment.html#Packet-Acknowledgment): /// /// > By default, when either the host or the target machine receives a /// > packet, the first response expected is an acknowledgment: either '+' /// > (to indicate the package was received correctly) or '-' (to request /// > retransmission). This mechanism allows the GDB remote protocol to /// > operate over unreliable transport mechanisms, such as a serial line. /// > /// > In cases where the transport mechanism is itself reliable (such as a /// > pipe or TCP connection), the '+'/'-' acknowledgments are redundant. It /// > may be desirable to disable them in that case to reduce communication /// > overhead, or for other reasons. This can be accomplished by means of /// > the 'QStartNoAckMode' packet #[inline(always)] fn use_no_ack_mode(&self) -> bool { true } /// Enable/disable using the more efficient `X` packet to write to target /// memory (as opposed to the basic `M` packet). /// /// By default, this method returns `true`. /// /// _Author's note:_ Unless you're _really_ trying to squeeze `gdbstub` onto /// a particularly resource-constrained platform, you may as well leave this /// optimization enabled. #[inline(always)] fn use_x_upcase_packet(&self) -> bool { true } /// Whether `gdbstub` should provide a "stub" `resume` implementation on /// targets without support for resumption. /// /// At the time of writing, the mainline GDB client does not gracefully /// handle targets that do not support support resumption, and will hang /// indefinitely if a user inadvertently attempts to `continue` or `step` /// such a target. /// /// To make the `gdbstub` user experience a bit better, the library includes /// bit of "stub" code to gracefully handle these cases. /// /// If a user attempts to resume a target that hasn't implemented support /// for resumption, `gdbstub` will write a brief message back to the GDB /// client console, and will immediately return a "stopped with TRAP" stop /// reason. /// /// This method controls whether or not this bt of behavior is enabled. /// /// _Author's note:_ Unless you're _really_ trying to squeeze `gdbstub` onto /// a particularly resource-constrained platform, you may as well leave this /// enabled. The resulting stub code is entirely optimized out on targets /// that implement support for resumption. #[inline(always)] fn use_resume_stub(&self) -> bool { true } /// Enable/Disable the use of run-length encoding on outgoing packets. /// /// This is enabled by default, as RLE can save substantial amounts of /// bandwidth down the wire. /// /// _Author's note:_ There are essentially no reasons to disable RLE, unless /// you happen to be using a custom GDB client that doesn't support RLE. #[inline(always)] fn use_rle(&self) -> bool { true } /// Whether to send a target description XML to the client. /// /// Setting this to `false` will override both /// [`Target::support_target_description_xml_override`] and the associated /// [`Arch::target_description_xml`]. /// /// _Author's note:_ Having the GDB client autodetect your target's /// architecture and register set is really useful, so unless you're /// _really_ trying to squeeze `gdbstub` onto a particularly /// resource-constrained platform, you may as well leave this enabled. #[inline(always)] fn use_target_description_xml(&self) -> bool { true } /// (LLDB extension) Whether to send register information to the client. /// /// Setting this to `false` will override both /// [`Target::support_lldb_register_info_override`] and the associated /// [`Arch::lldb_register_info`]. /// /// _Author's note:_ Having the LLDB client autodetect your target's /// register set is really useful, so unless you're _really_ trying to /// squeeze `gdbstub` onto a particularly resource-constrained platform, you /// may as well leave this enabled. #[inline(always)] fn use_lldb_register_info(&self) -> bool { true } /// Support for setting / removing breakpoints. #[inline(always)] fn support_breakpoints(&mut self) -> Option> { None } /// Support for handling custom GDB `monitor` commands. #[inline(always)] fn support_monitor_cmd(&mut self) -> Option> { None } /// Support for Extended Mode operations. #[inline(always)] fn support_extended_mode(&mut self) -> Option> { None } /// Support for handling requests to get the target's current section (or /// segment) offsets. #[inline(always)] fn support_section_offsets( &mut self, ) -> Option> { None } /// Support for overriding the target description XML specified by /// `Target::Arch`. #[inline(always)] fn support_target_description_xml_override( &mut self, ) -> Option> { None } /// (LLDB extension) Support for overriding the register info specified by /// `Target::Arch`. #[inline(always)] fn support_lldb_register_info_override( &mut self, ) -> Option> { None } /// Support for reading the target's memory map. #[inline(always)] fn support_memory_map(&mut self) -> Option> { None } /// Support for setting / removing syscall catchpoints. #[inline(always)] fn support_catch_syscalls( &mut self, ) -> Option> { None } /// Support for Host I/O operations. #[inline(always)] fn support_host_io(&mut self) -> Option> { None } /// Support for reading the current exec-file. #[inline(always)] fn support_exec_file(&mut self) -> Option> { None } /// Support for reading the target's Auxillary Vector. #[inline(always)] fn support_auxv(&mut self) -> Option> { None } /// Support for reading a list of libraries for SVR4 (System-V/Unix) /// platforms. #[inline(always)] fn support_libraries_svr4(&mut self) -> Option> { None } } macro_rules! __delegate { (fn $op:ident(&mut $this:ident) $($sig:tt)*) => { fn $op(&mut $this) $($sig)* { (**$this).$op() } }; (fn $op:ident(&$this:ident) $($sig:tt)*) => { fn $op(&$this) $($sig)* { (**$this).$op() } } } macro_rules! __delegate_support { ($ext:ident) => { paste::paste! { __delegate!(fn [](&mut self) -> Option]<'_, Self>>); } }; } macro_rules! impl_dyn_target { ($type:ty) => { impl Target for $type where A: Arch, { type Arch = A; type Error = E; __delegate!(fn base_ops(&mut self) -> ext::base::BaseOps<'_, Self::Arch, Self::Error>); __delegate!(fn guard_rail_implicit_sw_breakpoints(&self) -> bool); __delegate!(fn use_no_ack_mode(&self) -> bool); __delegate!(fn use_x_upcase_packet(&self) -> bool); __delegate!(fn use_resume_stub(&self) -> bool); __delegate!(fn use_rle(&self) -> bool); __delegate!(fn use_target_description_xml(&self) -> bool); __delegate!(fn use_lldb_register_info(&self) -> bool); __delegate_support!(breakpoints); __delegate_support!(monitor_cmd); __delegate_support!(extended_mode); __delegate_support!(section_offsets); __delegate_support!(target_description_xml_override); __delegate_support!(lldb_register_info_override); __delegate_support!(memory_map); __delegate_support!(catch_syscalls); __delegate_support!(host_io); __delegate_support!(exec_file); __delegate_support!(auxv); } }; } impl_dyn_target!(&mut dyn Target); #[cfg(feature = "alloc")] impl_dyn_target!(alloc::boxed::Box>);