pub trait Arch {
type Usize: Debug + FromPrimitive + PrimInt + Unsigned + BeBytes + LeBytes;
type Registers: Registers<ProgramCounter = Self::Usize>;
type BreakpointKind: BreakpointKind;
type RegId: RegId;
fn single_step_gdb_behavior() -> SingleStepGdbBehavior;
fn target_description_xml() -> Option<&'static str> { ... }
}
Expand description
Encodes architecture-specific information, such as pointer size, register layout, etc…
Types implementing Arch
should be
Zero-variant Enums,
as Arch
impls are only ever used at the type level, and should never be
explicitly instantiated.
Associated Types
The architecture’s pointer size (e.g: u32
on a 32-bit system).
The architecture’s register file. See Registers
for more details.
The architecture’s breakpoint “kind”, used to determine the “size”
of breakpoint to set. See BreakpointKind
for more details.
Register identifier enum/struct.
Used to access individual registers via Target::read/write_register
.
NOTE: An arch’s
RegId
type is not strictly required to have a 1:1 correspondence with theRegisters
type, and may include register identifiers which are separate from the mainRegisters
structure. (e.g: the RISC-V Control and Status registers)
Required methods
Encode how the mainline GDB client handles target support for single-step on this particular architecture.
Context
According to the spec, supporting single step should be quite straightforward:
- The GDB client sends a
vCont?
packet to enumerate supported resumption modes - If the target supports single-step, it responds with the
s;S
capability as part of the response, omitting it if it is not supported. - Later, when the user attempts to
stepi
, the GDB client sends as
resumption reason if it is supported, falling back to setting a temporary breakpoint + continue to “emulate” the single step.
Unfortunately, the reality is that the mainline GDB client does not do this on all architectures…
- On certain architectures (e.g: x86), GDB will unconditionally assume single-step support, regardless whether or not the target reports supports it.
- On certain architectures (e.g: MIPS), GDB will never use single-step support, even in the target has explicitly reported support for it.
This is a bug, and has been reported at https://sourceware.org/bugzilla/show_bug.cgi?id=28440.
For a easy repro of this behavior, also see https://github.com/daniel5151/gdb-optional-step-bug.
Implications
Unfortunately, even if these idiosyncratic behaviors get fixed in the mainline GDB client, it will be quite a while until the typical user’s distro-provided GDB client includes this bugfix.
As such, gdbstub
has opted to include this method as a “guard rail” to
preemptively detect cases of this idiosyncratic behavior, and throw a
pre-init error that informs the user of the potential issues they may
run into.
Unknown
implementations
Because this method was only introduced in gdbstub
version 0.6, there
are many existing Arch
implementations in the
gdbstub_arch
companion crate that
have not yet been tested and updated what kind of behavior they exhibit.
These implementations currently return
SingleStepGdbBehavior::Unknown
, which will result in a pre-init
error that notifies users of this issue, along with imploring them
to be a Good Citizen and discover + upstream a proper implementation
of this method for their Arch
.
Writing a proper implementation
To check whether or not a particular architecture exhibits this
behavior, an implementation should temporarily override this method to
return SingleStepGdbBehavior::Optional
, toggle target support for
single-step on/off, and observe the behavior of the GDB client after
invoking stepi
.
If single-stepping was disabled, yet the client nonetheless sent a
vCont
packet with a s
resume action, then this architecture
does not support optional single stepping, and this method should
return SingleStepGdbBehavior::Required
.
If single-stepping was disabled, and the client attempted to set a
temporary breakpoint (using the z
packet), and then sent a vCont
packet with a c
resume action, then this architecture does
support optional single stepping, and this method should return
SingleStepGdbBehavior::Optional
.
If single-stepping was enabled, yet the client did not send a
vCont
packet with a s
resume action, then this architecture
ignores single stepping entirely, and this method should return
SingleStepGdbBehavior::Ignored
.
Provided methods
fn target_description_xml() -> Option<&'static str>
fn target_description_xml() -> Option<&'static str>
(optional) Return the arch’s description XML file (target.xml
).
Implementing this method enables GDB to automatically detect the
target’s architecture, saving the hassle of having to run set architecture <arch>
when starting a debugging session.
These descriptions can be quite succinct. For example, the target
description for an armv4t
target can be as simple as:
r#"<target version="1.0"><architecture>armv4t</architecture></target>"#;
See the GDB docs for details on the target description XML format.