aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Barman <ludovicb@google.com>2024-01-05 10:17:19 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2024-01-05 10:17:19 +0000
commit96a25493be233ea1eaf7eeb785bbffb4fc92d53d (patch)
tree5e90745c9225a8b6a609a3a5dfc65d6d614e79da
parent756447bd7b0a4dd760e3ebfdf8db6170f67dd7db (diff)
parent4d46537554c908e8e66b98b33b738b756b804dbd (diff)
downloadgdbstub-96a25493be233ea1eaf7eeb785bbffb4fc92d53d.tar.gz
Upgrade gdbstub to 0.7.0 am: 4d46537554
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/gdbstub/+/2878118 Change-Id: Iea99b861d612aadd13e55ae2da20db10aaa9373f Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--.cargo/config.toml1
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--.git-blame-ignore-revs2
-rw-r--r--Android.bp4
-rw-r--r--CHANGELOG.md39
-rw-r--r--Cargo.toml4
-rw-r--r--Cargo.toml.orig4
-rw-r--r--METADATA21
-rw-r--r--README.md14
-rw-r--r--cargo_embargo.json3
-rw-r--r--docs/transition_guide.md70
-rw-r--r--examples/armv4t/emu.rs15
-rw-r--r--examples/armv4t/gdb/auxv.rs5
-rw-r--r--examples/armv4t/gdb/breakpoints.rs3
-rw-r--r--examples/armv4t/gdb/catch_syscalls.rs3
-rw-r--r--examples/armv4t/gdb/exec_file.rs5
-rw-r--r--examples/armv4t/gdb/extended_mode.rs27
-rw-r--r--examples/armv4t/gdb/host_io.rs21
-rw-r--r--examples/armv4t/gdb/lldb_register_info_override.rs13
-rw-r--r--examples/armv4t/gdb/memory_map.rs5
-rw-r--r--examples/armv4t/gdb/mod.rs52
-rw-r--r--examples/armv4t/gdb/monitor_cmd.rs6
-rw-r--r--examples/armv4t/gdb/section_offsets.rs3
-rw-r--r--examples/armv4t/gdb/target_description_xml_override.rs5
-rw-r--r--examples/armv4t/main.rs33
-rw-r--r--examples/armv4t_multicore/emu.rs13
-rw-r--r--examples/armv4t_multicore/gdb.rs23
-rw-r--r--examples/armv4t_multicore/main.rs34
-rw-r--r--rustfmt.toml3
-rw-r--r--src/arch.rs105
-rw-r--r--src/common/signal.rs790
-rw-r--r--src/conn/impls/boxed.rs1
-rw-r--r--src/conn/impls/tcpstream.rs3
-rw-r--r--src/conn/impls/unixstream.rs5
-rw-r--r--src/lib.rs31
-rw-r--r--src/protocol/commands.rs31
-rw-r--r--src/protocol/commands/_QCatchSyscalls.rs1
-rw-r--r--src/protocol/commands/_d_upcase.rs1
-rw-r--r--src/protocol/commands/_h_upcase.rs1
-rw-r--r--src/protocol/commands/_qAttached.rs1
-rw-r--r--src/protocol/commands/_qC.rs14
-rw-r--r--src/protocol/commands/_qThreadExtraInfo.rs1
-rw-r--r--src/protocol/commands/_qXfer_auxv_read.rs4
-rw-r--r--src/protocol/commands/_qXfer_exec_file.rs4
-rw-r--r--src/protocol/commands/_qXfer_features_read.rs4
-rw-r--r--src/protocol/commands/_qXfer_memory_map.rs4
-rw-r--r--src/protocol/commands/_t_upcase.rs1
-rw-r--r--src/protocol/commands/_vAttach.rs1
-rw-r--r--src/protocol/commands/_vCont.rs8
-rw-r--r--src/protocol/commands/_vFile_open.rs4
-rw-r--r--src/protocol/commands/_vFile_pwrite.rs1
-rw-r--r--src/protocol/commands/_vFile_setfs.rs1
-rw-r--r--src/protocol/commands/_vKill.rs1
-rw-r--r--src/protocol/commands/_vRun.rs1
-rw-r--r--src/protocol/commands/_x_upcase.rs1
-rw-r--r--src/protocol/commands/breakpoint.rs3
-rw-r--r--src/protocol/common/hex.rs5
-rw-r--r--src/protocol/common/lists.rs3
-rw-r--r--src/protocol/common/thread_id.rs6
-rw-r--r--src/protocol/console_output.rs3
-rw-r--r--src/protocol/mod.rs16
-rw-r--r--src/protocol/recv_packet.rs5
-rw-r--r--src/protocol/response_writer.rs12
-rw-r--r--src/stub/builder.rs14
-rw-r--r--src/stub/core_impl.rs47
-rw-r--r--src/stub/core_impl/base.rs138
-rw-r--r--src/stub/core_impl/breakpoints.rs4
-rw-r--r--src/stub/core_impl/catch_syscalls.rs3
-rw-r--r--src/stub/core_impl/extended_mode.rs59
-rw-r--r--src/stub/core_impl/host_io.rs6
-rw-r--r--src/stub/core_impl/lldb_register_info.rs14
-rw-r--r--src/stub/core_impl/monitor_cmd.rs1
-rw-r--r--src/stub/core_impl/no_ack_mode.rs25
-rw-r--r--src/stub/core_impl/resume.rs46
-rw-r--r--src/stub/core_impl/reverse_exec.rs9
-rw-r--r--src/stub/core_impl/single_register_access.rs4
-rw-r--r--src/stub/core_impl/target_xml.rs3
-rw-r--r--src/stub/core_impl/x_upcase_packet.rs3
-rw-r--r--src/stub/error.rs244
-rw-r--r--src/stub/mod.rs73
-rw-r--r--src/stub/state_machine.rs36
-rw-r--r--src/target/ext/auxv.rs3
-rw-r--r--src/target/ext/base/multithread.rs21
-rw-r--r--src/target/ext/base/single_register_access.rs3
-rw-r--r--src/target/ext/base/singlethread.rs21
-rw-r--r--src/target/ext/breakpoints.rs3
-rw-r--r--src/target/ext/catch_syscalls.rs3
-rw-r--r--src/target/ext/exec_file.rs4
-rw-r--r--src/target/ext/extended_mode.rs51
-rw-r--r--src/target/ext/host_io.rs37
-rw-r--r--src/target/ext/lldb_register_info_override.rs7
-rw-r--r--src/target/ext/memory_map.rs3
-rw-r--r--src/target/ext/monitor_cmd.rs7
-rw-r--r--src/target/ext/target_description_xml_override.rs3
-rw-r--r--src/target/mod.rs79
95 files changed, 1313 insertions, 1167 deletions
diff --git a/.cargo/config.toml b/.cargo/config.toml
index 86e7347..f74f939 100644
--- a/.cargo/config.toml
+++ b/.cargo/config.toml
@@ -56,4 +56,5 @@ rustflags = [
# type StopReason = MultiThreadStopReason<<Self::Arch as Arch>::Usize>>;
# Result<Option<StopReason>, Self::Error>
"-Aclippy::type_complexity",
+ "-Aclippy::manual_range_patterns",
]
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index a57d223..8350bf5 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
{
"git": {
- "sha1": "85ff370e018c031bc88438123bf2766c2c806d63"
+ "sha1": "c489dcdf5992d6e7ebfcf37775ce81dc8cf7861d"
},
"path_in_vcs": ""
} \ No newline at end of file
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 0000000..47e59e3
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,2 @@
+# fmt everything using imports_granularity = "Item"
+e2329b80c2d51ee0ab4678365a35b27b51f32235
diff --git a/Android.bp b/Android.bp
index df5246e..654cb99 100644
--- a/Android.bp
+++ b/Android.bp
@@ -23,7 +23,7 @@ rust_library {
host_supported: true,
crate_name: "gdbstub",
cargo_env_compat: true,
- cargo_pkg_version: "0.6.4",
+ cargo_pkg_version: "0.7.0",
srcs: ["src/lib.rs"],
edition: "2018",
features: [
@@ -33,7 +33,7 @@ rust_library {
"trace-pkt",
],
rustlibs: [
- "libbitflags-1.3.2",
+ "libbitflags",
"libcfg_if",
"liblog_rust",
"libmanaged",
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 435154f..97a4ae4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,45 @@ All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+# 0.7.0
+
+#### Breaking API Changes
+
+- `stub::GdbStubError` is now an opaque `struct` with a handful of methods to extract user-defined context (as opposed to being an `enum` that directly exposed all error internals to the user).
+ - _This change will enable future versions of `gdbstub` to fearlessly improve error messages and infrastructure without making semver breaking changes. See [\#112](https://github.com/daniel5151/gdbstub/pull/132) for more._
+- `common::Signal` is not longer an `enum`, and is instead a `struct` with a single `pub u8` field + a collection of associated constants.
+ - _As a result, yet another instance of `unsafe` could be removed from the codebase!_
+- `Arch` API:
+ - Entirely removed `single_step_behavior`. See [\#132](https://github.com/daniel5151/gdbstub/pull/132) for details and rationale
+- `Target` APIs:
+ - `SingleThreadBase`/`MultiThreadBase`
+ - `read_addrs` now returns a `usize` instead of a `()`, allowing implementations to report cases where only a subset of memory could be read.
+ - `HostIo`
+ - `bitflags` has been updated from `1.x` to `2.x`, affecting the type of `HostIoOpenFlags` and `HostIoOpenMode`
+
+#### Internal Improvements
+
+- Reformatted codebase with nightly rustfmt using `imports_granularity = "Item"`
+
+# 0.6.6
+
+#### New Features
+
+- `Target::use_no_ack_mode` - toggle support for for activating "no ack mode" [\#135](https://github.com/daniel5151/gdbstub/pull/135) ([bet4it](https://github.com/bet4it))
+
+# 0.6.5
+
+#### New Protocol Extensions
+
+- `ExtendedMode > CurrentActivePid` - Support reporting a non-default active PID [\#133](https://github.com/daniel5151/gdbstub/pull/129)
+ - Required to fix `vAttach` behavior (see Bugfixes section below)
+
+#### Bugfixes
+
+- Fix for targets with no active threads [\#127](https://github.com/daniel5151/gdbstub/pull/127) ([xobs](https://github.com/xobs))
+- Fix `vAttach` behavior when switching between multiple processes [\#129](https://github.com/daniel5151/gdbstub/pull/129) ([xobs](https://github.com/xobs)), and [\#133](https://github.com/daniel5151/gdbstub/pull/129)
+- Minor doc fixes
+
# 0.6.4
#### Bugfixes
diff --git a/Cargo.toml b/Cargo.toml
index 3dcdd43..0eb81ed 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,7 +12,7 @@
[package]
edition = "2018"
name = "gdbstub"
-version = "0.6.4"
+version = "0.7.0"
authors = ["Daniel Prilik <danielprilik@gmail.com>"]
exclude = [
"examples/**/*.elf",
@@ -47,7 +47,7 @@ name = "armv4t_multicore"
required-features = ["std"]
[dependencies.bitflags]
-version = "1.3"
+version = "2.3.1"
[dependencies.cfg-if]
version = "1.0"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index f448235..445e67b 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -2,7 +2,7 @@
name = "gdbstub"
description = "An implementation of the GDB Remote Serial Protocol in Rust"
authors = ["Daniel Prilik <danielprilik@gmail.com>"]
-version = "0.6.4"
+version = "0.7.0"
license = "MIT OR Apache-2.0"
edition = "2018"
readme = "README.md"
@@ -14,7 +14,7 @@ categories = ["development-tools::debugging", "embedded", "emulators", "network-
exclude = ["examples/**/*.elf", "examples/**/*.o"]
[dependencies]
-bitflags = "1.3"
+bitflags = "2.3.1"
cfg-if = "1.0"
log = "0.4"
managed = { version = "0.8", default-features = false }
diff --git a/METADATA b/METADATA
index 4b50ec0..146415c 100644
--- a/METADATA
+++ b/METADATA
@@ -1,23 +1,20 @@
# This project was upgraded with external_updater.
# Usage: tools/external_updater/updater.sh update rust/crates/gdbstub
-# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
name: "gdbstub"
description: "An implementation of the GDB Remote Serial Protocol in Rust"
third_party {
- url {
- type: HOMEPAGE
- value: "https://crates.io/crates/gdbstub"
- }
- url {
- type: ARCHIVE
- value: "https://static.crates.io/crates/gdbstub/gdbstub-0.6.4.crate"
- }
- version: "0.6.4"
license_type: NOTICE
last_upgrade_date {
year: 2023
- month: 3
- day: 6
+ month: 12
+ day: 16
+ }
+ homepage: "https://crates.io/crates/gdbstub"
+ identifier {
+ type: "Archive"
+ value: "https://static.crates.io/crates/gdbstub/gdbstub-0.7.0.crate"
+ version: "0.7.0"
}
}
diff --git a/README.md b/README.md
index c58e4f3..4ce94e4 100644
--- a/README.md
+++ b/README.md
@@ -4,13 +4,13 @@
[![](https://docs.rs/gdbstub/badge.svg)](https://docs.rs/gdbstub)
[![](https://img.shields.io/badge/license-MIT%2FApache-blue.svg)](./LICENSE)
-An ergonomic and easy-to-integrate implementation of the [GDB Remote Serial Protocol](https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html#Remote-Protocol) in Rust, with full `#![no_std]` support.
+An ergonomic, featureful, and easy-to-integrate implementation of the [GDB Remote Serial Protocol](https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html#Remote-Protocol) in Rust, with _no-compromises_ `#![no_std]` support.
`gdbstub` makes it easy to integrate powerful guest debugging support to your emulator / hypervisor / debugger / embedded project. By implementing just a few basic methods of the [`gdbstub::Target`](https://docs.rs/gdbstub/latest/gdbstub/target/ext/base/singlethread/trait.SingleThreadBase.html) trait, you can have a rich GDB debugging session up and running in no time!
`gdbstub`'s API makes extensive use of a technique called [**Inlineable Dyn Extension Traits**](#zero-overhead-protocol-extensions) (IDETs) to expose fine-grained, zero-cost control over enabled GDB protocol features _without_ relying on compile-time features flags. Aside from making it effortless to toggle enabled protocol features, IDETs also ensure that any unimplemented features are guaranteed to be dead-code-eliminated in release builds!
-**If you're looking for a quick snippet of example code to see what a typical `gdbstub` integration might look like, check out [examples/armv4t/gdb/mod.rs](https://github.com/daniel5151/gdbstub/blob/master/examples/armv4t/gdb/mod.rs)**
+**If you're looking for a quick snippet of example code to see what a featureful `gdbstub` integration might look like, check out [examples/armv4t/gdb/mod.rs](https://github.com/daniel5151/gdbstub/blob/master/examples/armv4t/gdb/mod.rs)**
- [Documentation (gdbstub)](https://docs.rs/gdbstub)
- [Documentation (gdbstub_arch)](https://docs.rs/gdbstub_arch)
@@ -134,8 +134,8 @@ If you end up using `gdbstub` in your project, consider opening a PR and adding
- [Firecracker](https://firecracker-microvm.github.io/) - A lightweight VMM developed by AWS (feature is in [PR](https://github.com/firecracker-microvm/firecracker/pull/2333))
- [uhyve](https://github.com/hermitcore/uhyve) - A minimal hypervisor for [RustyHermit](https://github.com/hermitcore/rusty-hermit)
- OS Kernels (using `gdbstub` on `no_std`)
+ - [`betrusted-io/xous-core`](https://github.com/betrusted-io/xous-core/blob/b471b604/kernel/src/debug/gdb.rs) - The Xous microkernel operating system
- [`vmware-labs/node-replicated-kernel`](https://github.com/vmware-labs/node-replicated-kernel/tree/4326704/kernel/src/arch/x86_64/gdb) - An (experimental) research OS kernel for x86-64 (amd64) machines
- - [`betrusted-io/xous-core`](https://github.com/betrusted-io/xous-core/blob/7d3d710/kernel/src/debug/gdb_server.rs) - The Xous microkernel operating system
- Emulators
- [solana_rbpf](https://github.com/solana-labs/rbpf) - VM and JIT compiler for eBPF programs
- [rustyboyadvance-ng](https://github.com/michelhe/rustboyadvance-ng/) - Nintendo Gameboy Advance emulator and debugger (ARMv4T)
@@ -178,8 +178,6 @@ The following list exhaustively documents all uses of `unsafe` in `gdbstub`:
- Don't emit provably unreachable panics
- `src/protocol/packet.rs`: Method in `PacketBuf` that use index using stored sub-`Range<usize>` into the buffer
- `src/protocol/common/hex.rs`: `decode_hex_buf`
- - Don't emit large `match`-arm LUT
- - `src/common.rs`: Checked transmute of `u8` to `Signal`
- When the `std` feature is enabled:
- `src/connection/impls/unixstream.rs`: An implementation of `UnixStream::peek` which uses `libc::recv`. Will be removed once [rust-lang/rust#76923](https://github.com/rust-lang/rust/issues/76923) stabilizes this feature in the stdlib.
@@ -220,7 +218,7 @@ Not that this is _not_ an exhaustive list, and is subject to change.
- [ ] Allow fine-grained control over target features via the `Arch` trait ([\#12](https://github.com/daniel5151/gdbstub/issues/12))
- [ ] Implement GDB's various high-level operating modes:
- [x] Single/Multi Thread debugging
- - [ ] Multiprocess Debugging
+ - [ ] Multiprocess Debugging ([\#124](https://github.com/daniel5151/gdbstub/issues/124)
- [ ] Requires adding a new `target::ext::base::multiprocess` API.
- _Note:_ `gdbstub` already implements multiprocess extensions "under-the-hood", and just hard-codes a fake PID, so this is mostly a matter of "putting in the work".
- [x] [Extended Mode](https://sourceware.org/gdb/current/onlinedocs/gdb/Connecting.html) (`target extended-remote`)
@@ -235,9 +233,7 @@ Additionally, while not _strict_ blockers to `1.0.0`, it would be good to explor
- [ ] How/if to support [LLDB extensions](https://raw.githubusercontent.com/llvm-mirror/lldb/master/docs/lldb-gdb-remote.txt) ([\#99](https://github.com/daniel5151/gdbstub/issues/99))
- [ ] Supporting multi-arch debugging via a single target
- e.g: debugging x86 and ARM processes on macOS
-- [ ] Proper handling of "nack" packets (for spotty connections)
- - Responding with "nack" is easy - the client has to re-transmit the command
- - Re-transmitting after receiving a "nack" might be a bit harder...
+- [ ] Proper handling of "nack" packets (for spotty connections) ([\#137](https://github.com/daniel5151/gdbstub/issues/137))
## License
diff --git a/cargo_embargo.json b/cargo_embargo.json
index 99df43f..cb908d7 100644
--- a/cargo_embargo.json
+++ b/cargo_embargo.json
@@ -1,6 +1,3 @@
{
- "module_name_overrides": {
- "libbitflags": "libbitflags-1.3.2"
- },
"run_cargo": false
}
diff --git a/docs/transition_guide.md b/docs/transition_guide.md
index 6197171..3ae106c 100644
--- a/docs/transition_guide.md
+++ b/docs/transition_guide.md
@@ -6,6 +6,76 @@ This document does _not_ discuss any new features that might have been added bet
> _Note:_ after reading through this doc, you may also find it helpful to refer to the in-tree `armv4t` and `armv4t_multicore` examples when transitioning between versions.
+## `0.6` -> `0.7`
+
+`0.7` is a fairly minimal "cleanup" release, landing a collection of small breaking changes that collectively improve various ergonomic issues in `gdbstub`'s API.
+
+The breaking changes introduced in `0.7` are generally trivial to fix, and porting from `0.6` to `0.7` shouldn't take more than ~10 minutes, at most.
+
+##### `stub::GdbStubError` Changes
+
+`stub::GdbStubError` is now an opaque `struct` with a handful of methods to extract user-defined context.
+
+**Please file an issue if your code required matching on concrete error variants aside from `TargetError` and `ConnectionError`!**.
+
+In contrast with the old version - which was an `enum` that directly exposed all error internals to the user - this new type will enable future versions of `gdbstub` to fearlessly improve error infrastructure without requiring semver breaking changes. See [\#112](https://github.com/daniel5151/gdbstub/pull/132) for more.
+
+Assuming you stuck to the example error handling described in the `gdbstub` getting started guide, adapting to the new type should be quite straightforward.
+
+
+```rust
+// ==== 0.6.x ==== //
+
+match gdb.run_blocking::<EmuGdbEventLoop>(&mut emu) {
+ Ok(disconnect_reason) => { ... },
+ Err(GdbStubError::TargetError(e)) => {
+ println!("target encountered a fatal error: {}", e)
+ }
+ Err(e) => {
+ println!("gdbstub encountered a fatal error: {}", e)
+ }
+}
+
+// ==== 0.7.0 ==== //
+
+match gdb.run_blocking::<EmuGdbEventLoop>(&mut emu) {
+ Ok(disconnect_reason) => { ... },
+ Err(e) => {
+ if e.is_target_error() {
+ println!(
+ "target encountered a fatal error: {}",
+ e.into_target_error().unwrap()
+ )
+ } else if e.is_connection_error() {
+ let (e, kind) = e.into_connection_error().unwrap();
+ println!("connection error: {:?} - {}", kind, e,)
+ } else {
+ println!("gdbstub encountered a fatal error: {}", e)
+ }
+ }
+}
+```
+
+
+##### `{Single, Multi}ThreadBase::read_addrs` return value
+
+`read_addrs` now returns a `usize` instead of a `()`, allowing implementations to report cases where only a subset of memory could be read.
+
+In the past, the only way to handle these cases was by returning a `TargetError`. This provides an alternative mechanism, which may or may not be more appropriate for your particular use-case.
+
+When upgrading, the Rust compiler will emit a clear error message pointing out the updated function signature. The fix should be trivial.
+
+##### Removal of `Arch::single_step_behavior`
+
+See [\#132](https://github.com/daniel5151/gdbstub/pull/132) for more discussion on why this API was removed.
+
+This change only affects you if you're maintaining a custom `Arch` implementation (vs. using a community-maintained one via `gdbstub_arch`).
+
+The fix here is to simply remove the `Arch::single_step_behavior` impl.
+
+That's it! It's that easy.
+
+
## `0.5` -> `0.6`
`0.6` introduces a large number of breaking changes to the public APIs, and will require quite a bit more more "hands on" porting than previous `gdbstub` upgrades.
diff --git a/examples/armv4t/emu.rs b/examples/armv4t/emu.rs
index e8f3305..e94131b 100644
--- a/examples/armv4t/emu.rs
+++ b/examples/armv4t/emu.rs
@@ -1,7 +1,12 @@
-use armv4t_emu::{reg, Cpu, ExampleMem, Memory, Mode};
-
-use crate::mem_sniffer::{AccessKind, MemSniffer};
+use crate::mem_sniffer::AccessKind;
+use crate::mem_sniffer::MemSniffer;
use crate::DynResult;
+use armv4t_emu::reg;
+use armv4t_emu::Cpu;
+use armv4t_emu::ExampleMem;
+use armv4t_emu::Memory;
+use armv4t_emu::Mode;
+use gdbstub::common::Pid;
const HLE_RETURN_ADDR: u32 = 0x12345678;
@@ -35,6 +40,8 @@ pub struct Emu {
pub(crate) watchpoints: Vec<u32>,
pub(crate) breakpoints: Vec<u32>,
pub(crate) files: Vec<Option<std::fs::File>>,
+
+ pub(crate) reported_pid: Pid,
}
impl Emu {
@@ -85,6 +92,8 @@ impl Emu {
watchpoints: Vec::new(),
breakpoints: Vec::new(),
files: Vec::new(),
+
+ reported_pid: Pid::new(1).unwrap(),
})
}
diff --git a/examples/armv4t/gdb/auxv.rs b/examples/armv4t/gdb/auxv.rs
index a0f163b..3be0549 100644
--- a/examples/armv4t/gdb/auxv.rs
+++ b/examples/armv4t/gdb/auxv.rs
@@ -1,8 +1,7 @@
-use gdbstub::target;
-use gdbstub::target::TargetResult;
-
use super::copy_range_to_buf;
use crate::emu::Emu;
+use gdbstub::target;
+use gdbstub::target::TargetResult;
impl target::ext::auxv::Auxv for Emu {
fn get_auxv(&self, offset: u64, length: usize, buf: &mut [u8]) -> TargetResult<usize, Self> {
diff --git a/examples/armv4t/gdb/breakpoints.rs b/examples/armv4t/gdb/breakpoints.rs
index 6fa3038..9d6d90d 100644
--- a/examples/armv4t/gdb/breakpoints.rs
+++ b/examples/armv4t/gdb/breakpoints.rs
@@ -1,9 +1,8 @@
+use crate::emu::Emu;
use gdbstub::target;
use gdbstub::target::ext::breakpoints::WatchKind;
use gdbstub::target::TargetResult;
-use crate::emu::Emu;
-
impl target::ext::breakpoints::Breakpoints for Emu {
#[inline(always)]
fn support_sw_breakpoint(
diff --git a/examples/armv4t/gdb/catch_syscalls.rs b/examples/armv4t/gdb/catch_syscalls.rs
index 63686f1..d58de98 100644
--- a/examples/armv4t/gdb/catch_syscalls.rs
+++ b/examples/armv4t/gdb/catch_syscalls.rs
@@ -1,8 +1,7 @@
+use crate::gdb::Emu;
use gdbstub::target;
use gdbstub::target::ext::catch_syscalls::SyscallNumbers;
-use crate::gdb::Emu;
-
// This implementation is for illustrative purposes only. If the target doesn't
// support syscalls then there is no need to implement this extension
diff --git a/examples/armv4t/gdb/exec_file.rs b/examples/armv4t/gdb/exec_file.rs
index e70a022..c2009a8 100644
--- a/examples/armv4t/gdb/exec_file.rs
+++ b/examples/armv4t/gdb/exec_file.rs
@@ -1,10 +1,9 @@
+use super::copy_range_to_buf;
+use crate::emu::Emu;
use gdbstub::common::Pid;
use gdbstub::target;
use gdbstub::target::TargetResult;
-use super::copy_range_to_buf;
-use crate::emu::Emu;
-
impl target::ext::exec_file::ExecFile for Emu {
fn get_exec_file(
&self,
diff --git a/examples/armv4t/gdb/extended_mode.rs b/examples/armv4t/gdb/extended_mode.rs
index 4b30657..31116f9 100644
--- a/examples/armv4t/gdb/extended_mode.rs
+++ b/examples/armv4t/gdb/extended_mode.rs
@@ -1,10 +1,11 @@
+use crate::emu::Emu;
use gdbstub::common::Pid;
use gdbstub::target;
-use gdbstub::target::ext::extended_mode::{Args, AttachKind, ShouldTerminate};
+use gdbstub::target::ext::extended_mode::Args;
+use gdbstub::target::ext::extended_mode::AttachKind;
+use gdbstub::target::ext::extended_mode::ShouldTerminate;
use gdbstub::target::TargetResult;
-use crate::emu::Emu;
-
/*=====================================
= Extended Mode =
=====================================*/
@@ -31,8 +32,11 @@ impl target::ext::extended_mode::ExtendedMode for Emu {
}
fn attach(&mut self, pid: Pid) -> TargetResult<(), Self> {
- eprintln!("GDB tried to attach to a process with PID {}", pid);
- Err(().into()) // non-specific failure
+ eprintln!("GDB attached to a process with PID {}", pid);
+ // stub implementation: just report the same code, but running under a
+ // different pid.
+ self.reported_pid = pid;
+ Ok(())
}
fn run(&mut self, filename: Option<&[u8]>, args: Args<'_, '_>) -> TargetResult<Pid, Self> {
@@ -96,6 +100,13 @@ impl target::ext::extended_mode::ExtendedMode for Emu {
) -> Option<target::ext::extended_mode::ConfigureWorkingDirOps<'_, Self>> {
Some(self)
}
+
+ #[inline(always)]
+ fn support_current_active_pid(
+ &mut self,
+ ) -> Option<target::ext::extended_mode::CurrentActivePidOps<'_, Self>> {
+ Some(self)
+ }
}
impl target::ext::extended_mode::ConfigureAslr for Emu {
@@ -158,3 +169,9 @@ impl target::ext::extended_mode::ConfigureWorkingDir for Emu {
Ok(())
}
}
+
+impl target::ext::extended_mode::CurrentActivePid for Emu {
+ fn current_active_pid(&mut self) -> Result<Pid, Self::Error> {
+ Ok(self.reported_pid)
+ }
+}
diff --git a/examples/armv4t/gdb/host_io.rs b/examples/armv4t/gdb/host_io.rs
index 40d6304..675b14e 100644
--- a/examples/armv4t/gdb/host_io.rs
+++ b/examples/armv4t/gdb/host_io.rs
@@ -1,13 +1,18 @@
-use std::io::{Read, Seek, Write};
-
-use gdbstub::target;
-use gdbstub::target::ext::host_io::{
- FsKind, HostIoErrno, HostIoError, HostIoOpenFlags, HostIoOpenMode, HostIoResult, HostIoStat,
-};
-
-use super::{copy_range_to_buf, copy_to_buf};
+use super::copy_range_to_buf;
+use super::copy_to_buf;
use crate::emu::Emu;
use crate::TEST_PROGRAM_ELF;
+use gdbstub::target;
+use gdbstub::target::ext::host_io::FsKind;
+use gdbstub::target::ext::host_io::HostIoErrno;
+use gdbstub::target::ext::host_io::HostIoError;
+use gdbstub::target::ext::host_io::HostIoOpenFlags;
+use gdbstub::target::ext::host_io::HostIoOpenMode;
+use gdbstub::target::ext::host_io::HostIoResult;
+use gdbstub::target::ext::host_io::HostIoStat;
+use std::io::Read;
+use std::io::Seek;
+use std::io::Write;
const FD_RESERVED: u32 = 1;
diff --git a/examples/armv4t/gdb/lldb_register_info_override.rs b/examples/armv4t/gdb/lldb_register_info_override.rs
index 664cb45..14a1279 100644
--- a/examples/armv4t/gdb/lldb_register_info_override.rs
+++ b/examples/armv4t/gdb/lldb_register_info_override.rs
@@ -1,12 +1,15 @@
-use gdbstub::arch::lldb::{Encoding, Format, Generic, Register};
+use crate::gdb::custom_arch::ArmCoreRegIdCustom;
+use crate::gdb::Emu;
+use gdbstub::arch::lldb::Encoding;
+use gdbstub::arch::lldb::Format;
+use gdbstub::arch::lldb::Generic;
+use gdbstub::arch::lldb::Register;
use gdbstub::arch::RegId;
use gdbstub::target;
-use gdbstub::target::ext::lldb_register_info_override::{Callback, CallbackToken};
+use gdbstub::target::ext::lldb_register_info_override::Callback;
+use gdbstub::target::ext::lldb_register_info_override::CallbackToken;
use gdbstub_arch::arm::reg::id::ArmCoreRegId;
-use crate::gdb::custom_arch::ArmCoreRegIdCustom;
-use crate::gdb::Emu;
-
// (LLDB extension) This implementation is for illustrative purposes only.
//
// Note: In this implementation, we have r0-pc from 0-16 but cpsr is at offset
diff --git a/examples/armv4t/gdb/memory_map.rs b/examples/armv4t/gdb/memory_map.rs
index ddddb65..0aa5c08 100644
--- a/examples/armv4t/gdb/memory_map.rs
+++ b/examples/armv4t/gdb/memory_map.rs
@@ -1,8 +1,7 @@
-use gdbstub::target;
-use gdbstub::target::TargetResult;
-
use super::copy_range_to_buf;
use crate::emu::Emu;
+use gdbstub::target;
+use gdbstub::target::TargetResult;
impl target::ext::memory_map::MemoryMap for Emu {
fn memory_map_xml(
diff --git a/examples/armv4t/gdb/mod.rs b/examples/armv4t/gdb/mod.rs
index 97f7b2d..5837ddd 100644
--- a/examples/armv4t/gdb/mod.rs
+++ b/examples/armv4t/gdb/mod.rs
@@ -1,14 +1,17 @@
+use crate::emu::Emu;
+use crate::emu::ExecMode;
+use armv4t_emu::reg;
+use armv4t_emu::Memory;
use core::convert::TryInto;
-
-use armv4t_emu::{reg, Memory};
use gdbstub::common::Signal;
use gdbstub::target;
-use gdbstub::target::ext::base::singlethread::{SingleThreadBase, SingleThreadResume};
-use gdbstub::target::{Target, TargetError, TargetResult};
+use gdbstub::target::ext::base::singlethread::SingleThreadBase;
+use gdbstub::target::ext::base::singlethread::SingleThreadResume;
+use gdbstub::target::Target;
+use gdbstub::target::TargetError;
+use gdbstub::target::TargetResult;
use gdbstub_arch::arm::reg::id::ArmCoreRegId;
-use crate::emu::{Emu, ExecMode};
-
// Additional GDB extensions
mod auxv;
@@ -196,11 +199,22 @@ impl SingleThreadBase for Emu {
Some(self)
}
- fn read_addrs(&mut self, start_addr: u32, data: &mut [u8]) -> TargetResult<(), Self> {
- for (addr, val) in (start_addr..).zip(data.iter_mut()) {
+ fn read_addrs(&mut self, start_addr: u32, data: &mut [u8]) -> TargetResult<usize, Self> {
+ // These values are taken from the link script.
+ const MEMORY_ORIGIN: u32 = 0x5555_0000;
+ const MEMORY_LENGTH: u32 = 0x1000_0000;
+ const MEMORY_END: u32 = MEMORY_ORIGIN + MEMORY_LENGTH;
+
+ if !(MEMORY_ORIGIN..MEMORY_END).contains(&start_addr) {
+ return Err(TargetError::NonFatal);
+ }
+
+ let end_addr = std::cmp::min(start_addr + data.len() as u32, MEMORY_END);
+
+ for (addr, val) in (start_addr..end_addr).zip(data.iter_mut()) {
*val = self.mem.r8(addr)
}
- Ok(())
+ Ok((end_addr - start_addr) as usize)
}
fn write_addrs(&mut self, start_addr: u32, data: &[u8]) -> TargetResult<(), Self> {
@@ -379,10 +393,14 @@ impl target::ext::base::singlethread::SingleThreadRangeStepping for Emu {
mod custom_arch {
use core::num::NonZeroUsize;
-
- use gdbstub::arch::lldb::{Encoding, Format, Generic, Register, RegisterInfo};
- use gdbstub::arch::{Arch, RegId, Registers, SingleStepGdbBehavior};
-
+ use gdbstub::arch::lldb::Encoding;
+ use gdbstub::arch::lldb::Format;
+ use gdbstub::arch::lldb::Generic;
+ use gdbstub::arch::lldb::Register;
+ use gdbstub::arch::lldb::RegisterInfo;
+ use gdbstub::arch::Arch;
+ use gdbstub::arch::RegId;
+ use gdbstub::arch::Registers;
use gdbstub_arch::arm::reg::id::ArmCoreRegId;
use gdbstub_arch::arm::reg::ArmCoreRegs;
use gdbstub_arch::arm::ArmBreakpointKind;
@@ -590,13 +608,5 @@ mod custom_arch {
}
}
}
- // armv4t supports optional single stepping.
- //
- // notably, x86 is an example of an arch that does _not_ support
- // optional single stepping.
- #[inline(always)]
- fn single_step_gdb_behavior() -> SingleStepGdbBehavior {
- SingleStepGdbBehavior::Optional
- }
}
}
diff --git a/examples/armv4t/gdb/monitor_cmd.rs b/examples/armv4t/gdb/monitor_cmd.rs
index 4dbdffc..4e91b28 100644
--- a/examples/armv4t/gdb/monitor_cmd.rs
+++ b/examples/armv4t/gdb/monitor_cmd.rs
@@ -1,7 +1,7 @@
-use gdbstub::target;
-use gdbstub::target::ext::monitor_cmd::{outputln, ConsoleOutput};
-
use crate::gdb::Emu;
+use gdbstub::target;
+use gdbstub::target::ext::monitor_cmd::outputln;
+use gdbstub::target::ext::monitor_cmd::ConsoleOutput;
impl target::ext::monitor_cmd::MonitorCmd for Emu {
fn handle_monitor_cmd(
diff --git a/examples/armv4t/gdb/section_offsets.rs b/examples/armv4t/gdb/section_offsets.rs
index d04aab7..facebc3 100644
--- a/examples/armv4t/gdb/section_offsets.rs
+++ b/examples/armv4t/gdb/section_offsets.rs
@@ -1,8 +1,7 @@
+use crate::gdb::Emu;
use gdbstub::target;
use gdbstub::target::ext::section_offsets::Offsets;
-use crate::gdb::Emu;
-
// This implementation is for illustrative purposes only. If the offsets are
// guaranteed to be zero, this extension does not need to be implemented.
diff --git a/examples/armv4t/gdb/target_description_xml_override.rs b/examples/armv4t/gdb/target_description_xml_override.rs
index 2c5348c..681a9d5 100644
--- a/examples/armv4t/gdb/target_description_xml_override.rs
+++ b/examples/armv4t/gdb/target_description_xml_override.rs
@@ -1,10 +1,9 @@
+use super::copy_range_to_buf;
+use crate::emu::Emu;
use gdbstub::target;
use gdbstub::target::TargetError;
use gdbstub::target::TargetResult;
-use super::copy_range_to_buf;
-use crate::emu::Emu;
-
impl target::ext::target_description_xml_override::TargetDescriptionXmlOverride for Emu {
fn target_description_xml(
&self,
diff --git a/examples/armv4t/main.rs b/examples/armv4t/main.rs
index 96edaef..ab15f9b 100644
--- a/examples/armv4t/main.rs
+++ b/examples/armv4t/main.rs
@@ -2,16 +2,20 @@
//! `arm-none-eabi-cc -march=armv4t`. It's not modeled after any real-world
//! system.
-use std::net::{TcpListener, TcpStream};
-
-#[cfg(unix)]
-use std::os::unix::net::{UnixListener, UnixStream};
-
use gdbstub::common::Signal;
-use gdbstub::conn::{Connection, ConnectionExt};
+use gdbstub::conn::Connection;
+use gdbstub::conn::ConnectionExt;
+use gdbstub::stub::run_blocking;
+use gdbstub::stub::DisconnectReason;
+use gdbstub::stub::GdbStub;
use gdbstub::stub::SingleThreadStopReason;
-use gdbstub::stub::{run_blocking, DisconnectReason, GdbStub, GdbStubError};
use gdbstub::target::Target;
+use std::net::TcpListener;
+use std::net::TcpStream;
+#[cfg(unix)]
+use std::os::unix::net::UnixListener;
+#[cfg(unix)]
+use std::os::unix::net::UnixStream;
type DynResult<T> = Result<T, Box<dyn std::error::Error>>;
@@ -177,11 +181,18 @@ fn main() -> DynResult<()> {
}
DisconnectReason::Kill => println!("GDB sent a kill command!"),
},
- Err(GdbStubError::TargetError(e)) => {
- println!("target encountered a fatal error: {}", e)
- }
Err(e) => {
- println!("gdbstub encountered a fatal error: {}", e)
+ if e.is_target_error() {
+ println!(
+ "target encountered a fatal error: {}",
+ e.into_target_error().unwrap()
+ )
+ } else if e.is_connection_error() {
+ let (e, kind) = e.into_connection_error().unwrap();
+ println!("connection error: {:?} - {}", kind, e,)
+ } else {
+ println!("gdbstub encountered a fatal error: {}", e)
+ }
}
}
diff --git a/examples/armv4t_multicore/emu.rs b/examples/armv4t_multicore/emu.rs
index 1eed74c..1b9dac4 100644
--- a/examples/armv4t_multicore/emu.rs
+++ b/examples/armv4t_multicore/emu.rs
@@ -9,12 +9,15 @@
//! system that can be debugged, it would really merit a re-write, since it's
//! not a good example of "proper Rust coding practices"
-use std::collections::HashMap;
-
-use armv4t_emu::{reg, Cpu, ExampleMem, Memory, Mode};
-
-use crate::mem_sniffer::{AccessKind, MemSniffer};
+use crate::mem_sniffer::AccessKind;
+use crate::mem_sniffer::MemSniffer;
use crate::DynResult;
+use armv4t_emu::reg;
+use armv4t_emu::Cpu;
+use armv4t_emu::ExampleMem;
+use armv4t_emu::Memory;
+use armv4t_emu::Mode;
+use std::collections::HashMap;
const HLE_RETURN_ADDR: u32 = 0x12345678;
diff --git a/examples/armv4t_multicore/gdb.rs b/examples/armv4t_multicore/gdb.rs
index 3c8cd75..11ed1e3 100644
--- a/examples/armv4t_multicore/gdb.rs
+++ b/examples/armv4t_multicore/gdb.rs
@@ -1,12 +1,17 @@
-use armv4t_emu::{reg, Memory};
-
-use gdbstub::common::{Signal, Tid};
+use crate::emu::CpuId;
+use crate::emu::Emu;
+use crate::emu::ExecMode;
+use armv4t_emu::reg;
+use armv4t_emu::Memory;
+use gdbstub::common::Signal;
+use gdbstub::common::Tid;
use gdbstub::target;
-use gdbstub::target::ext::base::multithread::{MultiThreadBase, MultiThreadResume};
+use gdbstub::target::ext::base::multithread::MultiThreadBase;
+use gdbstub::target::ext::base::multithread::MultiThreadResume;
use gdbstub::target::ext::breakpoints::WatchKind;
-use gdbstub::target::{Target, TargetError, TargetResult};
-
-use crate::emu::{CpuId, Emu, ExecMode};
+use gdbstub::target::Target;
+use gdbstub::target::TargetError;
+use gdbstub::target::TargetResult;
pub fn cpuid_to_tid(id: CpuId) -> Tid {
match id {
@@ -92,11 +97,11 @@ impl MultiThreadBase for Emu {
start_addr: u32,
data: &mut [u8],
_tid: Tid, // same address space for each core
- ) -> TargetResult<(), Self> {
+ ) -> TargetResult<usize, Self> {
for (addr, val) in (start_addr..).zip(data.iter_mut()) {
*val = self.mem.r8(addr)
}
- Ok(())
+ Ok(data.len())
}
fn write_addrs(
diff --git a/examples/armv4t_multicore/main.rs b/examples/armv4t_multicore/main.rs
index 4f799a7..c24f795 100644
--- a/examples/armv4t_multicore/main.rs
+++ b/examples/armv4t_multicore/main.rs
@@ -3,15 +3,20 @@
//! `gdbstub`'s multi-process support. It's not modeled after any real-world
//! system.
-use std::net::{TcpListener, TcpStream};
-
-#[cfg(unix)]
-use std::os::unix::net::{UnixListener, UnixStream};
-
use gdbstub::common::Signal;
-use gdbstub::conn::{Connection, ConnectionExt};
-use gdbstub::stub::{run_blocking, DisconnectReason, GdbStub, GdbStubError, MultiThreadStopReason};
+use gdbstub::conn::Connection;
+use gdbstub::conn::ConnectionExt;
+use gdbstub::stub::run_blocking;
+use gdbstub::stub::DisconnectReason;
+use gdbstub::stub::GdbStub;
+use gdbstub::stub::MultiThreadStopReason;
use gdbstub::target::Target;
+use std::net::TcpListener;
+use std::net::TcpStream;
+#[cfg(unix)]
+use std::os::unix::net::UnixListener;
+#[cfg(unix)]
+use std::os::unix::net::UnixStream;
type DynResult<T> = Result<T, Box<dyn std::error::Error>>;
@@ -178,11 +183,18 @@ fn main() -> DynResult<()> {
}
DisconnectReason::Kill => println!("GDB sent a kill command!"),
},
- Err(GdbStubError::TargetError(e)) => {
- println!("target encountered a fatal error: {}", e)
- }
Err(e) => {
- println!("gdbstub encountered a fatal error: {}", e)
+ if e.is_target_error() {
+ println!(
+ "target encountered a fatal error: {}",
+ e.into_target_error().unwrap()
+ )
+ } else if e.is_connection_error() {
+ let (e, kind) = e.into_connection_error().unwrap();
+ println!("connection error: {:?} - {}", kind, e,)
+ } else {
+ println!("gdbstub encountered a fatal error: {}", e)
+ }
}
}
diff --git a/rustfmt.toml b/rustfmt.toml
index 606e292..6e14a7c 100644
--- a/rustfmt.toml
+++ b/rustfmt.toml
@@ -1 +1,2 @@
-wrap_comments = true \ No newline at end of file
+imports_granularity = "Item"
+wrap_comments = true
diff --git a/src/arch.rs b/src/arch.rs
index f13adb0..00fbba2 100644
--- a/src/arch.rs
+++ b/src/arch.rs
@@ -15,12 +15,13 @@
//! > Having community-created `Arch` implementations distributed in a separate
//! crate helps minimize any unnecessary "version churn" in `gdbstub` core.
+use crate::internal::BeBytes;
+use crate::internal::LeBytes;
use core::fmt::Debug;
use core::num::NonZeroUsize;
-
-use num_traits::{FromPrimitive, PrimInt, Unsigned};
-
-use crate::internal::{BeBytes, LeBytes};
+use num_traits::FromPrimitive;
+use num_traits::PrimInt;
+use num_traits::Unsigned;
/// Register identifier for target registers.
///
@@ -187,102 +188,6 @@ pub trait Arch {
let _ = reg_id;
None
}
-
- /// 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 a `s`
- /// 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.
- ///
- /// # 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`].
- fn single_step_gdb_behavior() -> SingleStepGdbBehavior;
-}
-
-/// Encodes how the mainline GDB client handles target support for single-step
-/// on a particular architecture.
-///
-/// See [Arch::single_step_gdb_behavior] for details.
-#[non_exhaustive]
-#[derive(Debug, Clone, Copy)]
-pub enum SingleStepGdbBehavior {
- /// GDB will use single-stepping if available, falling back to using
- /// a temporary breakpoint + continue if unsupported.
- ///
- /// e.g: ARM
- Optional,
- /// GDB will unconditionally send single-step packets, _requiring_ the
- /// target to handle these requests.
- ///
- /// e.g: x86/x64
- Required,
- /// GDB will never use single-stepping, regardless if it's supported by the
- /// stub. It will always use a temporary breakpoint + continue.
- ///
- /// e.g: MIPS
- Ignored,
- /// Unknown behavior - no one has tested this platform yet. If possible,
- /// please conduct a test + upstream your findings to `gdbstub_arch`.
- #[doc(hidden)]
- Unknown,
}
/// LLDB-specific types supporting [`Arch::lldb_register_info`] and
diff --git a/src/common/signal.rs b/src/common/signal.rs
index 652752a..4ee9273 100644
--- a/src/common/signal.rs
+++ b/src/common/signal.rs
@@ -1,516 +1,348 @@
/// Cross-platform signal numbers defined by the GDB Remote Serial Protocol.
///
/// Transcribed from <https://github.com/bminor/binutils-gdb/blob/master/include/gdb/signals.def>
-#[repr(u8)]
+#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Signal(pub u8);
+
#[allow(clippy::upper_case_acronyms)]
#[allow(non_camel_case_types)]
#[rustfmt::skip]
-#[non_exhaustive]
-pub enum Signal {
- #[doc = "Signal 0 (shouldn't be used)"] SIGZERO = 0,
- #[doc = "Hangup"] SIGHUP = 1,
- #[doc = "Interrupt"] SIGINT = 2,
- #[doc = "Quit"] SIGQUIT = 3,
- #[doc = "Illegal instruction"] SIGILL = 4,
- #[doc = "Trace/breakpoint trap"] SIGTRAP = 5,
- #[doc = "Aborted"] SIGABRT = 6,
- #[doc = "Emulation trap"] SIGEMT = 7,
- #[doc = "Arithmetic exception"] SIGFPE = 8,
- #[doc = "Killed"] SIGKILL = 9,
- #[doc = "Bus error"] SIGBUS = 10,
- #[doc = "Segmentation fault"] SIGSEGV = 11,
- #[doc = "Bad system call"] SIGSYS = 12,
- #[doc = "Broken pipe"] SIGPIPE = 13,
- #[doc = "Alarm clock"] SIGALRM = 14,
- #[doc = "Terminated"] SIGTERM = 15,
- #[doc = "Urgent I/O condition"] SIGURG = 16,
- #[doc = "Stopped (signal)"] SIGSTOP = 17,
- #[doc = "Stopped (user)"] SIGTSTP = 18,
- #[doc = "Continued"] SIGCONT = 19,
- #[doc = "Child status changed"] SIGCHLD = 20,
- #[doc = "Stopped (tty input)"] SIGTTIN = 21,
- #[doc = "Stopped (tty output)"] SIGTTOU = 22,
- #[doc = "I/O possible"] SIGIO = 23,
- #[doc = "CPU time limit exceeded"] SIGXCPU = 24,
- #[doc = "File size limit exceeded"] SIGXFSZ = 25,
- #[doc = "Virtual timer expired"] SIGVTALRM = 26,
- #[doc = "Profiling timer expired"] SIGPROF = 27,
- #[doc = "Window size changed"] SIGWINCH = 28,
- #[doc = "Resource lost"] SIGLOST = 29,
- #[doc = "User defined signal 1"] SIGUSR1 = 30,
- #[doc = "User defined signal 2"] SIGUSR2 = 31,
- #[doc = "Power fail/restart"] SIGPWR = 32,
+impl Signal {
+ #[doc = "Signal 0 (shouldn't be used)"] pub const SIGZERO: Self = Self(0);
+ #[doc = "Hangup"] pub const SIGHUP: Self = Self(1);
+ #[doc = "Interrupt"] pub const SIGINT: Self = Self(2);
+ #[doc = "Quit"] pub const SIGQUIT: Self = Self(3);
+ #[doc = "Illegal instruction"] pub const SIGILL: Self = Self(4);
+ #[doc = "Trace/breakpoint trap"] pub const SIGTRAP: Self = Self(5);
+ #[doc = "Aborted"] pub const SIGABRT: Self = Self(6);
+ #[doc = "Emulation trap"] pub const SIGEMT: Self = Self(7);
+ #[doc = "Arithmetic exception"] pub const SIGFPE: Self = Self(8);
+ #[doc = "Killed"] pub const SIGKILL: Self = Self(9);
+ #[doc = "Bus error"] pub const SIGBUS: Self = Self(10);
+ #[doc = "Segmentation fault"] pub const SIGSEGV: Self = Self(11);
+ #[doc = "Bad system call"] pub const SIGSYS: Self = Self(12);
+ #[doc = "Broken pipe"] pub const SIGPIPE: Self = Self(13);
+ #[doc = "Alarm clock"] pub const SIGALRM: Self = Self(14);
+ #[doc = "Terminated"] pub const SIGTERM: Self = Self(15);
+ #[doc = "Urgent I/O condition"] pub const SIGURG: Self = Self(16);
+ #[doc = "Stopped (signal)"] pub const SIGSTOP: Self = Self(17);
+ #[doc = "Stopped (user)"] pub const SIGTSTP: Self = Self(18);
+ #[doc = "Continued"] pub const SIGCONT: Self = Self(19);
+ #[doc = "Child status changed"] pub const SIGCHLD: Self = Self(20);
+ #[doc = "Stopped (tty input)"] pub const SIGTTIN: Self = Self(21);
+ #[doc = "Stopped (tty output)"] pub const SIGTTOU: Self = Self(22);
+ #[doc = "I/O possible"] pub const SIGIO: Self = Self(23);
+ #[doc = "CPU time limit exceeded"] pub const SIGXCPU: Self = Self(24);
+ #[doc = "File size limit exceeded"] pub const SIGXFSZ: Self = Self(25);
+ #[doc = "Virtual timer expired"] pub const SIGVTALRM: Self = Self(26);
+ #[doc = "Profiling timer expired"] pub const SIGPROF: Self = Self(27);
+ #[doc = "Window size changed"] pub const SIGWINCH: Self = Self(28);
+ #[doc = "Resource lost"] pub const SIGLOST: Self = Self(29);
+ #[doc = "User defined signal 1"] pub const SIGUSR1: Self = Self(30);
+ #[doc = "User defined signal 2"] pub const SIGUSR2: Self = Self(31);
+ #[doc = "Power fail/restart"] pub const SIGPWR: Self = Self(32);
/* Similar to SIGIO. Perhaps they should have the same number. */
- #[doc = "Pollable event occurred"] SIGPOLL = 33,
- #[doc = "SIGWIND"] SIGWIND = 34,
- #[doc = "SIGPHONE"] SIGPHONE = 35,
- #[doc = "Process's LWPs are blocked"] SIGWAITING = 36,
- #[doc = "Signal LWP"] SIGLWP = 37,
- #[doc = "Swap space dangerously low"] SIGDANGER = 38,
- #[doc = "Monitor mode granted"] SIGGRANT = 39,
- #[doc = "Need to relinquish monitor mode"] SIGRETRACT = 40,
- #[doc = "Monitor mode data available"] SIGMSG = 41,
- #[doc = "Sound completed"] SIGSOUND = 42,
- #[doc = "Secure attention"] SIGSAK = 43,
- #[doc = "SIGPRIO"] SIGPRIO = 44,
- #[doc = "Real-time event 33"] SIG33 = 45,
- #[doc = "Real-time event 34"] SIG34 = 46,
- #[doc = "Real-time event 35"] SIG35 = 47,
- #[doc = "Real-time event 36"] SIG36 = 48,
- #[doc = "Real-time event 37"] SIG37 = 49,
- #[doc = "Real-time event 38"] SIG38 = 50,
- #[doc = "Real-time event 39"] SIG39 = 51,
- #[doc = "Real-time event 40"] SIG40 = 52,
- #[doc = "Real-time event 41"] SIG41 = 53,
- #[doc = "Real-time event 42"] SIG42 = 54,
- #[doc = "Real-time event 43"] SIG43 = 55,
- #[doc = "Real-time event 44"] SIG44 = 56,
- #[doc = "Real-time event 45"] SIG45 = 57,
- #[doc = "Real-time event 46"] SIG46 = 58,
- #[doc = "Real-time event 47"] SIG47 = 59,
- #[doc = "Real-time event 48"] SIG48 = 60,
- #[doc = "Real-time event 49"] SIG49 = 61,
- #[doc = "Real-time event 50"] SIG50 = 62,
- #[doc = "Real-time event 51"] SIG51 = 63,
- #[doc = "Real-time event 52"] SIG52 = 64,
- #[doc = "Real-time event 53"] SIG53 = 65,
- #[doc = "Real-time event 54"] SIG54 = 66,
- #[doc = "Real-time event 55"] SIG55 = 67,
- #[doc = "Real-time event 56"] SIG56 = 68,
- #[doc = "Real-time event 57"] SIG57 = 69,
- #[doc = "Real-time event 58"] SIG58 = 70,
- #[doc = "Real-time event 59"] SIG59 = 71,
- #[doc = "Real-time event 60"] SIG60 = 72,
- #[doc = "Real-time event 61"] SIG61 = 73,
- #[doc = "Real-time event 62"] SIG62 = 74,
- #[doc = "Real-time event 63"] SIG63 = 75,
+ #[doc = "Pollable event occurred"] pub const SIGPOLL: Self = Self(33);
+ #[doc = "SIGWIND"] pub const SIGWIND: Self = Self(34);
+ #[doc = "SIGPHONE"] pub const SIGPHONE: Self = Self(35);
+ #[doc = "Process's LWPs are blocked"] pub const SIGWAITING: Self = Self(36);
+ #[doc = "Signal LWP"] pub const SIGLWP: Self = Self(37);
+ #[doc = "Swap space dangerously low"] pub const SIGDANGER: Self = Self(38);
+ #[doc = "Monitor mode granted"] pub const SIGGRANT: Self = Self(39);
+ #[doc = "Need to relinquish monitor mode"] pub const SIGRETRACT: Self = Self(40);
+ #[doc = "Monitor mode data available"] pub const SIGMSG: Self = Self(41);
+ #[doc = "Sound completed"] pub const SIGSOUND: Self = Self(42);
+ #[doc = "Secure attention"] pub const SIGSAK: Self = Self(43);
+ #[doc = "SIGPRIO"] pub const SIGPRIO: Self = Self(44);
+ #[doc = "Real-time event 33"] pub const SIG33: Self = Self(45);
+ #[doc = "Real-time event 34"] pub const SIG34: Self = Self(46);
+ #[doc = "Real-time event 35"] pub const SIG35: Self = Self(47);
+ #[doc = "Real-time event 36"] pub const SIG36: Self = Self(48);
+ #[doc = "Real-time event 37"] pub const SIG37: Self = Self(49);
+ #[doc = "Real-time event 38"] pub const SIG38: Self = Self(50);
+ #[doc = "Real-time event 39"] pub const SIG39: Self = Self(51);
+ #[doc = "Real-time event 40"] pub const SIG40: Self = Self(52);
+ #[doc = "Real-time event 41"] pub const SIG41: Self = Self(53);
+ #[doc = "Real-time event 42"] pub const SIG42: Self = Self(54);
+ #[doc = "Real-time event 43"] pub const SIG43: Self = Self(55);
+ #[doc = "Real-time event 44"] pub const SIG44: Self = Self(56);
+ #[doc = "Real-time event 45"] pub const SIG45: Self = Self(57);
+ #[doc = "Real-time event 46"] pub const SIG46: Self = Self(58);
+ #[doc = "Real-time event 47"] pub const SIG47: Self = Self(59);
+ #[doc = "Real-time event 48"] pub const SIG48: Self = Self(60);
+ #[doc = "Real-time event 49"] pub const SIG49: Self = Self(61);
+ #[doc = "Real-time event 50"] pub const SIG50: Self = Self(62);
+ #[doc = "Real-time event 51"] pub const SIG51: Self = Self(63);
+ #[doc = "Real-time event 52"] pub const SIG52: Self = Self(64);
+ #[doc = "Real-time event 53"] pub const SIG53: Self = Self(65);
+ #[doc = "Real-time event 54"] pub const SIG54: Self = Self(66);
+ #[doc = "Real-time event 55"] pub const SIG55: Self = Self(67);
+ #[doc = "Real-time event 56"] pub const SIG56: Self = Self(68);
+ #[doc = "Real-time event 57"] pub const SIG57: Self = Self(69);
+ #[doc = "Real-time event 58"] pub const SIG58: Self = Self(70);
+ #[doc = "Real-time event 59"] pub const SIG59: Self = Self(71);
+ #[doc = "Real-time event 60"] pub const SIG60: Self = Self(72);
+ #[doc = "Real-time event 61"] pub const SIG61: Self = Self(73);
+ #[doc = "Real-time event 62"] pub const SIG62: Self = Self(74);
+ #[doc = "Real-time event 63"] pub const SIG63: Self = Self(75);
/* Used internally by Solaris threads. See signal(5) on Solaris. */
- #[doc = "LWP internal signal"] SIGCANCEL = 76,
+ #[doc = "LWP internal signal"] pub const SIGCANCEL: Self = Self(76);
/* Yes, this pains me, too. But LynxOS didn't have SIG32, and now
GNU/Linux does, and we can't disturb the numbering, since it's
part of the remote protocol. Note that in some GDB's
GDB_SIGNAL_REALTIME_32 is number 76. */
- #[doc = "Real-time event 32"] SIG32 = 77,
+ #[doc = "Real-time event 32"] pub const SIG32: Self = Self(77);
/* Yet another pain, IRIX 6 has SIG64. */
- #[doc = "Real-time event 64"] SIG64 = 78,
+ #[doc = "Real-time event 64"] pub const SIG64: Self = Self(78);
/* Yet another pain, GNU/Linux MIPS might go up to 128. */
- #[doc = "Real-time event 65"] SIG65 = 79,
- #[doc = "Real-time event 66"] SIG66 = 80,
- #[doc = "Real-time event 67"] SIG67 = 81,
- #[doc = "Real-time event 68"] SIG68 = 82,
- #[doc = "Real-time event 69"] SIG69 = 83,
- #[doc = "Real-time event 70"] SIG70 = 84,
- #[doc = "Real-time event 71"] SIG71 = 85,
- #[doc = "Real-time event 72"] SIG72 = 86,
- #[doc = "Real-time event 73"] SIG73 = 87,
- #[doc = "Real-time event 74"] SIG74 = 88,
- #[doc = "Real-time event 75"] SIG75 = 89,
- #[doc = "Real-time event 76"] SIG76 = 90,
- #[doc = "Real-time event 77"] SIG77 = 91,
- #[doc = "Real-time event 78"] SIG78 = 92,
- #[doc = "Real-time event 79"] SIG79 = 93,
- #[doc = "Real-time event 80"] SIG80 = 94,
- #[doc = "Real-time event 81"] SIG81 = 95,
- #[doc = "Real-time event 82"] SIG82 = 96,
- #[doc = "Real-time event 83"] SIG83 = 97,
- #[doc = "Real-time event 84"] SIG84 = 98,
- #[doc = "Real-time event 85"] SIG85 = 99,
- #[doc = "Real-time event 86"] SIG86 = 100,
- #[doc = "Real-time event 87"] SIG87 = 101,
- #[doc = "Real-time event 88"] SIG88 = 102,
- #[doc = "Real-time event 89"] SIG89 = 103,
- #[doc = "Real-time event 90"] SIG90 = 104,
- #[doc = "Real-time event 91"] SIG91 = 105,
- #[doc = "Real-time event 92"] SIG92 = 106,
- #[doc = "Real-time event 93"] SIG93 = 107,
- #[doc = "Real-time event 94"] SIG94 = 108,
- #[doc = "Real-time event 95"] SIG95 = 109,
- #[doc = "Real-time event 96"] SIG96 = 110,
- #[doc = "Real-time event 97"] SIG97 = 111,
- #[doc = "Real-time event 98"] SIG98 = 112,
- #[doc = "Real-time event 99"] SIG99 = 113,
- #[doc = "Real-time event 100"] SIG100 = 114,
- #[doc = "Real-time event 101"] SIG101 = 115,
- #[doc = "Real-time event 102"] SIG102 = 116,
- #[doc = "Real-time event 103"] SIG103 = 117,
- #[doc = "Real-time event 104"] SIG104 = 118,
- #[doc = "Real-time event 105"] SIG105 = 119,
- #[doc = "Real-time event 106"] SIG106 = 120,
- #[doc = "Real-time event 107"] SIG107 = 121,
- #[doc = "Real-time event 108"] SIG108 = 122,
- #[doc = "Real-time event 109"] SIG109 = 123,
- #[doc = "Real-time event 110"] SIG110 = 124,
- #[doc = "Real-time event 111"] SIG111 = 125,
- #[doc = "Real-time event 112"] SIG112 = 126,
- #[doc = "Real-time event 113"] SIG113 = 127,
- #[doc = "Real-time event 114"] SIG114 = 128,
- #[doc = "Real-time event 115"] SIG115 = 129,
- #[doc = "Real-time event 116"] SIG116 = 130,
- #[doc = "Real-time event 117"] SIG117 = 131,
- #[doc = "Real-time event 118"] SIG118 = 132,
- #[doc = "Real-time event 119"] SIG119 = 133,
- #[doc = "Real-time event 120"] SIG120 = 134,
- #[doc = "Real-time event 121"] SIG121 = 135,
- #[doc = "Real-time event 122"] SIG122 = 136,
- #[doc = "Real-time event 123"] SIG123 = 137,
- #[doc = "Real-time event 124"] SIG124 = 138,
- #[doc = "Real-time event 125"] SIG125 = 139,
- #[doc = "Real-time event 126"] SIG126 = 140,
- #[doc = "Real-time event 127"] SIG127 = 141,
+ #[doc = "Real-time event 65"] pub const SIG65: Self = Self(79);
+ #[doc = "Real-time event 66"] pub const SIG66: Self = Self(80);
+ #[doc = "Real-time event 67"] pub const SIG67: Self = Self(81);
+ #[doc = "Real-time event 68"] pub const SIG68: Self = Self(82);
+ #[doc = "Real-time event 69"] pub const SIG69: Self = Self(83);
+ #[doc = "Real-time event 70"] pub const SIG70: Self = Self(84);
+ #[doc = "Real-time event 71"] pub const SIG71: Self = Self(85);
+ #[doc = "Real-time event 72"] pub const SIG72: Self = Self(86);
+ #[doc = "Real-time event 73"] pub const SIG73: Self = Self(87);
+ #[doc = "Real-time event 74"] pub const SIG74: Self = Self(88);
+ #[doc = "Real-time event 75"] pub const SIG75: Self = Self(89);
+ #[doc = "Real-time event 76"] pub const SIG76: Self = Self(90);
+ #[doc = "Real-time event 77"] pub const SIG77: Self = Self(91);
+ #[doc = "Real-time event 78"] pub const SIG78: Self = Self(92);
+ #[doc = "Real-time event 79"] pub const SIG79: Self = Self(93);
+ #[doc = "Real-time event 80"] pub const SIG80: Self = Self(94);
+ #[doc = "Real-time event 81"] pub const SIG81: Self = Self(95);
+ #[doc = "Real-time event 82"] pub const SIG82: Self = Self(96);
+ #[doc = "Real-time event 83"] pub const SIG83: Self = Self(97);
+ #[doc = "Real-time event 84"] pub const SIG84: Self = Self(98);
+ #[doc = "Real-time event 85"] pub const SIG85: Self = Self(99);
+ #[doc = "Real-time event 86"] pub const SIG86: Self = Self(100);
+ #[doc = "Real-time event 87"] pub const SIG87: Self = Self(101);
+ #[doc = "Real-time event 88"] pub const SIG88: Self = Self(102);
+ #[doc = "Real-time event 89"] pub const SIG89: Self = Self(103);
+ #[doc = "Real-time event 90"] pub const SIG90: Self = Self(104);
+ #[doc = "Real-time event 91"] pub const SIG91: Self = Self(105);
+ #[doc = "Real-time event 92"] pub const SIG92: Self = Self(106);
+ #[doc = "Real-time event 93"] pub const SIG93: Self = Self(107);
+ #[doc = "Real-time event 94"] pub const SIG94: Self = Self(108);
+ #[doc = "Real-time event 95"] pub const SIG95: Self = Self(109);
+ #[doc = "Real-time event 96"] pub const SIG96: Self = Self(110);
+ #[doc = "Real-time event 97"] pub const SIG97: Self = Self(111);
+ #[doc = "Real-time event 98"] pub const SIG98: Self = Self(112);
+ #[doc = "Real-time event 99"] pub const SIG99: Self = Self(113);
+ #[doc = "Real-time event 100"] pub const SIG100: Self = Self(114);
+ #[doc = "Real-time event 101"] pub const SIG101: Self = Self(115);
+ #[doc = "Real-time event 102"] pub const SIG102: Self = Self(116);
+ #[doc = "Real-time event 103"] pub const SIG103: Self = Self(117);
+ #[doc = "Real-time event 104"] pub const SIG104: Self = Self(118);
+ #[doc = "Real-time event 105"] pub const SIG105: Self = Self(119);
+ #[doc = "Real-time event 106"] pub const SIG106: Self = Self(120);
+ #[doc = "Real-time event 107"] pub const SIG107: Self = Self(121);
+ #[doc = "Real-time event 108"] pub const SIG108: Self = Self(122);
+ #[doc = "Real-time event 109"] pub const SIG109: Self = Self(123);
+ #[doc = "Real-time event 110"] pub const SIG110: Self = Self(124);
+ #[doc = "Real-time event 111"] pub const SIG111: Self = Self(125);
+ #[doc = "Real-time event 112"] pub const SIG112: Self = Self(126);
+ #[doc = "Real-time event 113"] pub const SIG113: Self = Self(127);
+ #[doc = "Real-time event 114"] pub const SIG114: Self = Self(128);
+ #[doc = "Real-time event 115"] pub const SIG115: Self = Self(129);
+ #[doc = "Real-time event 116"] pub const SIG116: Self = Self(130);
+ #[doc = "Real-time event 117"] pub const SIG117: Self = Self(131);
+ #[doc = "Real-time event 118"] pub const SIG118: Self = Self(132);
+ #[doc = "Real-time event 119"] pub const SIG119: Self = Self(133);
+ #[doc = "Real-time event 120"] pub const SIG120: Self = Self(134);
+ #[doc = "Real-time event 121"] pub const SIG121: Self = Self(135);
+ #[doc = "Real-time event 122"] pub const SIG122: Self = Self(136);
+ #[doc = "Real-time event 123"] pub const SIG123: Self = Self(137);
+ #[doc = "Real-time event 124"] pub const SIG124: Self = Self(138);
+ #[doc = "Real-time event 125"] pub const SIG125: Self = Self(139);
+ #[doc = "Real-time event 126"] pub const SIG126: Self = Self(140);
+ #[doc = "Real-time event 127"] pub const SIG127: Self = Self(141);
- #[doc = "Information request"] SIGINFO = 142,
+ #[doc = "Information request"] pub const SIGINFO: Self = Self(142);
/* Some signal we don't know about. */
- #[doc = "Unknown signal"] UNKNOWN = 143,
+ #[doc = "Unknown signal"] pub const UNKNOWN: Self = Self(143);
/* Use whatever signal we use when one is not specifically specified
(for passing to proceed and so on). */
- #[doc = "Internal error: printing GDB_SIGNAL_DEFAULT"] INTERNAL_DEFAULT = 144,
+ #[doc = "Internal error: printing GDB_SIGNAL_DEFAULT"]
+ pub const INTERNAL_DEFAULT: Self = Self(144);
/* Mach exceptions. In versions of GDB before 5.2, these were just before
GDB_SIGNAL_INFO if you were compiling on a Mach host (and missing
otherwise). */
- #[doc = "Could not access memory"] EXC_BAD_ACCESS = 145,
- #[doc = "Illegal instruction/operand"] EXC_BAD_INSTRUCTION = 146,
- #[doc = "Arithmetic exception"] EXC_ARITHMETIC = 147,
- #[doc = "Emulation instruction"] EXC_EMULATION = 148,
- #[doc = "Software generated exception"] EXC_SOFTWARE = 149,
- #[doc = "Breakpoint"] EXC_BREAKPOINT = 150,
+ #[doc = "Could not access memory"] pub const EXC_BAD_ACCESS: Self = Self(145);
+ #[doc = "Illegal instruction/operand"] pub const EXC_BAD_INSTRUCTION: Self = Self(146);
+ #[doc = "Arithmetic exception"] pub const EXC_ARITHMETIC: Self = Self(147);
+ #[doc = "Emulation instruction"] pub const EXC_EMULATION: Self = Self(148);
+ #[doc = "Software generated exception"] pub const EXC_SOFTWARE: Self = Self(149);
+ #[doc = "Breakpoint"] pub const EXC_BREAKPOINT: Self = Self(150);
- #[doc = "librt internal signal"] SIGLIBRT = 151,
+ #[doc = "librt internal signal"] pub const SIGLIBRT: Self = Self(151);
}
impl core::fmt::Display for Signal {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
#[rustfmt::skip]
- let s = match self {
- Signal::SIGZERO => "SIGZERO - Signal 0",
- Signal::SIGHUP => "SIGHUP - Hangup",
- Signal::SIGINT => "SIGINT - Interrupt",
- Signal::SIGQUIT => "SIGQUIT - Quit",
- Signal::SIGILL => "SIGILL - Illegal instruction",
- Signal::SIGTRAP => "SIGTRAP - Trace/breakpoint trap",
- Signal::SIGABRT => "SIGABRT - Aborted",
- Signal::SIGEMT => "SIGEMT - Emulation trap",
- Signal::SIGFPE => "SIGFPE - Arithmetic exception",
- Signal::SIGKILL => "SIGKILL - Killed",
- Signal::SIGBUS => "SIGBUS - Bus error",
- Signal::SIGSEGV => "SIGSEGV - Segmentation fault",
- Signal::SIGSYS => "SIGSYS - Bad system call",
- Signal::SIGPIPE => "SIGPIPE - Broken pipe",
- Signal::SIGALRM => "SIGALRM - Alarm clock",
- Signal::SIGTERM => "SIGTERM - Terminated",
- Signal::SIGURG => "SIGURG - Urgent I/O condition",
- Signal::SIGSTOP => "SIGSTOP - Stopped (signal)",
- Signal::SIGTSTP => "SIGTSTP - Stopped (user)",
- Signal::SIGCONT => "SIGCONT - Continued",
- Signal::SIGCHLD => "SIGCHLD - Child status changed",
- Signal::SIGTTIN => "SIGTTIN - Stopped (tty input)",
- Signal::SIGTTOU => "SIGTTOU - Stopped (tty output)",
- Signal::SIGIO => "SIGIO - I/O possible",
- Signal::SIGXCPU => "SIGXCPU - CPU time limit exceeded",
- Signal::SIGXFSZ => "SIGXFSZ - File size limit exceeded",
- Signal::SIGVTALRM => "SIGVTALRM - Virtual timer expired",
- Signal::SIGPROF => "SIGPROF - Profiling timer expired",
- Signal::SIGWINCH => "SIGWINCH - Window size changed",
- Signal::SIGLOST => "SIGLOST - Resource lost",
- Signal::SIGUSR1 => "SIGUSR1 - User defined signal 1",
- Signal::SIGUSR2 => "SIGUSR2 - User defined signal 2",
- Signal::SIGPWR => "SIGPWR - Power fail/restart",
- Signal::SIGPOLL => "SIGPOLL - Pollable event occurred",
- Signal::SIGWIND => "SIGWIND - SIGWIND",
- Signal::SIGPHONE => "SIGPHONE - SIGPHONE",
- Signal::SIGWAITING => "SIGWAITING - Process's LWPs are blocked",
- Signal::SIGLWP => "SIGLWP - Signal LWP",
- Signal::SIGDANGER => "SIGDANGER - Swap space dangerously low",
- Signal::SIGGRANT => "SIGGRANT - Monitor mode granted",
- Signal::SIGRETRACT => "SIGRETRACT - Need to relinquish monitor mode",
- Signal::SIGMSG => "SIGMSG - Monitor mode data available",
- Signal::SIGSOUND => "SIGSOUND - Sound completed",
- Signal::SIGSAK => "SIGSAK - Secure attention",
- Signal::SIGPRIO => "SIGPRIO - SIGPRIO",
- Signal::SIG33 => "SIG33 - Real-time event 33",
- Signal::SIG34 => "SIG34 - Real-time event 34",
- Signal::SIG35 => "SIG35 - Real-time event 35",
- Signal::SIG36 => "SIG36 - Real-time event 36",
- Signal::SIG37 => "SIG37 - Real-time event 37",
- Signal::SIG38 => "SIG38 - Real-time event 38",
- Signal::SIG39 => "SIG39 - Real-time event 39",
- Signal::SIG40 => "SIG40 - Real-time event 40",
- Signal::SIG41 => "SIG41 - Real-time event 41",
- Signal::SIG42 => "SIG42 - Real-time event 42",
- Signal::SIG43 => "SIG43 - Real-time event 43",
- Signal::SIG44 => "SIG44 - Real-time event 44",
- Signal::SIG45 => "SIG45 - Real-time event 45",
- Signal::SIG46 => "SIG46 - Real-time event 46",
- Signal::SIG47 => "SIG47 - Real-time event 47",
- Signal::SIG48 => "SIG48 - Real-time event 48",
- Signal::SIG49 => "SIG49 - Real-time event 49",
- Signal::SIG50 => "SIG50 - Real-time event 50",
- Signal::SIG51 => "SIG51 - Real-time event 51",
- Signal::SIG52 => "SIG52 - Real-time event 52",
- Signal::SIG53 => "SIG53 - Real-time event 53",
- Signal::SIG54 => "SIG54 - Real-time event 54",
- Signal::SIG55 => "SIG55 - Real-time event 55",
- Signal::SIG56 => "SIG56 - Real-time event 56",
- Signal::SIG57 => "SIG57 - Real-time event 57",
- Signal::SIG58 => "SIG58 - Real-time event 58",
- Signal::SIG59 => "SIG59 - Real-time event 59",
- Signal::SIG60 => "SIG60 - Real-time event 60",
- Signal::SIG61 => "SIG61 - Real-time event 61",
- Signal::SIG62 => "SIG62 - Real-time event 62",
- Signal::SIG63 => "SIG63 - Real-time event 63",
- Signal::SIGCANCEL => "SIGCANCEL - LWP internal signal",
- Signal::SIG32 => "SIG32 - Real-time event 32",
- Signal::SIG64 => "SIG64 - Real-time event 64",
- Signal::SIG65 => "SIG65 - Real-time event 65",
- Signal::SIG66 => "SIG66 - Real-time event 66",
- Signal::SIG67 => "SIG67 - Real-time event 67",
- Signal::SIG68 => "SIG68 - Real-time event 68",
- Signal::SIG69 => "SIG69 - Real-time event 69",
- Signal::SIG70 => "SIG70 - Real-time event 70",
- Signal::SIG71 => "SIG71 - Real-time event 71",
- Signal::SIG72 => "SIG72 - Real-time event 72",
- Signal::SIG73 => "SIG73 - Real-time event 73",
- Signal::SIG74 => "SIG74 - Real-time event 74",
- Signal::SIG75 => "SIG75 - Real-time event 75",
- Signal::SIG76 => "SIG76 - Real-time event 76",
- Signal::SIG77 => "SIG77 - Real-time event 77",
- Signal::SIG78 => "SIG78 - Real-time event 78",
- Signal::SIG79 => "SIG79 - Real-time event 79",
- Signal::SIG80 => "SIG80 - Real-time event 80",
- Signal::SIG81 => "SIG81 - Real-time event 81",
- Signal::SIG82 => "SIG82 - Real-time event 82",
- Signal::SIG83 => "SIG83 - Real-time event 83",
- Signal::SIG84 => "SIG84 - Real-time event 84",
- Signal::SIG85 => "SIG85 - Real-time event 85",
- Signal::SIG86 => "SIG86 - Real-time event 86",
- Signal::SIG87 => "SIG87 - Real-time event 87",
- Signal::SIG88 => "SIG88 - Real-time event 88",
- Signal::SIG89 => "SIG89 - Real-time event 89",
- Signal::SIG90 => "SIG90 - Real-time event 90",
- Signal::SIG91 => "SIG91 - Real-time event 91",
- Signal::SIG92 => "SIG92 - Real-time event 92",
- Signal::SIG93 => "SIG93 - Real-time event 93",
- Signal::SIG94 => "SIG94 - Real-time event 94",
- Signal::SIG95 => "SIG95 - Real-time event 95",
- Signal::SIG96 => "SIG96 - Real-time event 96",
- Signal::SIG97 => "SIG97 - Real-time event 97",
- Signal::SIG98 => "SIG98 - Real-time event 98",
- Signal::SIG99 => "SIG99 - Real-time event 99",
- Signal::SIG100 => "SIG100 - Real-time event 100",
- Signal::SIG101 => "SIG101 - Real-time event 101",
- Signal::SIG102 => "SIG102 - Real-time event 102",
- Signal::SIG103 => "SIG103 - Real-time event 103",
- Signal::SIG104 => "SIG104 - Real-time event 104",
- Signal::SIG105 => "SIG105 - Real-time event 105",
- Signal::SIG106 => "SIG106 - Real-time event 106",
- Signal::SIG107 => "SIG107 - Real-time event 107",
- Signal::SIG108 => "SIG108 - Real-time event 108",
- Signal::SIG109 => "SIG109 - Real-time event 109",
- Signal::SIG110 => "SIG110 - Real-time event 110",
- Signal::SIG111 => "SIG111 - Real-time event 111",
- Signal::SIG112 => "SIG112 - Real-time event 112",
- Signal::SIG113 => "SIG113 - Real-time event 113",
- Signal::SIG114 => "SIG114 - Real-time event 114",
- Signal::SIG115 => "SIG115 - Real-time event 115",
- Signal::SIG116 => "SIG116 - Real-time event 116",
- Signal::SIG117 => "SIG117 - Real-time event 117",
- Signal::SIG118 => "SIG118 - Real-time event 118",
- Signal::SIG119 => "SIG119 - Real-time event 119",
- Signal::SIG120 => "SIG120 - Real-time event 120",
- Signal::SIG121 => "SIG121 - Real-time event 121",
- Signal::SIG122 => "SIG122 - Real-time event 122",
- Signal::SIG123 => "SIG123 - Real-time event 123",
- Signal::SIG124 => "SIG124 - Real-time event 124",
- Signal::SIG125 => "SIG125 - Real-time event 125",
- Signal::SIG126 => "SIG126 - Real-time event 126",
- Signal::SIG127 => "SIG127 - Real-time event 127",
- Signal::SIGINFO => "SIGINFO - Information request",
- Signal::UNKNOWN => "UNKNOWN - Unknown signal",
- Signal::INTERNAL_DEFAULT => "INTERNAL_DEFAULT - Internal error: printing GDB_SIGNAL_DEFAULT",
- Signal::EXC_BAD_ACCESS => "EXC_BAD_ACCESS - Could not access memory",
+ let s = match *self {
+ Signal::SIGZERO => "SIGZERO - Signal 0",
+ Signal::SIGHUP => "SIGHUP - Hangup",
+ Signal::SIGINT => "SIGINT - Interrupt",
+ Signal::SIGQUIT => "SIGQUIT - Quit",
+ Signal::SIGILL => "SIGILL - Illegal instruction",
+ Signal::SIGTRAP => "SIGTRAP - Trace/breakpoint trap",
+ Signal::SIGABRT => "SIGABRT - Aborted",
+ Signal::SIGEMT => "SIGEMT - Emulation trap",
+ Signal::SIGFPE => "SIGFPE - Arithmetic exception",
+ Signal::SIGKILL => "SIGKILL - Killed",
+ Signal::SIGBUS => "SIGBUS - Bus error",
+ Signal::SIGSEGV => "SIGSEGV - Segmentation fault",
+ Signal::SIGSYS => "SIGSYS - Bad system call",
+ Signal::SIGPIPE => "SIGPIPE - Broken pipe",
+ Signal::SIGALRM => "SIGALRM - Alarm clock",
+ Signal::SIGTERM => "SIGTERM - Terminated",
+ Signal::SIGURG => "SIGURG - Urgent I/O condition",
+ Signal::SIGSTOP => "SIGSTOP - Stopped (signal)",
+ Signal::SIGTSTP => "SIGTSTP - Stopped (user)",
+ Signal::SIGCONT => "SIGCONT - Continued",
+ Signal::SIGCHLD => "SIGCHLD - Child status changed",
+ Signal::SIGTTIN => "SIGTTIN - Stopped (tty input)",
+ Signal::SIGTTOU => "SIGTTOU - Stopped (tty output)",
+ Signal::SIGIO => "SIGIO - I/O possible",
+ Signal::SIGXCPU => "SIGXCPU - CPU time limit exceeded",
+ Signal::SIGXFSZ => "SIGXFSZ - File size limit exceeded",
+ Signal::SIGVTALRM => "SIGVTALRM - Virtual timer expired",
+ Signal::SIGPROF => "SIGPROF - Profiling timer expired",
+ Signal::SIGWINCH => "SIGWINCH - Window size changed",
+ Signal::SIGLOST => "SIGLOST - Resource lost",
+ Signal::SIGUSR1 => "SIGUSR1 - User defined signal 1",
+ Signal::SIGUSR2 => "SIGUSR2 - User defined signal 2",
+ Signal::SIGPWR => "SIGPWR - Power fail/restart",
+ Signal::SIGPOLL => "SIGPOLL - Pollable event occurred",
+ Signal::SIGWIND => "SIGWIND - SIGWIND",
+ Signal::SIGPHONE => "SIGPHONE - SIGPHONE",
+ Signal::SIGWAITING => "SIGWAITING - Process's LWPs are blocked",
+ Signal::SIGLWP => "SIGLWP - Signal LWP",
+ Signal::SIGDANGER => "SIGDANGER - Swap space dangerously low",
+ Signal::SIGGRANT => "SIGGRANT - Monitor mode granted",
+ Signal::SIGRETRACT => "SIGRETRACT - Need to relinquish monitor mode",
+ Signal::SIGMSG => "SIGMSG - Monitor mode data available",
+ Signal::SIGSOUND => "SIGSOUND - Sound completed",
+ Signal::SIGSAK => "SIGSAK - Secure attention",
+ Signal::SIGPRIO => "SIGPRIO - SIGPRIO",
+ Signal::SIG33 => "SIG33 - Real-time event 33",
+ Signal::SIG34 => "SIG34 - Real-time event 34",
+ Signal::SIG35 => "SIG35 - Real-time event 35",
+ Signal::SIG36 => "SIG36 - Real-time event 36",
+ Signal::SIG37 => "SIG37 - Real-time event 37",
+ Signal::SIG38 => "SIG38 - Real-time event 38",
+ Signal::SIG39 => "SIG39 - Real-time event 39",
+ Signal::SIG40 => "SIG40 - Real-time event 40",
+ Signal::SIG41 => "SIG41 - Real-time event 41",
+ Signal::SIG42 => "SIG42 - Real-time event 42",
+ Signal::SIG43 => "SIG43 - Real-time event 43",
+ Signal::SIG44 => "SIG44 - Real-time event 44",
+ Signal::SIG45 => "SIG45 - Real-time event 45",
+ Signal::SIG46 => "SIG46 - Real-time event 46",
+ Signal::SIG47 => "SIG47 - Real-time event 47",
+ Signal::SIG48 => "SIG48 - Real-time event 48",
+ Signal::SIG49 => "SIG49 - Real-time event 49",
+ Signal::SIG50 => "SIG50 - Real-time event 50",
+ Signal::SIG51 => "SIG51 - Real-time event 51",
+ Signal::SIG52 => "SIG52 - Real-time event 52",
+ Signal::SIG53 => "SIG53 - Real-time event 53",
+ Signal::SIG54 => "SIG54 - Real-time event 54",
+ Signal::SIG55 => "SIG55 - Real-time event 55",
+ Signal::SIG56 => "SIG56 - Real-time event 56",
+ Signal::SIG57 => "SIG57 - Real-time event 57",
+ Signal::SIG58 => "SIG58 - Real-time event 58",
+ Signal::SIG59 => "SIG59 - Real-time event 59",
+ Signal::SIG60 => "SIG60 - Real-time event 60",
+ Signal::SIG61 => "SIG61 - Real-time event 61",
+ Signal::SIG62 => "SIG62 - Real-time event 62",
+ Signal::SIG63 => "SIG63 - Real-time event 63",
+ Signal::SIGCANCEL => "SIGCANCEL - LWP internal signal",
+ Signal::SIG32 => "SIG32 - Real-time event 32",
+ Signal::SIG64 => "SIG64 - Real-time event 64",
+ Signal::SIG65 => "SIG65 - Real-time event 65",
+ Signal::SIG66 => "SIG66 - Real-time event 66",
+ Signal::SIG67 => "SIG67 - Real-time event 67",
+ Signal::SIG68 => "SIG68 - Real-time event 68",
+ Signal::SIG69 => "SIG69 - Real-time event 69",
+ Signal::SIG70 => "SIG70 - Real-time event 70",
+ Signal::SIG71 => "SIG71 - Real-time event 71",
+ Signal::SIG72 => "SIG72 - Real-time event 72",
+ Signal::SIG73 => "SIG73 - Real-time event 73",
+ Signal::SIG74 => "SIG74 - Real-time event 74",
+ Signal::SIG75 => "SIG75 - Real-time event 75",
+ Signal::SIG76 => "SIG76 - Real-time event 76",
+ Signal::SIG77 => "SIG77 - Real-time event 77",
+ Signal::SIG78 => "SIG78 - Real-time event 78",
+ Signal::SIG79 => "SIG79 - Real-time event 79",
+ Signal::SIG80 => "SIG80 - Real-time event 80",
+ Signal::SIG81 => "SIG81 - Real-time event 81",
+ Signal::SIG82 => "SIG82 - Real-time event 82",
+ Signal::SIG83 => "SIG83 - Real-time event 83",
+ Signal::SIG84 => "SIG84 - Real-time event 84",
+ Signal::SIG85 => "SIG85 - Real-time event 85",
+ Signal::SIG86 => "SIG86 - Real-time event 86",
+ Signal::SIG87 => "SIG87 - Real-time event 87",
+ Signal::SIG88 => "SIG88 - Real-time event 88",
+ Signal::SIG89 => "SIG89 - Real-time event 89",
+ Signal::SIG90 => "SIG90 - Real-time event 90",
+ Signal::SIG91 => "SIG91 - Real-time event 91",
+ Signal::SIG92 => "SIG92 - Real-time event 92",
+ Signal::SIG93 => "SIG93 - Real-time event 93",
+ Signal::SIG94 => "SIG94 - Real-time event 94",
+ Signal::SIG95 => "SIG95 - Real-time event 95",
+ Signal::SIG96 => "SIG96 - Real-time event 96",
+ Signal::SIG97 => "SIG97 - Real-time event 97",
+ Signal::SIG98 => "SIG98 - Real-time event 98",
+ Signal::SIG99 => "SIG99 - Real-time event 99",
+ Signal::SIG100 => "SIG100 - Real-time event 100",
+ Signal::SIG101 => "SIG101 - Real-time event 101",
+ Signal::SIG102 => "SIG102 - Real-time event 102",
+ Signal::SIG103 => "SIG103 - Real-time event 103",
+ Signal::SIG104 => "SIG104 - Real-time event 104",
+ Signal::SIG105 => "SIG105 - Real-time event 105",
+ Signal::SIG106 => "SIG106 - Real-time event 106",
+ Signal::SIG107 => "SIG107 - Real-time event 107",
+ Signal::SIG108 => "SIG108 - Real-time event 108",
+ Signal::SIG109 => "SIG109 - Real-time event 109",
+ Signal::SIG110 => "SIG110 - Real-time event 110",
+ Signal::SIG111 => "SIG111 - Real-time event 111",
+ Signal::SIG112 => "SIG112 - Real-time event 112",
+ Signal::SIG113 => "SIG113 - Real-time event 113",
+ Signal::SIG114 => "SIG114 - Real-time event 114",
+ Signal::SIG115 => "SIG115 - Real-time event 115",
+ Signal::SIG116 => "SIG116 - Real-time event 116",
+ Signal::SIG117 => "SIG117 - Real-time event 117",
+ Signal::SIG118 => "SIG118 - Real-time event 118",
+ Signal::SIG119 => "SIG119 - Real-time event 119",
+ Signal::SIG120 => "SIG120 - Real-time event 120",
+ Signal::SIG121 => "SIG121 - Real-time event 121",
+ Signal::SIG122 => "SIG122 - Real-time event 122",
+ Signal::SIG123 => "SIG123 - Real-time event 123",
+ Signal::SIG124 => "SIG124 - Real-time event 124",
+ Signal::SIG125 => "SIG125 - Real-time event 125",
+ Signal::SIG126 => "SIG126 - Real-time event 126",
+ Signal::SIG127 => "SIG127 - Real-time event 127",
+ Signal::SIGINFO => "SIGINFO - Information request",
+ Signal::UNKNOWN => "UNKNOWN - Unknown signal",
+ Signal::INTERNAL_DEFAULT => "INTERNAL_DEFAULT - Internal error: printing GDB_SIGNAL_DEFAULT",
+ Signal::EXC_BAD_ACCESS => "EXC_BAD_ACCESS - Could not access memory",
Signal::EXC_BAD_INSTRUCTION => "EXC_BAD_INSTRUCTION - Illegal instruction/operand",
- Signal::EXC_ARITHMETIC => "EXC_ARITHMETIC - Arithmetic exception",
- Signal::EXC_EMULATION => "EXC_EMULATION - Emulation instruction",
- Signal::EXC_SOFTWARE => "EXC_SOFTWARE - Software generated exception",
- Signal::EXC_BREAKPOINT => "EXC_BREAKPOINT - Breakpoint",
- Signal::SIGLIBRT => "SIGLIBRT - librt internal signal",
+ Signal::EXC_ARITHMETIC => "EXC_ARITHMETIC - Arithmetic exception",
+ Signal::EXC_EMULATION => "EXC_EMULATION - Emulation instruction",
+ Signal::EXC_SOFTWARE => "EXC_SOFTWARE - Software generated exception",
+ Signal::EXC_BREAKPOINT => "EXC_BREAKPOINT - Breakpoint",
+ Signal::SIGLIBRT => "SIGLIBRT - librt internal signal",
+
+ _ => "custom signal (not defined in GDB's signals.def file)"
};
write!(f, "{}", s)
}
}
-
-impl Signal {
- #[cfg(not(feature = "paranoid_unsafe"))]
- pub(crate) fn from_protocol_u8(val: u8) -> Signal {
- if val <= 151 {
- // SAFETY: Signal is repr(u8), and `val` was confirmed to fall in valid range
- unsafe { core::mem::transmute(val) }
- } else {
- Signal::UNKNOWN
- }
- }
-
- #[cfg(feature = "paranoid_unsafe")]
- pub(crate) fn from_protocol_u8(val: u8) -> Signal {
- match val {
- 0 => Signal::SIGZERO,
- 1 => Signal::SIGHUP,
- 2 => Signal::SIGINT,
- 3 => Signal::SIGQUIT,
- 4 => Signal::SIGILL,
- 5 => Signal::SIGTRAP,
- 6 => Signal::SIGABRT,
- 7 => Signal::SIGEMT,
- 8 => Signal::SIGFPE,
- 9 => Signal::SIGKILL,
- 10 => Signal::SIGBUS,
- 11 => Signal::SIGSEGV,
- 12 => Signal::SIGSYS,
- 13 => Signal::SIGPIPE,
- 14 => Signal::SIGALRM,
- 15 => Signal::SIGTERM,
- 16 => Signal::SIGURG,
- 17 => Signal::SIGSTOP,
- 18 => Signal::SIGTSTP,
- 19 => Signal::SIGCONT,
- 20 => Signal::SIGCHLD,
- 21 => Signal::SIGTTIN,
- 22 => Signal::SIGTTOU,
- 23 => Signal::SIGIO,
- 24 => Signal::SIGXCPU,
- 25 => Signal::SIGXFSZ,
- 26 => Signal::SIGVTALRM,
- 27 => Signal::SIGPROF,
- 28 => Signal::SIGWINCH,
- 29 => Signal::SIGLOST,
- 30 => Signal::SIGUSR1,
- 31 => Signal::SIGUSR2,
- 32 => Signal::SIGPWR,
- 33 => Signal::SIGPOLL,
- 34 => Signal::SIGWIND,
- 35 => Signal::SIGPHONE,
- 36 => Signal::SIGWAITING,
- 37 => Signal::SIGLWP,
- 38 => Signal::SIGDANGER,
- 39 => Signal::SIGGRANT,
- 40 => Signal::SIGRETRACT,
- 41 => Signal::SIGMSG,
- 42 => Signal::SIGSOUND,
- 43 => Signal::SIGSAK,
- 44 => Signal::SIGPRIO,
- 45 => Signal::SIG33,
- 46 => Signal::SIG34,
- 47 => Signal::SIG35,
- 48 => Signal::SIG36,
- 49 => Signal::SIG37,
- 50 => Signal::SIG38,
- 51 => Signal::SIG39,
- 52 => Signal::SIG40,
- 53 => Signal::SIG41,
- 54 => Signal::SIG42,
- 55 => Signal::SIG43,
- 56 => Signal::SIG44,
- 57 => Signal::SIG45,
- 58 => Signal::SIG46,
- 59 => Signal::SIG47,
- 60 => Signal::SIG48,
- 61 => Signal::SIG49,
- 62 => Signal::SIG50,
- 63 => Signal::SIG51,
- 64 => Signal::SIG52,
- 65 => Signal::SIG53,
- 66 => Signal::SIG54,
- 67 => Signal::SIG55,
- 68 => Signal::SIG56,
- 69 => Signal::SIG57,
- 70 => Signal::SIG58,
- 71 => Signal::SIG59,
- 72 => Signal::SIG60,
- 73 => Signal::SIG61,
- 74 => Signal::SIG62,
- 75 => Signal::SIG63,
- 76 => Signal::SIGCANCEL,
- 77 => Signal::SIG32,
- 78 => Signal::SIG64,
- 79 => Signal::SIG65,
- 80 => Signal::SIG66,
- 81 => Signal::SIG67,
- 82 => Signal::SIG68,
- 83 => Signal::SIG69,
- 84 => Signal::SIG70,
- 85 => Signal::SIG71,
- 86 => Signal::SIG72,
- 87 => Signal::SIG73,
- 88 => Signal::SIG74,
- 89 => Signal::SIG75,
- 90 => Signal::SIG76,
- 91 => Signal::SIG77,
- 92 => Signal::SIG78,
- 93 => Signal::SIG79,
- 94 => Signal::SIG80,
- 95 => Signal::SIG81,
- 96 => Signal::SIG82,
- 97 => Signal::SIG83,
- 98 => Signal::SIG84,
- 99 => Signal::SIG85,
- 100 => Signal::SIG86,
- 101 => Signal::SIG87,
- 102 => Signal::SIG88,
- 103 => Signal::SIG89,
- 104 => Signal::SIG90,
- 105 => Signal::SIG91,
- 106 => Signal::SIG92,
- 107 => Signal::SIG93,
- 108 => Signal::SIG94,
- 109 => Signal::SIG95,
- 110 => Signal::SIG96,
- 111 => Signal::SIG97,
- 112 => Signal::SIG98,
- 113 => Signal::SIG99,
- 114 => Signal::SIG100,
- 115 => Signal::SIG101,
- 116 => Signal::SIG102,
- 117 => Signal::SIG103,
- 118 => Signal::SIG104,
- 119 => Signal::SIG105,
- 120 => Signal::SIG106,
- 121 => Signal::SIG107,
- 122 => Signal::SIG108,
- 123 => Signal::SIG109,
- 124 => Signal::SIG110,
- 125 => Signal::SIG111,
- 126 => Signal::SIG112,
- 127 => Signal::SIG113,
- 128 => Signal::SIG114,
- 129 => Signal::SIG115,
- 130 => Signal::SIG116,
- 131 => Signal::SIG117,
- 132 => Signal::SIG118,
- 133 => Signal::SIG119,
- 134 => Signal::SIG120,
- 135 => Signal::SIG121,
- 136 => Signal::SIG122,
- 137 => Signal::SIG123,
- 138 => Signal::SIG124,
- 139 => Signal::SIG125,
- 140 => Signal::SIG126,
- 141 => Signal::SIG127,
- 142 => Signal::SIGINFO,
- 143 => Signal::UNKNOWN,
- 144 => Signal::INTERNAL_DEFAULT,
- 145 => Signal::EXC_BAD_ACCESS,
- 146 => Signal::EXC_BAD_INSTRUCTION,
- 147 => Signal::EXC_ARITHMETIC,
- 148 => Signal::EXC_EMULATION,
- 149 => Signal::EXC_SOFTWARE,
- 150 => Signal::EXC_BREAKPOINT,
- 151 => Signal::SIGLIBRT,
-
- _ => Signal::UNKNOWN,
- }
- }
-}
diff --git a/src/conn/impls/boxed.rs b/src/conn/impls/boxed.rs
index 2de92c0..100d83e 100644
--- a/src/conn/impls/boxed.rs
+++ b/src/conn/impls/boxed.rs
@@ -1,6 +1,5 @@
use crate::conn::Connection;
use crate::conn::ConnectionExt;
-
use alloc::boxed::Box;
impl<E> Connection for Box<dyn Connection<Error = E>> {
diff --git a/src/conn/impls/tcpstream.rs b/src/conn/impls/tcpstream.rs
index 969b7ff..512a15d 100644
--- a/src/conn/impls/tcpstream.rs
+++ b/src/conn/impls/tcpstream.rs
@@ -1,7 +1,6 @@
-use std::net::TcpStream;
-
use crate::conn::Connection;
use crate::conn::ConnectionExt;
+use std::net::TcpStream;
impl Connection for TcpStream {
type Error = std::io::Error;
diff --git a/src/conn/impls/unixstream.rs b/src/conn/impls/unixstream.rs
index a810021..575cc4e 100644
--- a/src/conn/impls/unixstream.rs
+++ b/src/conn/impls/unixstream.rs
@@ -1,8 +1,7 @@
-use std::io;
-use std::os::unix::net::UnixStream;
-
use crate::conn::Connection;
use crate::conn::ConnectionExt;
+use std::io;
+use std::os::unix::net::UnixStream;
// TODO: Remove PeekExt once rust-lang/rust#73761 is stabilized
trait PeekExt {
diff --git a/src/lib.rs b/src/lib.rs
index d71756b..3d99165 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,6 +1,6 @@
-//! An ergonomic and easy-to-integrate implementation of the
-//! [GDB Remote Serial Protocol](https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html#Remote-Protocol)
-//! in Rust, with full `#![no_std]` support.
+//! An ergonomic, featureful, and easy-to-integrate implementation of the [GDB
+//! Remote Serial Protocol](https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html#Remote-Protocol)
+//! in Rust, with no-compromises `#![no_std]` support.
//!
//! ## Feature flags
//!
@@ -86,8 +86,8 @@
//!
//! ### The `Target` Trait
//!
-//! The [`Target`](target::Target) trait describes how to control and modify
-//! a system's execution state during a GDB debugging session, and serves as the
+//! The [`Target`](target::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 GDB protocol implementation and a
//! specific target's project/platform-specific code.
//!
@@ -169,7 +169,7 @@
//! #
//! use gdbstub::common::Signal;
//! use gdbstub::conn::{Connection, ConnectionExt}; // note the use of `ConnectionExt`
-//! use gdbstub::stub::{run_blocking, DisconnectReason, GdbStub, GdbStubError};
+//! use gdbstub::stub::{run_blocking, DisconnectReason, GdbStub};
//! use gdbstub::stub::SingleThreadStopReason;
//! use gdbstub::target::Target;
//!
@@ -251,11 +251,18 @@
//! }
//! DisconnectReason::Kill => println!("GDB sent a kill command"),
//! },
-//! Err(GdbStubError::TargetError(e)) => {
-//! println!("target encountered a fatal error: {}", e)
-//! }
//! Err(e) => {
-//! println!("gdbstub encountered a fatal error: {}", e)
+//! if e.is_target_error() {
+//! println!(
+//! "target encountered a fatal error: {}",
+//! e.into_target_error().unwrap()
+//! )
+//! } else if e.is_connection_error() {
+//! let (e, kind) = e.into_connection_error().unwrap();
+//! println!("connection error: {:?} - {}", kind, e,)
+//! } else {
+//! println!("gdbstub encountered a fatal error: {}", e)
+//! }
//! }
//! }
//! }
@@ -304,6 +311,7 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "paranoid_unsafe", forbid(unsafe_code))]
+#![warn(missing_docs)]
#[cfg(feature = "alloc")]
extern crate alloc;
@@ -341,7 +349,8 @@ macro_rules! unwrap {
/// (Internal) The fake Tid that's used when running in single-threaded mode.
const SINGLE_THREAD_TID: common::Tid = unwrap!(common::Tid::new(1));
-/// (Internal) The fake Pid reported to GDB when running in multi-threaded mode.
+/// (Internal) The fake Pid reported to GDB when the target hasn't opted into
+/// reporting a custom Pid itself.
const FAKE_PID: common::Pid = unwrap!(common::Pid::new(1));
pub(crate) mod is_valid_tid {
diff --git a/src/protocol/commands.rs b/src/protocol/commands.rs
index c42dccd..1229899 100644
--- a/src/protocol/commands.rs
+++ b/src/protocol/commands.rs
@@ -1,17 +1,17 @@
-use paste::paste;
-
use crate::protocol::packet::PacketBuf;
use crate::target::Target;
+use paste::paste;
/// Common imports used by >50% of all packet parsers.
///
/// Do not clutter this prelude with types only used by a few packets.
-pub(self) mod prelude {
- pub use core::convert::{TryFrom, TryInto};
-
+pub mod prelude {
pub use crate::protocol::commands::ParseCommand;
- pub use crate::protocol::common::hex::{decode_hex, decode_hex_buf};
+ pub use crate::protocol::common::hex::decode_hex;
+ pub use crate::protocol::common::hex::decode_hex_buf;
pub use crate::protocol::packet::PacketBuf;
+ pub use core::convert::TryFrom;
+ pub use core::convert::TryInto;
}
pub trait ParseCommand<'a>: Sized {
@@ -91,6 +91,7 @@ macro_rules! commands {
fn support_single_register_access(&mut self) -> Option<()>;
fn support_reverse_step(&mut self) -> Option<()>;
fn support_reverse_cont(&mut self) -> Option<()>;
+ fn support_no_ack_mode(&mut self) -> Option<()>;
fn support_x_upcase_packet(&mut self) -> Option<()>;
fn support_thread_extra_info(&mut self) -> Option<()>;
}
@@ -114,7 +115,7 @@ macro_rules! commands {
fn support_lldb_register_info(&mut self) -> Option<()> {
use crate::arch::Arch;
- if self.use_lldb_register_info()
+ if self.use_lldb_register_info()
&& (T::Arch::lldb_register_info(usize::max_value()).is_some()
|| self.support_lldb_register_info_override().is_some())
{
@@ -122,7 +123,7 @@ macro_rules! commands {
} else {
None
}
- }
+ }
fn support_resume(&mut self) -> Option<()> {
self.base_ops().resume_ops().map(drop)
@@ -160,6 +161,14 @@ macro_rules! commands {
}
}
+ fn support_no_ack_mode(&mut self) -> Option<()> {
+ if self.use_no_ack_mode() {
+ Some(())
+ } else {
+ None
+ }
+ }
+
fn support_thread_extra_info(&mut self) -> Option<()> {
use crate::target::ext::base::BaseOps;
match self.base_ops() {
@@ -228,7 +237,6 @@ commands! {
"M" => _m_upcase::M<'a>,
"qAttached" => _qAttached::qAttached,
"qfThreadInfo" => _qfThreadInfo::qfThreadInfo,
- "QStartNoAckMode" => _QStartNoAckMode::QStartNoAckMode,
"qsThreadInfo" => _qsThreadInfo::qsThreadInfo,
"qSupported" => _qSupported::qSupported<'a>,
"T" => _t_upcase::T,
@@ -249,6 +257,10 @@ commands! {
"X" => _x_upcase::X<'a>,
}
+ no_ack_mode {
+ "QStartNoAckMode" => _QStartNoAckMode::QStartNoAckMode,
+ }
+
single_register_access use 'a {
"p" => _p::p<'a>,
"P" => _p_upcase::P<'a>,
@@ -256,6 +268,7 @@ commands! {
extended_mode use 'a {
"!" => exclamation_mark::ExclamationMark,
+ "qC" => _qC::qC,
"QDisableRandomization" => _QDisableRandomization::QDisableRandomization,
"QEnvironmentHexEncoded" => _QEnvironmentHexEncoded::QEnvironmentHexEncoded<'a>,
"QEnvironmentReset" => _QEnvironmentReset::QEnvironmentReset,
diff --git a/src/protocol/commands/_QCatchSyscalls.rs b/src/protocol/commands/_QCatchSyscalls.rs
index 26a27a1..0991117 100644
--- a/src/protocol/commands/_QCatchSyscalls.rs
+++ b/src/protocol/commands/_QCatchSyscalls.rs
@@ -1,5 +1,4 @@
use super::prelude::*;
-
use crate::protocol::common::lists::ArgListHex;
#[derive(Debug)]
diff --git a/src/protocol/commands/_d_upcase.rs b/src/protocol/commands/_d_upcase.rs
index c532532..f33ae62 100644
--- a/src/protocol/commands/_d_upcase.rs
+++ b/src/protocol/commands/_d_upcase.rs
@@ -1,5 +1,4 @@
use super::prelude::*;
-
use crate::common::Pid;
#[derive(Debug)]
diff --git a/src/protocol/commands/_h_upcase.rs b/src/protocol/commands/_h_upcase.rs
index 3e23ced..f7bb9ed 100644
--- a/src/protocol/commands/_h_upcase.rs
+++ b/src/protocol/commands/_h_upcase.rs
@@ -1,5 +1,4 @@
use super::prelude::*;
-
use crate::protocol::common::thread_id::ThreadId;
#[derive(Debug)]
diff --git a/src/protocol/commands/_qAttached.rs b/src/protocol/commands/_qAttached.rs
index 3655559..6323e87 100644
--- a/src/protocol/commands/_qAttached.rs
+++ b/src/protocol/commands/_qAttached.rs
@@ -1,5 +1,4 @@
use super::prelude::*;
-
use crate::common::Pid;
#[derive(Debug)]
diff --git a/src/protocol/commands/_qC.rs b/src/protocol/commands/_qC.rs
new file mode 100644
index 0000000..decba12
--- /dev/null
+++ b/src/protocol/commands/_qC.rs
@@ -0,0 +1,14 @@
+use super::prelude::*;
+
+#[derive(Debug)]
+pub struct qC;
+
+impl<'a> ParseCommand<'a> for qC {
+ #[inline(always)]
+ fn from_packet(buf: PacketBuf<'a>) -> Option<Self> {
+ if !buf.into_body().is_empty() {
+ return None;
+ }
+ Some(qC)
+ }
+}
diff --git a/src/protocol/commands/_qThreadExtraInfo.rs b/src/protocol/commands/_qThreadExtraInfo.rs
index 9fe6200..d89fbcd 100644
--- a/src/protocol/commands/_qThreadExtraInfo.rs
+++ b/src/protocol/commands/_qThreadExtraInfo.rs
@@ -1,5 +1,4 @@
use super::prelude::*;
-
use crate::protocol::common::thread_id::ThreadId;
use crate::protocol::ConcreteThreadId;
diff --git a/src/protocol/commands/_qXfer_auxv_read.rs b/src/protocol/commands/_qXfer_auxv_read.rs
index 15a8c17..11a2c9b 100644
--- a/src/protocol/commands/_qXfer_auxv_read.rs
+++ b/src/protocol/commands/_qXfer_auxv_read.rs
@@ -1,6 +1,6 @@
// use super::prelude::*; // unused
-
-use crate::protocol::common::qxfer::{ParseAnnex, QXferReadBase};
+use crate::protocol::common::qxfer::ParseAnnex;
+use crate::protocol::common::qxfer::QXferReadBase;
pub type qXferAuxvRead<'a> = QXferReadBase<'a, AuxvAnnex>;
diff --git a/src/protocol/commands/_qXfer_exec_file.rs b/src/protocol/commands/_qXfer_exec_file.rs
index 8280bda..efcb8bc 100644
--- a/src/protocol/commands/_qXfer_exec_file.rs
+++ b/src/protocol/commands/_qXfer_exec_file.rs
@@ -1,7 +1,7 @@
use super::prelude::*;
-
use crate::common::Pid;
-use crate::protocol::common::qxfer::{ParseAnnex, QXferReadBase};
+use crate::protocol::common::qxfer::ParseAnnex;
+use crate::protocol::common::qxfer::QXferReadBase;
pub type qXferExecFileRead<'a> = QXferReadBase<'a, ExecFileAnnex>;
diff --git a/src/protocol/commands/_qXfer_features_read.rs b/src/protocol/commands/_qXfer_features_read.rs
index 73f96e5..6da9a72 100644
--- a/src/protocol/commands/_qXfer_features_read.rs
+++ b/src/protocol/commands/_qXfer_features_read.rs
@@ -1,6 +1,6 @@
// use super::prelude::*; // unused
-
-use crate::protocol::common::qxfer::{ParseAnnex, QXferReadBase};
+use crate::protocol::common::qxfer::ParseAnnex;
+use crate::protocol::common::qxfer::QXferReadBase;
pub type qXferFeaturesRead<'a> = QXferReadBase<'a, FeaturesAnnex<'a>>;
diff --git a/src/protocol/commands/_qXfer_memory_map.rs b/src/protocol/commands/_qXfer_memory_map.rs
index 169d1b4..6496cdc 100644
--- a/src/protocol/commands/_qXfer_memory_map.rs
+++ b/src/protocol/commands/_qXfer_memory_map.rs
@@ -1,6 +1,6 @@
// use super::prelude::*; // unused
-
-use crate::protocol::common::qxfer::{ParseAnnex, QXferReadBase};
+use crate::protocol::common::qxfer::ParseAnnex;
+use crate::protocol::common::qxfer::QXferReadBase;
pub type qXferMemoryMapRead<'a> = QXferReadBase<'a, MemoryMapAnnex>;
diff --git a/src/protocol/commands/_t_upcase.rs b/src/protocol/commands/_t_upcase.rs
index e7c4636..e638330 100644
--- a/src/protocol/commands/_t_upcase.rs
+++ b/src/protocol/commands/_t_upcase.rs
@@ -1,5 +1,4 @@
use super::prelude::*;
-
use crate::protocol::common::thread_id::ThreadId;
#[derive(Debug)]
diff --git a/src/protocol/commands/_vAttach.rs b/src/protocol/commands/_vAttach.rs
index 252db54..cfe026f 100644
--- a/src/protocol/commands/_vAttach.rs
+++ b/src/protocol/commands/_vAttach.rs
@@ -1,5 +1,4 @@
use super::prelude::*;
-
use crate::common::Pid;
#[derive(Debug)]
diff --git a/src/protocol/commands/_vCont.rs b/src/protocol/commands/_vCont.rs
index b90c9e6..437fa4c 100644
--- a/src/protocol/commands/_vCont.rs
+++ b/src/protocol/commands/_vCont.rs
@@ -1,8 +1,8 @@
use super::prelude::*;
-
use crate::common::Signal;
use crate::protocol::common::hex::HexString;
-use crate::protocol::common::thread_id::{SpecificThreadId, ThreadId};
+use crate::protocol::common::thread_id::SpecificThreadId;
+use crate::protocol::common::thread_id::ThreadId;
// TODO?: instead of lazily parsing data, parse the strings into a compressed
// binary representations that can be stuffed back into the packet buffer and
@@ -112,8 +112,8 @@ impl<'a> VContKind<'a> {
[b'c'] => Continue,
[b's'] => Step,
[b't'] => Stop,
- [b'C', sig @ ..] => ContinueWithSig(Signal::from_protocol_u8(decode_hex(sig).ok()?)),
- [b'S', sig @ ..] => StepWithSig(Signal::from_protocol_u8(decode_hex(sig).ok()?)),
+ [b'C', sig @ ..] => ContinueWithSig(Signal(decode_hex(sig).ok()?)),
+ [b'S', sig @ ..] => StepWithSig(Signal(decode_hex(sig).ok()?)),
[b'r', range @ ..] => {
let mut range = range.split(|b| *b == b',');
RangeStep(HexString(range.next()?), HexString(range.next()?))
diff --git a/src/protocol/commands/_vFile_open.rs b/src/protocol/commands/_vFile_open.rs
index 7497912..04a1828 100644
--- a/src/protocol/commands/_vFile_open.rs
+++ b/src/protocol/commands/_vFile_open.rs
@@ -1,6 +1,6 @@
use super::prelude::*;
-
-use crate::target::ext::host_io::{HostIoOpenFlags, HostIoOpenMode};
+use crate::target::ext::host_io::HostIoOpenFlags;
+use crate::target::ext::host_io::HostIoOpenMode;
#[derive(Debug)]
pub struct vFileOpen<'a> {
diff --git a/src/protocol/commands/_vFile_pwrite.rs b/src/protocol/commands/_vFile_pwrite.rs
index 94cd34a..32f45f1 100644
--- a/src/protocol/commands/_vFile_pwrite.rs
+++ b/src/protocol/commands/_vFile_pwrite.rs
@@ -1,5 +1,4 @@
use super::prelude::*;
-
use crate::protocol::common::hex::decode_bin_buf;
#[derive(Debug)]
diff --git a/src/protocol/commands/_vFile_setfs.rs b/src/protocol/commands/_vFile_setfs.rs
index 41a3100..aacbc69 100644
--- a/src/protocol/commands/_vFile_setfs.rs
+++ b/src/protocol/commands/_vFile_setfs.rs
@@ -1,5 +1,4 @@
use super::prelude::*;
-
use crate::target::ext::host_io::FsKind;
#[derive(Debug)]
diff --git a/src/protocol/commands/_vKill.rs b/src/protocol/commands/_vKill.rs
index a1d687b..c06818b 100644
--- a/src/protocol/commands/_vKill.rs
+++ b/src/protocol/commands/_vKill.rs
@@ -1,5 +1,4 @@
use super::prelude::*;
-
use crate::common::Pid;
#[derive(Debug)]
diff --git a/src/protocol/commands/_vRun.rs b/src/protocol/commands/_vRun.rs
index 849c795..a4b619d 100644
--- a/src/protocol/commands/_vRun.rs
+++ b/src/protocol/commands/_vRun.rs
@@ -1,5 +1,4 @@
use super::prelude::*;
-
use crate::protocol::common::lists::ArgListHex;
#[derive(Debug)]
diff --git a/src/protocol/commands/_x_upcase.rs b/src/protocol/commands/_x_upcase.rs
index 218c16c..9467e5f 100644
--- a/src/protocol/commands/_x_upcase.rs
+++ b/src/protocol/commands/_x_upcase.rs
@@ -1,5 +1,4 @@
use super::prelude::*;
-
use crate::protocol::common::hex::decode_bin_buf;
#[derive(Debug)]
diff --git a/src/protocol/commands/breakpoint.rs b/src/protocol/commands/breakpoint.rs
index 38ad046..b0a0e9d 100644
--- a/src/protocol/commands/breakpoint.rs
+++ b/src/protocol/commands/breakpoint.rs
@@ -1,4 +1,5 @@
-use crate::protocol::common::hex::{decode_hex, decode_hex_buf};
+use crate::protocol::common::hex::decode_hex;
+use crate::protocol::common::hex::decode_hex_buf;
// Breakpoint packets are split up like this:
//
diff --git a/src/protocol/common/hex.rs b/src/protocol/common/hex.rs
index ade9032..6eb35e0 100644
--- a/src/protocol/common/hex.rs
+++ b/src/protocol/common/hex.rs
@@ -1,4 +1,7 @@
-use num_traits::{CheckedAdd, CheckedMul, FromPrimitive, Zero};
+use num_traits::CheckedAdd;
+use num_traits::CheckedMul;
+use num_traits::FromPrimitive;
+use num_traits::Zero;
#[derive(Debug)]
pub enum DecodeHexError {
diff --git a/src/protocol/common/lists.rs b/src/protocol/common/lists.rs
index 5dfdab7..1f2bc88 100644
--- a/src/protocol/common/lists.rs
+++ b/src/protocol/common/lists.rs
@@ -1,4 +1,5 @@
-use crate::protocol::common::hex::{decode_hex_buf, is_hex};
+use crate::protocol::common::hex::decode_hex_buf;
+use crate::protocol::common::hex::is_hex;
/// A wrapper type around a list of hex encoded arguments separated by `;`.
#[derive(Debug)]
diff --git a/src/protocol/common/thread_id.rs b/src/protocol/common/thread_id.rs
index 36a3ea9..e1104d3 100644
--- a/src/protocol/common/thread_id.rs
+++ b/src/protocol/common/thread_id.rs
@@ -1,7 +1,7 @@
-use core::convert::{TryFrom, TryInto};
-use core::num::NonZeroUsize;
-
use crate::protocol::common::hex::decode_hex;
+use core::convert::TryFrom;
+use core::convert::TryInto;
+use core::num::NonZeroUsize;
/// Tid/Pid Selector.
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
diff --git a/src/protocol/console_output.rs b/src/protocol/console_output.rs
index 16b30aa..54774be 100644
--- a/src/protocol/console_output.rs
+++ b/src/protocol/console_output.rs
@@ -1,7 +1,6 @@
-use core::fmt;
-
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
+use core::fmt;
/// Helper struct to send console output to GDB.
///
diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs
index 6dd8166..3ea5a03 100644
--- a/src/protocol/mod.rs
+++ b/src/protocol/mod.rs
@@ -3,6 +3,9 @@
//! These types should _not_ leak into the public interface (with a few
//! exceptions, as listed below).
+pub use console_output::ConsoleOutput;
+pub use packet::PacketParseError;
+
mod common;
mod console_output;
mod packet;
@@ -10,11 +13,10 @@ mod response_writer;
pub(crate) mod commands;
pub(crate) mod recv_packet;
-
-pub(crate) use common::thread_id::{ConcreteThreadId, IdKind, SpecificIdKind, SpecificThreadId};
+pub(crate) use common::thread_id::ConcreteThreadId;
+pub(crate) use common::thread_id::IdKind;
+pub(crate) use common::thread_id::SpecificIdKind;
+pub(crate) use common::thread_id::SpecificThreadId;
pub(crate) use packet::Packet;
-pub(crate) use response_writer::{Error as ResponseWriterError, ResponseWriter};
-
-// These types end up a part of the public interface.
-pub use console_output::ConsoleOutput;
-pub use packet::PacketParseError;
+pub(crate) use response_writer::Error as ResponseWriterError;
+pub(crate) use response_writer::ResponseWriter;
diff --git a/src/protocol/recv_packet.rs b/src/protocol/recv_packet.rs
index 9f3b567..f6e7003 100644
--- a/src/protocol/recv_packet.rs
+++ b/src/protocol/recv_packet.rs
@@ -1,10 +1,9 @@
+use crate::util::managed_vec::CapacityError;
+use crate::util::managed_vec::ManagedVec;
#[cfg(feature = "trace-pkt")]
use alloc::string::String;
-
use managed::ManagedSlice;
-use crate::util::managed_vec::{CapacityError, ManagedVec};
-
enum State {
Ready,
Body,
diff --git a/src/protocol/response_writer.rs b/src/protocol/response_writer.rs
index 3dea22a..42c2a20 100644
--- a/src/protocol/response_writer.rs
+++ b/src/protocol/response_writer.rs
@@ -1,14 +1,14 @@
+use crate::conn::Connection;
+use crate::internal::BeBytes;
+use crate::protocol::SpecificIdKind;
+use crate::protocol::SpecificThreadId;
#[cfg(feature = "trace-pkt")]
use alloc::string::String;
#[cfg(feature = "trace-pkt")]
use alloc::vec::Vec;
-
use num_traits::identities::one;
-use num_traits::{CheckedRem, PrimInt};
-
-use crate::conn::Connection;
-use crate::internal::BeBytes;
-use crate::protocol::{SpecificIdKind, SpecificThreadId};
+use num_traits::CheckedRem;
+use num_traits::PrimInt;
/// Newtype around a Connection error. Having a newtype allows implementing a
/// `From<ResponseWriterError<C>> for crate::Error<T, C>`, which greatly
diff --git a/src/stub/builder.rs b/src/stub/builder.rs
index bb1ceba..fa9e5a2 100644
--- a/src/stub/builder.rs
+++ b/src/stub/builder.rs
@@ -1,13 +1,11 @@
-use core::fmt::{self, Display};
-use core::marker::PhantomData;
-
-use managed::ManagedSlice;
-
-use crate::conn::Connection;
-use crate::target::Target;
-
use super::core_impl::GdbStubImpl;
use super::GdbStub;
+use crate::conn::Connection;
+use crate::target::Target;
+use core::fmt::Display;
+use core::fmt::{self};
+use core::marker::PhantomData;
+use managed::ManagedSlice;
/// An error which may occur when building a [`GdbStub`].
#[derive(Debug)]
diff --git a/src/stub/core_impl.rs b/src/stub/core_impl.rs
index 31ab884..07774d4 100644
--- a/src/stub/core_impl.rs
+++ b/src/stub/core_impl.rs
@@ -1,12 +1,14 @@
-use core::marker::PhantomData;
-
-use crate::common::{Signal, Tid};
+use crate::common::Signal;
+use crate::common::Tid;
use crate::conn::Connection;
use crate::protocol::commands::Command;
-use crate::protocol::{Packet, ResponseWriter, SpecificIdKind};
-use crate::stub::GdbStubError as Error;
+use crate::protocol::Packet;
+use crate::protocol::ResponseWriter;
+use crate::protocol::SpecificIdKind;
+use crate::stub::error::InternalError;
use crate::target::Target;
use crate::SINGLE_THREAD_TID;
+use core::marker::PhantomData;
/// Common imports used by >50% of all extensions.
///
@@ -16,8 +18,9 @@ mod prelude {
pub(super) use crate::internal::BeBytes;
pub(super) use crate::protocol::ResponseWriter;
pub(super) use crate::stub::core_impl::target_result_ext::TargetResultExt;
- pub(super) use crate::stub::core_impl::{GdbStubImpl, HandlerStatus};
- pub(super) use crate::stub::error::GdbStubError as Error;
+ pub(super) use crate::stub::core_impl::GdbStubImpl;
+ pub(super) use crate::stub::core_impl::HandlerStatus;
+ pub(super) use crate::stub::error::InternalError as Error;
pub(super) use crate::target::Target;
}
@@ -31,6 +34,7 @@ mod host_io;
mod lldb_register_info;
mod memory_map;
mod monitor_cmd;
+mod no_ack_mode;
mod resume;
mod reverse_exec;
mod section_offsets;
@@ -42,7 +46,7 @@ mod x_upcase_packet;
pub(crate) use resume::FinishExecStatus;
pub(crate) mod target_result_ext {
- use crate::stub::GdbStubError;
+ use crate::stub::error::InternalError;
use crate::target::TargetError;
/// Extension trait to ease working with `TargetResult` in the GdbStub
@@ -51,14 +55,14 @@ pub(crate) mod target_result_ext {
/// Encapsulates the boilerplate associated with handling
/// `TargetError`s, such as bailing-out on Fatal errors, or
/// returning response codes.
- fn handle_error(self) -> Result<V, GdbStubError<T, C>>;
+ fn handle_error(self) -> Result<V, InternalError<T, C>>;
}
impl<V, T, C> TargetResultExt<V, T, C> for Result<V, TargetError<T>> {
- fn handle_error(self) -> Result<V, GdbStubError<T, C>> {
+ fn handle_error(self) -> Result<V, InternalError<T, C>> {
let code = match self {
Ok(v) => return Ok(v),
- Err(TargetError::Fatal(e)) => return Err(GdbStubError::TargetError(e)),
+ Err(TargetError::Fatal(e)) => return Err(InternalError::TargetError(e)),
// Recoverable errors:
// Error code 121 corresponds to `EREMOTEIO` lol
Err(TargetError::NonFatal) => 121,
@@ -67,7 +71,7 @@ pub(crate) mod target_result_ext {
Err(TargetError::Io(e)) => e.raw_os_error().unwrap_or(121) as u8,
};
- Err(GdbStubError::NonFatalError(code))
+ Err(InternalError::NonFatalError(code))
}
}
}
@@ -92,7 +96,7 @@ pub enum State {
Disconnect(DisconnectReason),
}
-pub struct GdbStubImpl<T: Target, C: Connection> {
+pub(crate) struct GdbStubImpl<T: Target, C: Connection> {
_target: PhantomData<T>,
_connection: PhantomData<C>,
@@ -133,10 +137,10 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
target: &mut T,
conn: &mut C,
packet: Packet<'_>,
- ) -> Result<State, Error<T::Error, C::Error>> {
+ ) -> Result<State, InternalError<T::Error, C::Error>> {
match packet {
Packet::Ack => Ok(State::Pump),
- Packet::Nack => Err(Error::ClientSentNack),
+ Packet::Nack => Err(InternalError::ClientSentNack),
Packet::Interrupt => {
debug!("<-- interrupt packet");
Ok(State::CtrlCInterrupt)
@@ -144,7 +148,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
Packet::Command(command) => {
// Acknowledge the command
if !self.features.no_ack_mode() {
- conn.write(b'+').map_err(Error::ConnectionWrite)?;
+ conn.write(b'+').map_err(InternalError::conn_write)?;
}
let mut res = ResponseWriter::new(conn, target.use_rle());
@@ -158,7 +162,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
Ok(HandlerStatus::Disconnect(reason)) => Some(reason),
// HACK: handling this "dummy" error is required as part of the
// `TargetResultExt::handle_error()` machinery.
- Err(Error::NonFatalError(code)) => {
+ Err(InternalError::NonFatalError(code)) => {
res.write_str("E")?;
res.write_num(code)?;
None
@@ -188,12 +192,13 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
res: &mut ResponseWriter<'_, C>,
target: &mut T,
cmd: Command<'_>,
- ) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
+ ) -> Result<HandlerStatus, InternalError<T::Error, C::Error>> {
match cmd {
// `handle_X` methods are defined in the `ext` module
Command::Base(cmd) => self.handle_base(res, target, cmd),
Command::TargetXml(cmd) => self.handle_target_xml(res, target, cmd),
Command::Resume(cmd) => self.handle_stop_resume(res, target, cmd),
+ Command::NoAckMode(cmd) => self.handle_no_ack_mode(res, target, cmd),
Command::XUpcasePacket(cmd) => self.handle_x_upcase_packet(res, target, cmd),
Command::SingleRegisterAccess(cmd) => {
self.handle_single_register_access(res, target, cmd)
@@ -244,11 +249,15 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
}
}
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+struct ProtocolFeatures(u8);
+
// This bitflag is not part of the protocol - it is an internal implementation
// detail. The alternative would be to use multiple `bool` fields, which wastes
// space in minimal `gdbstub` configurations.
bitflags::bitflags! {
- struct ProtocolFeatures: u8 {
+ impl ProtocolFeatures: u8 {
const NO_ACK_MODE = 1 << 0;
const MULTIPROCESS = 1 << 1;
}
diff --git a/src/stub/core_impl/base.rs b/src/stub/core_impl/base.rs
index e7d77dd..9110297 100644
--- a/src/stub/core_impl/base.rs
+++ b/src/stub/core_impl/base.rs
@@ -1,19 +1,26 @@
use super::prelude::*;
-use crate::protocol::commands::ext::Base;
-
-use crate::arch::{Arch, Registers};
-use crate::common::Tid;
-use crate::protocol::{IdKind, SpecificIdKind, SpecificThreadId};
-use crate::target::ext::base::{BaseOps, ResumeOps};
-use crate::{FAKE_PID, SINGLE_THREAD_TID};
-
use super::DisconnectReason;
+use crate::arch::Arch;
+use crate::arch::Registers;
+use crate::common::Pid;
+use crate::common::Tid;
+use crate::protocol::commands::ext::Base;
+use crate::protocol::IdKind;
+use crate::protocol::SpecificIdKind;
+use crate::protocol::SpecificThreadId;
+use crate::target::ext::base::BaseOps;
+use crate::target::ext::base::ResumeOps;
+use crate::FAKE_PID;
+use crate::SINGLE_THREAD_TID;
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
#[inline(always)]
- fn get_sane_any_tid(&mut self, target: &mut T) -> Result<Tid, Error<T::Error, C::Error>> {
+ fn get_sane_any_tid(
+ &mut self,
+ target: &mut T,
+ ) -> Result<Option<Tid>, Error<T::Error, C::Error>> {
let tid = match target.base_ops() {
- BaseOps::SingleThread(_) => SINGLE_THREAD_TID,
+ BaseOps::SingleThread(_) => Some(SINGLE_THREAD_TID),
BaseOps::MultiThread(ops) => {
let mut first_tid = None;
ops.list_active_threads(&mut |tid| {
@@ -22,18 +29,58 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
}
})
.map_err(Error::TargetError)?;
- // Note that `Error::NoActiveThreads` shouldn't ever occur, since this method is
- // called from the `H` packet handler, which AFAIK is only sent after the GDB
- // client has confirmed that a thread / process exists.
- //
- // If it does, that really sucks, and will require rethinking how to handle "any
- // thread" messages.
- first_tid.ok_or(Error::NoActiveThreads)?
+ // It is possible for this to be `None` in the case where the target has
+ // not yet called `register_thread()`. This can happen, for example, if
+ // there are no active threads in the current target process.
+ first_tid
}
};
Ok(tid)
}
+ pub(crate) fn get_current_pid(
+ &mut self,
+ target: &mut T,
+ ) -> Result<Pid, Error<T::Error, C::Error>> {
+ if let Some(ops) = target
+ .support_extended_mode()
+ .and_then(|ops| ops.support_current_active_pid())
+ {
+ ops.current_active_pid().map_err(Error::TargetError)
+ } else {
+ Ok(FAKE_PID)
+ }
+ }
+
+ // Used by `?` and `vAttach` to return a "reasonable" stop reason.
+ //
+ // This is a bit of an implementation wart, since this is really something
+ // the user ought to be able to customize.
+ //
+ // Works fine for now though...
+ pub(crate) fn report_reasonable_stop_reason(
+ &mut self,
+ res: &mut ResponseWriter<'_, C>,
+ target: &mut T,
+ ) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
+ // Reply with a valid thread-id or GDB issues a warning when more
+ // than one thread is active
+ if let Some(tid) = self.get_sane_any_tid(target)? {
+ res.write_str("T05thread:")?;
+ res.write_specific_thread_id(SpecificThreadId {
+ pid: self
+ .features
+ .multiprocess()
+ .then_some(SpecificIdKind::WithId(self.get_current_pid(target)?)),
+ tid: SpecificIdKind::WithId(tid),
+ })?;
+ } else {
+ res.write_str("W00")?;
+ }
+ res.write_str(";")?;
+ Ok(HandlerStatus::Handled)
+ }
+
pub(crate) fn handle_base(
&mut self,
res: &mut ResponseWriter<'_, C>,
@@ -66,11 +113,11 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
res.write_num(cmd.packet_buffer_len)?;
// these are the few features that gdbstub unconditionally supports
- res.write_str(concat!(
- ";vContSupported+",
- ";multiprocess+",
- ";QStartNoAckMode+",
- ))?;
+ res.write_str(concat!(";vContSupported+", ";multiprocess+",))?;
+
+ if target.use_no_ack_mode() {
+ res.write_str(";QStartNoAckMode+")?;
+ }
if let Some(resume_ops) = target.base_ops().resume_ops() {
let (reverse_cont, reverse_step) = match resume_ops {
@@ -150,27 +197,12 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
HandlerStatus::Handled
}
- Base::QStartNoAckMode(_) => {
- self.features.set_no_ack_mode(true);
- HandlerStatus::NeedsOk
- }
// -------------------- "Core" Functionality -------------------- //
- // TODO: Improve the '?' response based on last-sent stop reason.
- // this will be particularly relevant when working on non-stop mode.
Base::QuestionMark(_) => {
- // Reply with a valid thread-id or GDB issues a warning when more
- // than one thread is active
- res.write_str("T05thread:")?;
- res.write_specific_thread_id(SpecificThreadId {
- pid: self
- .features
- .multiprocess()
- .then_some(SpecificIdKind::WithId(FAKE_PID)),
- tid: SpecificIdKind::WithId(self.get_sane_any_tid(target)?),
- })?;
- res.write_str(";")?;
- HandlerStatus::Handled
+ // TODO: Improve the '?' response.
+ // this will be particularly relevant when working on non-stop mode.
+ self.report_reasonable_stop_reason(res, target)?
}
Base::qAttached(cmd) => {
let is_attached = match target.support_extended_mode() {
@@ -238,7 +270,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
let addr = addr + NumCast::from(i).ok_or(Error::TargetMismatch)?;
let data = &mut buf[..chunk_size];
- match target.base_ops() {
+ let data_len = match target.base_ops() {
BaseOps::SingleThread(ops) => ops.read_addrs(addr, data),
BaseOps::MultiThread(ops) => {
ops.read_addrs(addr, data, self.current_mem_tid)
@@ -249,6 +281,8 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
n -= chunk_size;
i += chunk_size;
+ // TODO: add more specific error variant?
+ let data = data.get(..data_len).ok_or(Error::PacketBufferOverflow)?;
res.write_hex_buf(data)?;
}
HandlerStatus::Handled
@@ -302,17 +336,24 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
use crate::protocol::commands::_h_upcase::Op;
match cmd.kind {
Op::Other => match cmd.thread.tid {
- IdKind::Any => self.current_mem_tid = self.get_sane_any_tid(target)?,
+ IdKind::Any => match self.get_sane_any_tid(target)? {
+ Some(tid) => self.current_mem_tid = tid,
+ None => {
+ return Err(Error::NonFatalError(1));
+ }
+ },
// "All" threads doesn't make sense for memory accesses
IdKind::All => return Err(Error::PacketUnexpected),
IdKind::WithId(tid) => self.current_mem_tid = tid,
},
// technically, this variant is deprecated in favor of vCont...
Op::StepContinue => match cmd.thread.tid {
- IdKind::Any => {
- self.current_resume_tid =
- SpecificIdKind::WithId(self.get_sane_any_tid(target)?)
- }
+ IdKind::Any => match self.get_sane_any_tid(target)? {
+ Some(tid) => self.current_resume_tid = SpecificIdKind::WithId(tid),
+ None => {
+ return Err(Error::NonFatalError(1));
+ }
+ },
IdKind::All => self.current_resume_tid = SpecificIdKind::All,
IdKind::WithId(tid) => {
self.current_resume_tid = SpecificIdKind::WithId(tid)
@@ -323,13 +364,14 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
}
Base::qfThreadInfo(_) => {
res.write_str("m")?;
+ let pid = self.get_current_pid(target)?;
match target.base_ops() {
BaseOps::SingleThread(_) => res.write_specific_thread_id(SpecificThreadId {
pid: self
.features
.multiprocess()
- .then_some(SpecificIdKind::WithId(FAKE_PID)),
+ .then_some(SpecificIdKind::WithId(pid)),
tid: SpecificIdKind::WithId(SINGLE_THREAD_TID),
})?,
BaseOps::MultiThread(ops) => {
@@ -346,7 +388,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
pid: self
.features
.multiprocess()
- .then_some(SpecificIdKind::WithId(FAKE_PID)),
+ .then_some(SpecificIdKind::WithId(pid)),
tid: SpecificIdKind::WithId(tid),
})?;
Ok(())
diff --git a/src/stub/core_impl/breakpoints.rs b/src/stub/core_impl/breakpoints.rs
index a54da71..3b45eff 100644
--- a/src/stub/core_impl/breakpoints.rs
+++ b/src/stub/core_impl/breakpoints.rs
@@ -1,8 +1,8 @@
use super::prelude::*;
+use crate::arch::Arch;
+use crate::arch::BreakpointKind;
use crate::protocol::commands::ext::Breakpoints;
-use crate::arch::{Arch, BreakpointKind};
-
enum CmdKind {
Add,
Remove,
diff --git a/src/stub/core_impl/catch_syscalls.rs b/src/stub/core_impl/catch_syscalls.rs
index b7dde2e..7f38222 100644
--- a/src/stub/core_impl/catch_syscalls.rs
+++ b/src/stub/core_impl/catch_syscalls.rs
@@ -1,8 +1,7 @@
use super::prelude::*;
-use crate::protocol::commands::ext::CatchSyscalls;
-
use crate::arch::Arch;
use crate::protocol::commands::_QCatchSyscalls::QCatchSyscalls;
+use crate::protocol::commands::ext::CatchSyscalls;
use crate::target::ext::catch_syscalls::SyscallNumbers;
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
diff --git a/src/stub/core_impl/extended_mode.rs b/src/stub/core_impl/extended_mode.rs
index dbe3913..703b3f8 100644
--- a/src/stub/core_impl/extended_mode.rs
+++ b/src/stub/core_impl/extended_mode.rs
@@ -1,5 +1,9 @@
use super::prelude::*;
use crate::protocol::commands::ext::ExtendedMode;
+use crate::protocol::SpecificIdKind;
+use crate::protocol::SpecificThreadId;
+use crate::target::ext::base::BaseOps;
+use crate::SINGLE_THREAD_TID;
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
pub(crate) fn handle_extended_mode(
@@ -25,9 +29,56 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
HandlerStatus::Handled
}
ExtendedMode::vAttach(cmd) => {
+ if ops.support_current_active_pid().is_none() {
+ return Err(Error::MissingCurrentActivePidImpl);
+ }
+
ops.attach(cmd.pid).handle_error()?;
+ self.report_reasonable_stop_reason(res, target)?
+ }
+ ExtendedMode::qC(_cmd) if ops.support_current_active_pid().is_some() => {
+ let ops = ops.support_current_active_pid().unwrap();
+
+ res.write_str("QC")?;
+ let pid = ops.current_active_pid().map_err(Error::TargetError)?;
+ let tid = match target.base_ops() {
+ BaseOps::SingleThread(_) => SINGLE_THREAD_TID,
+ BaseOps::MultiThread(ops) => {
+ // HACK: gdbstub should avoid using a sentinel value here...
+ if self.current_mem_tid == SINGLE_THREAD_TID {
+ let mut err: Result<_, Error<T::Error, C::Error>> = Ok(());
+ let mut first_tid = None;
+ ops.list_active_threads(&mut |tid| {
+ // TODO: replace this with a try block (once stabilized)
+ let e = (|| {
+ if first_tid.is_some() {
+ return Ok(());
+ }
+ first_tid = Some(tid);
+ Ok(())
+ })();
+
+ if let Err(e) = e {
+ err = Err(e)
+ }
+ })
+ .map_err(Error::TargetError)?;
+ err?;
+ first_tid.unwrap_or(SINGLE_THREAD_TID)
+ } else {
+ self.current_mem_tid
+ }
+ }
+ };
+
+ res.write_specific_thread_id(SpecificThreadId {
+ pid: self
+ .features
+ .multiprocess()
+ .then_some(SpecificIdKind::WithId(pid)),
+ tid: SpecificIdKind::WithId(tid),
+ })?;
- // TODO: sends OK when running in Non-Stop mode
HandlerStatus::Handled
}
ExtendedMode::vRun(cmd) => {
@@ -37,10 +88,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
.run(cmd.filename, Args::new(&mut cmd.args.into_iter()))
.handle_error()?;
- // This is a reasonable response, as the `run` handler must
- // spawn the process in a stopped state.
- res.write_str("S05")?;
- HandlerStatus::Handled
+ self.report_reasonable_stop_reason(res, target)?
}
// --------- ASLR --------- //
ExtendedMode::QDisableRandomization(cmd) if ops.support_configure_aslr().is_some() => {
@@ -78,6 +126,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
ops.cfg_startup_with_shell(cmd.value).handle_error()?;
HandlerStatus::NeedsOk
}
+
_ => HandlerStatus::Handled,
};
diff --git a/src/stub/core_impl/host_io.rs b/src/stub/core_impl/host_io.rs
index 4ea6b1a..f62bf66 100644
--- a/src/stub/core_impl/host_io.rs
+++ b/src/stub/core_impl/host_io.rs
@@ -1,8 +1,8 @@
use super::prelude::*;
-use crate::protocol::commands::ext::HostIo;
-
use crate::arch::Arch;
-use crate::target::ext::host_io::{HostIoError, HostIoStat};
+use crate::protocol::commands::ext::HostIo;
+use crate::target::ext::host_io::HostIoError;
+use crate::target::ext::host_io::HostIoStat;
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
pub(crate) fn handle_host_io(
diff --git a/src/stub/core_impl/lldb_register_info.rs b/src/stub/core_impl/lldb_register_info.rs
index 2b27f7c..676991d 100644
--- a/src/stub/core_impl/lldb_register_info.rs
+++ b/src/stub/core_impl/lldb_register_info.rs
@@ -1,8 +1,11 @@
use super::prelude::*;
-use crate::protocol::commands::ext::LldbRegisterInfo;
-
-use crate::arch::lldb::{Encoding, Format, Generic, Register, RegisterInfo as LLDBRegisterInfo};
+use crate::arch::lldb::Encoding;
+use crate::arch::lldb::Format;
+use crate::arch::lldb::Generic;
+use crate::arch::lldb::Register;
+use crate::arch::lldb::RegisterInfo as LLDBRegisterInfo;
use crate::arch::Arch;
+use crate::protocol::commands::ext::LldbRegisterInfo;
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
pub(crate) fn handle_lldb_register_info(
@@ -112,9 +115,8 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
}
};
if let Some(ops) = target.support_lldb_register_info_override() {
- use crate::target::ext::lldb_register_info_override::{
- Callback, CallbackToken,
- };
+ use crate::target::ext::lldb_register_info_override::Callback;
+ use crate::target::ext::lldb_register_info_override::CallbackToken;
ops.lldb_register_info(
cmd.reg_id,
diff --git a/src/stub/core_impl/monitor_cmd.rs b/src/stub/core_impl/monitor_cmd.rs
index 50425a2..e4cfc1e 100644
--- a/src/stub/core_impl/monitor_cmd.rs
+++ b/src/stub/core_impl/monitor_cmd.rs
@@ -1,6 +1,5 @@
use super::prelude::*;
use crate::protocol::commands::ext::MonitorCmd;
-
use crate::protocol::ConsoleOutput;
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
diff --git a/src/stub/core_impl/no_ack_mode.rs b/src/stub/core_impl/no_ack_mode.rs
new file mode 100644
index 0000000..48b5173
--- /dev/null
+++ b/src/stub/core_impl/no_ack_mode.rs
@@ -0,0 +1,25 @@
+use super::prelude::*;
+use crate::protocol::commands::ext::NoAckMode;
+
+impl<T: Target, C: Connection> GdbStubImpl<T, C> {
+ pub(crate) fn handle_no_ack_mode(
+ &mut self,
+ _res: &mut ResponseWriter<'_, C>,
+ target: &mut T,
+ command: NoAckMode,
+ ) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
+ if !target.use_no_ack_mode() {
+ return Ok(HandlerStatus::Handled);
+ }
+
+ crate::__dead_code_marker!("no_ack_mode", "impl");
+
+ let handler_status = match command {
+ NoAckMode::QStartNoAckMode(_) => {
+ self.features.set_no_ack_mode(true);
+ HandlerStatus::NeedsOk
+ }
+ };
+ Ok(handler_status)
+ }
+}
diff --git a/src/stub/core_impl/resume.rs b/src/stub/core_impl/resume.rs
index e63381a..1a06e0b 100644
--- a/src/stub/core_impl/resume.rs
+++ b/src/stub/core_impl/resume.rs
@@ -1,17 +1,16 @@
use super::prelude::*;
-use crate::protocol::commands::ext::Resume;
-
+use super::DisconnectReason;
use crate::arch::Arch;
-use crate::common::{Signal, Tid};
+use crate::common::Signal;
+use crate::common::Tid;
use crate::protocol::commands::_vCont::Actions;
-use crate::protocol::{SpecificIdKind, SpecificThreadId};
+use crate::protocol::commands::ext::Resume;
+use crate::protocol::SpecificIdKind;
+use crate::protocol::SpecificThreadId;
use crate::stub::MultiThreadStopReason;
use crate::target::ext::base::reverse_exec::ReplayLogPosition;
use crate::target::ext::base::ResumeOps;
use crate::target::ext::catch_syscalls::CatchSyscallPosition;
-use crate::FAKE_PID;
-
-use super::DisconnectReason;
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
pub(crate) fn handle_stop_resume(
@@ -230,8 +229,16 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
// TODO: update this case when non-stop mode is implemented
VContKind::Stop => return Err(Error::PacketUnexpected),
+ // GDB doesn't always respect `vCont?` responses that omit `;s;S`, and will try to
+ // send step packets regardless. Inform the user of this bug by issuing a
+ // `UnexpectedStepPacket` error, which is more useful than a generic
+ // `PacketUnexpected` error.
+ VContKind::Step | VContKind::StepWithSig(..) => {
+ return Err(Error::UnexpectedStepPacket)
+ }
+
// Instead of using `_ =>`, explicitly list out any remaining unguarded cases.
- VContKind::RangeStep(..) | VContKind::Step | VContKind::StepWithSig(..) => {
+ VContKind::RangeStep(..) => {
error!("GDB client sent resume action not reported by `vCont?`");
return Err(Error::PacketUnexpected);
}
@@ -257,11 +264,12 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
fn write_stop_common(
&mut self,
res: &mut ResponseWriter<'_, C>,
+ target: &mut T,
tid: Option<Tid>,
signal: Signal,
) -> Result<(), Error<T::Error, C::Error>> {
res.write_str("T")?;
- res.write_num(signal as u8)?;
+ res.write_num(signal.0)?;
if let Some(tid) = tid {
self.current_mem_tid = tid;
@@ -272,7 +280,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
pid: self
.features
.multiprocess()
- .then_some(SpecificIdKind::WithId(FAKE_PID)),
+ .then_some(SpecificIdKind::WithId(self.get_current_pid(target)?)),
tid: SpecificIdKind::WithId(tid),
})?;
res.write_str(";")?;
@@ -326,12 +334,12 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
let status = match stop_reason {
MultiThreadStopReason::DoneStep => {
res.write_str("S")?;
- res.write_num(Signal::SIGTRAP as u8)?;
+ res.write_num(Signal::SIGTRAP.0)?;
FinishExecStatus::Handled
}
MultiThreadStopReason::Signal(sig) => {
res.write_str("S")?;
- res.write_num(sig as u8)?;
+ res.write_num(sig.0)?;
FinishExecStatus::Handled
}
MultiThreadStopReason::Exited(code) => {
@@ -341,24 +349,24 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
}
MultiThreadStopReason::Terminated(sig) => {
res.write_str("X")?;
- res.write_num(sig as u8)?;
+ res.write_num(sig.0)?;
FinishExecStatus::Disconnect(DisconnectReason::TargetTerminated(sig))
}
MultiThreadStopReason::SignalWithThread { tid, signal } => {
- self.write_stop_common(res, Some(tid), signal)?;
+ self.write_stop_common(res, target, Some(tid), signal)?;
FinishExecStatus::Handled
}
MultiThreadStopReason::SwBreak(tid) if guard_break!(support_sw_breakpoint) => {
crate::__dead_code_marker!("sw_breakpoint", "stop_reason");
- self.write_stop_common(res, Some(tid), Signal::SIGTRAP)?;
+ self.write_stop_common(res, target, Some(tid), Signal::SIGTRAP)?;
res.write_str("swbreak:;")?;
FinishExecStatus::Handled
}
MultiThreadStopReason::HwBreak(tid) if guard_break!(support_hw_breakpoint) => {
crate::__dead_code_marker!("hw_breakpoint", "stop_reason");
- self.write_stop_common(res, Some(tid), Signal::SIGTRAP)?;
+ self.write_stop_common(res, target, Some(tid), Signal::SIGTRAP)?;
res.write_str("hwbreak:;")?;
FinishExecStatus::Handled
}
@@ -367,7 +375,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
{
crate::__dead_code_marker!("hw_watchpoint", "stop_reason");
- self.write_stop_common(res, Some(tid), Signal::SIGTRAP)?;
+ self.write_stop_common(res, target, Some(tid), Signal::SIGTRAP)?;
use crate::target::ext::breakpoints::WatchKind;
match kind {
@@ -382,7 +390,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
MultiThreadStopReason::ReplayLog { tid, pos } if guard_reverse_exec!() => {
crate::__dead_code_marker!("reverse_exec", "stop_reason");
- self.write_stop_common(res, tid, Signal::SIGTRAP)?;
+ self.write_stop_common(res, target, tid, Signal::SIGTRAP)?;
res.write_str("replaylog:")?;
res.write_str(match pos {
@@ -400,7 +408,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
} if guard_catch_syscall!() => {
crate::__dead_code_marker!("catch_syscall", "stop_reason");
- self.write_stop_common(res, tid, Signal::SIGTRAP)?;
+ self.write_stop_common(res, target, tid, Signal::SIGTRAP)?;
res.write_str(match position {
CatchSyscallPosition::Entry => "syscall_entry:",
diff --git a/src/stub/core_impl/reverse_exec.rs b/src/stub/core_impl/reverse_exec.rs
index 7b85d38..e7269a3 100644
--- a/src/stub/core_impl/reverse_exec.rs
+++ b/src/stub/core_impl/reverse_exec.rs
@@ -1,12 +1,11 @@
use super::prelude::*;
-use crate::protocol::commands::ext::{ReverseCont, ReverseStep};
-
use crate::arch::Arch;
use crate::common::Tid;
+use crate::protocol::commands::ext::ReverseCont;
+use crate::protocol::commands::ext::ReverseStep;
use crate::protocol::SpecificIdKind;
-use crate::target::ext::base::reverse_exec::{
- ReverseCont as ReverseContTrait, ReverseStep as ReverseStepTrait,
-};
+use crate::target::ext::base::reverse_exec::ReverseCont as ReverseContTrait;
+use crate::target::ext::base::reverse_exec::ReverseStep as ReverseStepTrait;
use crate::target::ext::base::ResumeOps;
macro_rules! defn_ops {
diff --git a/src/stub/core_impl/single_register_access.rs b/src/stub/core_impl/single_register_access.rs
index 954a634..093e7f5 100644
--- a/src/stub/core_impl/single_register_access.rs
+++ b/src/stub/core_impl/single_register_access.rs
@@ -1,7 +1,7 @@
use super::prelude::*;
+use crate::arch::Arch;
+use crate::arch::RegId;
use crate::protocol::commands::ext::SingleRegisterAccess;
-
-use crate::arch::{Arch, RegId};
use crate::target::ext::base::BaseOps;
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
diff --git a/src/stub/core_impl/target_xml.rs b/src/stub/core_impl/target_xml.rs
index 2650ad2..bf3fc5c 100644
--- a/src/stub/core_impl/target_xml.rs
+++ b/src/stub/core_impl/target_xml.rs
@@ -1,7 +1,6 @@
use super::prelude::*;
-use crate::protocol::commands::ext::TargetXml;
-
use crate::arch::Arch;
+use crate::protocol::commands::ext::TargetXml;
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
pub(crate) fn handle_target_xml(
diff --git a/src/stub/core_impl/x_upcase_packet.rs b/src/stub/core_impl/x_upcase_packet.rs
index 9d865e5..aa36a44 100644
--- a/src/stub/core_impl/x_upcase_packet.rs
+++ b/src/stub/core_impl/x_upcase_packet.rs
@@ -1,7 +1,6 @@
use super::prelude::*;
-use crate::protocol::commands::ext::XUpcasePacket;
-
use crate::arch::Arch;
+use crate::protocol::commands::ext::XUpcasePacket;
use crate::target::ext::base::BaseOps;
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
diff --git a/src/stub/error.rs b/src/stub/error.rs
index 6d55997..8cdc18e 100644
--- a/src/stub/error.rs
+++ b/src/stub/error.rs
@@ -1,62 +1,42 @@
-use core::fmt::{self, Debug, Display};
-
-use crate::arch::SingleStepGdbBehavior;
-use crate::protocol::{PacketParseError, ResponseWriterError};
+use crate::protocol::PacketParseError;
+use crate::protocol::ResponseWriterError;
use crate::util::managed_vec::CapacityError;
+use core::fmt::Debug;
+use core::fmt::Display;
+use core::fmt::{self};
+
+/// An error that may occur while interacting with a
+/// [`Connection`](crate::conn::Connection).
+#[derive(Debug)]
+pub enum ConnectionErrorKind {
+ /// Error initializing the session.
+ Init,
+ /// Error reading data.
+ Read,
+ /// Error writing data.
+ Write,
+}
-/// An error which may occur during a GDB debugging session.
#[derive(Debug)]
-#[non_exhaustive]
-pub enum GdbStubError<T, C> {
- /// Connection Error while initializing the session.
- ConnectionInit(C),
- /// Connection Error while reading request.
- ConnectionRead(C),
- /// Connection Error while writing response.
- ConnectionWrite(C),
-
- /// Client nack'd the last packet, but `gdbstub` doesn't implement
- /// re-transmission.
+pub(crate) enum InternalError<T, C> {
+ /// Connection Error
+ Connection(C, ConnectionErrorKind),
+ /// Target encountered a fatal error.
+ TargetError(T),
+
ClientSentNack,
- /// Packet cannot fit in the provided packet buffer.
PacketBufferOverflow,
- /// Could not parse the packet into a valid command.
PacketParse(PacketParseError),
- /// GDB client sent an unexpected packet. This should never happen!
- /// Please re-run with `log` trace-level logging enabled and file an issue
- /// at <https://github.com/daniel5151/gdbstub/issues>
PacketUnexpected,
- /// GDB client sent a packet with too much data for the given target.
TargetMismatch,
- /// Target encountered a fatal error.
- TargetError(T),
- /// Target responded with an unsupported stop reason.
- ///
- /// Certain stop reasons can only be used when their associated protocol
- /// feature has been implemented. e.g: a Target cannot return a
- /// `StopReason::HwBreak` if the hardware breakpoints IDET hasn't been
- /// implemented.
UnsupportedStopReason,
- /// Target didn't report any active threads when there should have been at
- /// least one running.
- NoActiveThreads,
-
- /// The target has not opted into using implicit software breakpoints.
- /// See [`Target::guard_rail_implicit_sw_breakpoints`] for more information.
- ///
- /// [`Target::guard_rail_implicit_sw_breakpoints`]:
- /// crate::target::Target::guard_rail_implicit_sw_breakpoints
+ UnexpectedStepPacket,
ImplicitSwBreakpoints,
- /// The target has not indicated support for optional single stepping. See
- /// [`Target::guard_rail_single_step_gdb_behavior`] for more information.
- ///
- /// If you encountered this error while using an `Arch` implementation
- /// defined in `gdbstub_arch` and believe this is incorrect, please file an
- /// issue at <https://github.com/daniel5151/gdbstub/issues>.
- ///
- /// [`Target::guard_rail_single_step_gdb_behavior`]:
- /// crate::target::Target::guard_rail_single_step_gdb_behavior
- SingleStepGdbBehavior(SingleStepGdbBehavior),
+ // DEVNOTE: this is a temporary workaround for something that can and should
+ // be caught at compile time via IDETs. That said, since i'm not sure when
+ // I'll find the time to cut a breaking release of gdbstub, I'd prefer to
+ // push out this feature as a non-breaking change now.
+ MissingCurrentActivePidImpl,
// Internal - A non-fatal error occurred (with errno-style error code)
//
@@ -67,55 +47,100 @@ pub enum GdbStubError<T, C> {
NonFatalError(u8),
}
-impl<T, C> From<ResponseWriterError<C>> for GdbStubError<T, C> {
- fn from(e: ResponseWriterError<C>) -> Self {
- GdbStubError::ConnectionWrite(e.0)
+impl<T, C> InternalError<T, C> {
+ pub fn conn_read(e: C) -> Self {
+ InternalError::Connection(e, ConnectionErrorKind::Read)
+ }
+
+ pub fn conn_write(e: C) -> Self {
+ InternalError::Connection(e, ConnectionErrorKind::Write)
+ }
+
+ pub fn conn_init(e: C) -> Self {
+ InternalError::Connection(e, ConnectionErrorKind::Init)
}
}
-impl<A, T, C> From<CapacityError<A>> for GdbStubError<T, C> {
- fn from(_: CapacityError<A>) -> Self {
- GdbStubError::PacketBufferOverflow
+impl<T, C> From<ResponseWriterError<C>> for InternalError<T, C> {
+ fn from(e: ResponseWriterError<C>) -> Self {
+ InternalError::Connection(e.0, ConnectionErrorKind::Write)
}
}
+// these macros are used to keep the docs and `Display` impl in-sync
+
+macro_rules! unsupported_stop_reason {
+ () => {
+ "User error: cannot report stop reason without also implementing its corresponding IDET"
+ };
+}
+
+macro_rules! unexpected_step_packet {
+ () => {
+ "Received an unexpected `step` request. This is most-likely due to this GDB client bug: <https://sourceware.org/bugzilla/show_bug.cgi?id=28440>"
+ };
+}
+
+/// An error which may occur during a GDB debugging session.
+///
+/// ## Additional Notes
+///
+/// `GdbStubError`'s inherent `Display` impl typically contains enough context
+/// for users to understand why the error occurred.
+///
+/// That said, there are a few instances where the error condition requires
+/// additional context.
+///
+/// * * *
+#[doc = concat!("_", unsupported_stop_reason!(), "_")]
+///
+/// This is a not a bug with `gdbstub`. Rather, this is indicative of a bug in
+/// your `gdbstub` integration.
+///
+/// Certain stop reasons can only be used when their associated protocol feature
+/// has been implemented. e.g: a Target cannot return a `StopReason::HwBreak` if
+/// the hardware breakpoints IDET hasn't been implemented.
+///
+/// Please double-check that you've implemented all the necessary `supports_`
+/// methods related to the stop reason you're trying to report.
+///
+/// * * *
+#[doc = concat!("_", unexpected_step_packet!(), "_")]
+///
+/// Unfortunately, there's nothing `gdbstub` can do to work around this bug.
+///
+/// Until the issue is fixed upstream, certain architectures are essentially
+/// forced to manually implement single-step support.
+#[derive(Debug)]
+pub struct GdbStubError<T, C> {
+ kind: InternalError<T, C>,
+}
+
impl<T, C> Display for GdbStubError<T, C>
where
- C: Debug,
- T: Debug,
+ C: Display,
+ T: Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- use self::GdbStubError::*;
- match self {
- ConnectionInit(e) => write!(f, "Connection Error while initializing the session: {:?}", e),
- ConnectionRead(e) => write!(f, "Connection Error while reading request: {:?}", e),
- ConnectionWrite(e) => write!(f, "Connection Error while writing response: {:?}", e),
+ use self::InternalError::*;
+ const CONTEXT: &str = "See the `GdbStubError` docs for more details";
+ match &self.kind {
+ Connection(e, ConnectionErrorKind::Init) => write!(f, "Connection Error while initializing the session: {}", e),
+ Connection(e, ConnectionErrorKind::Read) => write!(f, "Connection Error while reading request: {}", e),
+ Connection(e, ConnectionErrorKind::Write) => write!(f, "Connection Error while writing response: {}", e),
ClientSentNack => write!(f, "Client nack'd the last packet, but `gdbstub` doesn't implement re-transmission."),
- PacketBufferOverflow => write!(f, "Packet too big for provided buffer!"),
- PacketParse(e) => write!(f, "Could not parse the packet into a valid command: {:?}", e),
- PacketUnexpected => write!(f, "Client sent an unexpected packet. Please re-run with `log` trace-level logging enabled and file an issue at https://github.com/daniel5151/gdbstub/issues"),
- TargetMismatch => write!(f, "GDB client sent a packet with too much data for the given target."),
- TargetError(e) => write!(f, "Target threw a fatal error: {:?}", e),
- UnsupportedStopReason => write!(f, "Target responded with an unsupported stop reason."),
- NoActiveThreads => write!(f, "Target didn't report any active threads when there should have been at least one running."),
-
- ImplicitSwBreakpoints => write!(f, "Warning: The target has not opted into using implicit software breakpoints. See `Target::guard_rail_implicit_sw_breakpoints` for more information."),
- SingleStepGdbBehavior(behavior) => {
- use crate::arch::SingleStepGdbBehavior;
- write!(
- f,
- "Warning: Mismatch between the targets' single-step support and arch-level single-step behavior: {} ",
- match behavior {
- SingleStepGdbBehavior::Optional => "", // unreachable, since optional single step will not result in an error
- SingleStepGdbBehavior::Required => "GDB requires single-step support on this arch.",
- SingleStepGdbBehavior::Ignored => "GDB ignores single-step support on this arch, yet the target has implemented support for it.",
- SingleStepGdbBehavior::Unknown => "This arch's single-step behavior hasn't been tested yet: please conduct a test + upstream your findings!",
- }
- )?;
- write!(f, "See `Target::guard_rail_single_step_gdb_behavior` for more information.")
- },
-
- NonFatalError(_) => write!(f, "Internal non-fatal error. End users should never see this! Please file an issue if you do!"),
+ PacketBufferOverflow => write!(f, "Received an oversized packet (did not fit in provided packet buffer)"),
+ PacketParse(e) => write!(f, "Failed to parse packet into a valid command: {:?}", e),
+ PacketUnexpected => write!(f, "Client sent an unexpected packet. This should never happen! Please re-run with `log` trace-level logging enabled and file an issue at https://github.com/daniel5151/gdbstub/issues"),
+ TargetMismatch => write!(f, "Received a packet with too much data for the given target"),
+ TargetError(e) => write!(f, "Target threw a fatal error: {}", e),
+ UnsupportedStopReason => write!(f, "{} {}", unsupported_stop_reason!(), CONTEXT),
+ UnexpectedStepPacket => write!(f, "{} {}", unexpected_step_packet!(), CONTEXT),
+
+ ImplicitSwBreakpoints => write!(f, "Warning: The target has not opted into using implicit software breakpoints. See `Target::guard_rail_implicit_sw_breakpoints` for more information"),
+ MissingCurrentActivePidImpl => write!(f, "GDB client attempted to attach to a new process, but the target has not implemented support for `ExtendedMode::support_current_active_pid`"),
+
+ NonFatalError(_) => write!(f, "Internal non-fatal error. You should never see this! Please file an issue if you do!"),
}
}
}
@@ -123,7 +148,48 @@ where
#[cfg(feature = "std")]
impl<T, C> std::error::Error for GdbStubError<T, C>
where
- C: Debug,
- T: Debug,
+ C: Debug + Display,
+ T: Debug + Display,
{
}
+
+impl<T, C> GdbStubError<T, C> {
+ /// Check if the error was due to a target error.
+ pub fn is_target_error(&self) -> bool {
+ matches!(self.kind, InternalError::TargetError(..))
+ }
+
+ /// If the error was due to a target error, return the concrete error type.
+ pub fn into_target_error(self) -> Option<T> {
+ match self.kind {
+ InternalError::TargetError(e) => Some(e),
+ _ => None,
+ }
+ }
+
+ /// Check if the error was due to a connection error.
+ pub fn is_connection_error(&self) -> bool {
+ matches!(self.kind, InternalError::Connection(..))
+ }
+
+ /// If the error was due to a connection error, return the concrete error
+ /// type.
+ pub fn into_connection_error(self) -> Option<(C, ConnectionErrorKind)> {
+ match self.kind {
+ InternalError::Connection(e, kind) => Some((e, kind)),
+ _ => None,
+ }
+ }
+}
+
+impl<T, C> From<InternalError<T, C>> for GdbStubError<T, C> {
+ fn from(kind: InternalError<T, C>) -> Self {
+ GdbStubError { kind }
+ }
+}
+
+impl<A, T, C> From<CapacityError<A>> for GdbStubError<T, C> {
+ fn from(_: CapacityError<A>) -> Self {
+ InternalError::PacketBufferOverflow.into()
+ }
+}
diff --git a/src/stub/mod.rs b/src/stub/mod.rs
index 8cf08d9..b98c190 100644
--- a/src/stub/mod.rs
+++ b/src/stub/mod.rs
@@ -1,10 +1,14 @@
//! The core [`GdbStub`] type, used to drive a GDB debugging session for a
//! particular [`Target`] over a given [`Connection`].
-use managed::ManagedSlice;
-
-use crate::conn::{Connection, ConnectionExt};
-use crate::target::Target;
+pub use builder::GdbStubBuilder;
+pub use builder::GdbStubBuilderError;
+pub use core_impl::DisconnectReason;
+pub use error::GdbStubError;
+pub use stop_reason::BaseStopReason;
+pub use stop_reason::IntoStopReason;
+pub use stop_reason::MultiThreadStopReason;
+pub use stop_reason::SingleThreadStopReason;
mod builder;
mod core_impl;
@@ -13,19 +17,15 @@ mod stop_reason;
pub mod state_machine;
-pub use builder::{GdbStubBuilder, GdbStubBuilderError};
-pub use core_impl::DisconnectReason;
-pub use error::GdbStubError;
-pub use stop_reason::{
- BaseStopReason, IntoStopReason, MultiThreadStopReason, SingleThreadStopReason,
-};
-
-use GdbStubError as Error;
+use self::error::InternalError;
+use crate::conn::Connection;
+use crate::conn::ConnectionExt;
+use crate::target::Target;
+use managed::ManagedSlice;
/// Types and traits related to the [`GdbStub::run_blocking`] interface.
pub mod run_blocking {
use super::*;
-
use crate::conn::ConnectionExt;
/// A set of user-provided methods required to run a GDB debugging session
@@ -157,7 +157,7 @@ impl<'a, T: Target, C: Connection> GdbStub<'a, T, C> {
pub fn run_blocking<E>(
self,
target: &mut T,
- ) -> Result<DisconnectReason, Error<T::Error, C::Error>>
+ ) -> Result<DisconnectReason, GdbStubError<T::Error, C::Error>>
where
C: ConnectionExt,
E: run_blocking::BlockingEventLoop<Target = T, Connection = C>,
@@ -167,7 +167,7 @@ impl<'a, T: Target, C: Connection> GdbStub<'a, T, C> {
gdb = match gdb {
state_machine::GdbStubStateMachine::Idle(mut gdb) => {
// needs more data, so perform a blocking read on the connection
- let byte = gdb.borrow_conn().read().map_err(Error::ConnectionRead)?;
+ let byte = gdb.borrow_conn().read().map_err(InternalError::conn_read)?;
gdb.incoming_data(target, byte)?
}
@@ -179,12 +179,14 @@ impl<'a, T: Target, C: Connection> GdbStub<'a, T, C> {
state_machine::GdbStubStateMachine::CtrlCInterrupt(gdb) => {
// defer to the implementation on how it wants to handle the interrupt
- let stop_reason = E::on_interrupt(target).map_err(Error::TargetError)?;
+ let stop_reason =
+ E::on_interrupt(target).map_err(InternalError::TargetError)?;
gdb.interrupt_handled(target, stop_reason)?
}
state_machine::GdbStubStateMachine::Running(mut gdb) => {
- use run_blocking::{Event as BlockingEventLoopEvent, WaitForStopReasonError};
+ use run_blocking::Event as BlockingEventLoopEvent;
+ use run_blocking::WaitForStopReasonError;
// block waiting for the target to return a stop reason
let event = E::wait_for_stop_reason(target, gdb.borrow_conn());
@@ -198,10 +200,10 @@ impl<'a, T: Target, C: Connection> GdbStub<'a, T, C> {
}
Err(WaitForStopReasonError::Target(e)) => {
- break Err(Error::TargetError(e));
+ break Err(InternalError::TargetError(e).into());
}
Err(WaitForStopReasonError::Connection(e)) => {
- break Err(Error::ConnectionRead(e));
+ break Err(InternalError::conn_read(e).into());
}
}
}
@@ -216,7 +218,8 @@ impl<'a, T: Target, C: Connection> GdbStub<'a, T, C> {
pub fn run_state_machine(
mut self,
target: &mut T,
- ) -> Result<state_machine::GdbStubStateMachine<'a, T, C>, Error<T::Error, C::Error>> {
+ ) -> Result<state_machine::GdbStubStateMachine<'a, T, C>, GdbStubError<T::Error, C::Error>>
+ {
// Check if the target hasn't explicitly opted into implicit sw breakpoints
{
let support_software_breakpoints = target
@@ -225,33 +228,7 @@ impl<'a, T: Target, C: Connection> GdbStub<'a, T, C> {
.unwrap_or(false);
if !support_software_breakpoints && !target.guard_rail_implicit_sw_breakpoints() {
- return Err(Error::ImplicitSwBreakpoints);
- }
- }
-
- // Check how the target's arch handles single stepping
- {
- use crate::arch::SingleStepGdbBehavior;
- use crate::target::ext::base::ResumeOps;
-
- if let Some(ops) = target.base_ops().resume_ops() {
- let support_single_step = match ops {
- ResumeOps::SingleThread(ops) => ops.support_single_step().is_some(),
- ResumeOps::MultiThread(ops) => ops.support_single_step().is_some(),
- };
-
- let behavior = target.guard_rail_single_step_gdb_behavior();
-
- let return_error = match behavior {
- SingleStepGdbBehavior::Optional => false,
- SingleStepGdbBehavior::Required => !support_single_step,
- SingleStepGdbBehavior::Ignored => support_single_step,
- SingleStepGdbBehavior::Unknown => true,
- };
-
- if return_error {
- return Err(Error::SingleStepGdbBehavior(behavior));
- }
+ return Err(InternalError::ImplicitSwBreakpoints.into());
}
}
@@ -259,7 +236,7 @@ impl<'a, T: Target, C: Connection> GdbStub<'a, T, C> {
{
self.conn
.on_session_start()
- .map_err(Error::ConnectionInit)?;
+ .map_err(InternalError::conn_init)?;
}
Ok(state_machine::GdbStubStateMachineInner::from_plain_gdbstub(self).into())
diff --git a/src/stub/state_machine.rs b/src/stub/state_machine.rs
index 766d343..7b623dd 100644
--- a/src/stub/state_machine.rs
+++ b/src/stub/state_machine.rs
@@ -33,18 +33,21 @@
//! [`BlockingEventLoop`]: super::run_blocking::BlockingEventLoop
//! [`GdbStub::run_blocking`]: super::GdbStub::run_blocking
-use managed::ManagedSlice;
-
+use super::core_impl::FinishExecStatus;
+use super::core_impl::GdbStubImpl;
+use super::core_impl::State;
+use super::DisconnectReason;
+use super::GdbStub;
use crate::arch::Arch;
use crate::conn::Connection;
use crate::protocol::recv_packet::RecvPacketStateMachine;
-use crate::protocol::{Packet, ResponseWriter};
-use crate::stub::error::GdbStubError as Error;
+use crate::protocol::Packet;
+use crate::protocol::ResponseWriter;
+use crate::stub::error::GdbStubError;
+use crate::stub::error::InternalError;
use crate::stub::stop_reason::IntoStopReason;
use crate::target::Target;
-
-use super::core_impl::{FinishExecStatus, GdbStubImpl, State};
-use super::{DisconnectReason, GdbStub};
+use managed::ManagedSlice;
/// State-machine interface to `GdbStub`.
///
@@ -78,7 +81,6 @@ where
// payloads, which are used when transitioning between states.
pub mod state {
use super::*;
-
use crate::stub::stop_reason::MultiThreadStopReason;
// used internally when logging state transitions
@@ -212,13 +214,13 @@ impl<'a, T: Target, C: Connection> GdbStubStateMachineInner<'a, state::Idle<T>,
mut self,
target: &mut T,
byte: u8,
- ) -> Result<GdbStubStateMachine<'a, T, C>, Error<T::Error, C::Error>> {
+ ) -> Result<GdbStubStateMachine<'a, T, C>, GdbStubError<T::Error, C::Error>> {
let packet_buffer = match self.i.recv_packet.pump(&mut self.i.packet_buffer, byte)? {
Some(buf) => buf,
None => return Ok(self.into()),
};
- let packet = Packet::from_buf(target, packet_buffer).map_err(Error::PacketParse)?;
+ let packet = Packet::from_buf(target, packet_buffer).map_err(InternalError::PacketParse)?;
let state = self
.i
.inner
@@ -254,10 +256,10 @@ impl<'a, T: Target, C: Connection> GdbStubStateMachineInner<'a, state::Running,
mut self,
target: &mut T,
reason: impl IntoStopReason<T>,
- ) -> Result<GdbStubStateMachine<'a, T, C>, Error<T::Error, C::Error>> {
+ ) -> Result<GdbStubStateMachine<'a, T, C>, GdbStubError<T::Error, C::Error>> {
let mut res = ResponseWriter::new(&mut self.i.conn, target.use_rle());
let event = self.i.inner.finish_exec(&mut res, target, reason.into())?;
- res.flush()?;
+ res.flush().map_err(InternalError::from)?;
Ok(match event {
FinishExecStatus::Handled => self
@@ -272,21 +274,17 @@ impl<'a, T: Target, C: Connection> GdbStubStateMachineInner<'a, state::Running,
}
/// Pass a byte to the GDB stub.
- ///
- /// NOTE: unlike the `incoming_data` method in the `state::Idle` state,
- /// this method does not perform any state transitions, and will
- /// return a `GdbStubStateMachineInner` in the `state::Running` state.
pub fn incoming_data(
mut self,
target: &mut T,
byte: u8,
- ) -> Result<GdbStubStateMachine<'a, T, C>, Error<T::Error, C::Error>> {
+ ) -> Result<GdbStubStateMachine<'a, T, C>, GdbStubError<T::Error, C::Error>> {
let packet_buffer = match self.i.recv_packet.pump(&mut self.i.packet_buffer, byte)? {
Some(buf) => buf,
None => return Ok(self.into()),
};
- let packet = Packet::from_buf(target, packet_buffer).map_err(Error::PacketParse)?;
+ let packet = Packet::from_buf(target, packet_buffer).map_err(InternalError::PacketParse)?;
let state = self
.i
.inner
@@ -333,7 +331,7 @@ impl<'a, T: Target, C: Connection> GdbStubStateMachineInner<'a, state::CtrlCInte
self,
target: &mut T,
stop_reason: Option<impl IntoStopReason<T>>,
- ) -> Result<GdbStubStateMachine<'a, T, C>, Error<T::Error, C::Error>> {
+ ) -> Result<GdbStubStateMachine<'a, T, C>, GdbStubError<T::Error, C::Error>> {
if self.state.from_idle {
// target is stopped - we cannot report the stop reason yet
Ok(self
diff --git a/src/target/ext/auxv.rs b/src/target/ext/auxv.rs
index c801af2..8760439 100644
--- a/src/target/ext/auxv.rs
+++ b/src/target/ext/auxv.rs
@@ -1,5 +1,6 @@
//! Access the target’s auxiliary vector.
-use crate::target::{Target, TargetResult};
+use crate::target::Target;
+use crate::target::TargetResult;
/// Target Extension - Access the target’s auxiliary vector.
pub trait Auxv: Target {
diff --git a/src/target/ext/base/multithread.rs b/src/target/ext/base/multithread.rs
index 693030e..e2293fd 100644
--- a/src/target/ext/base/multithread.rs
+++ b/src/target/ext/base/multithread.rs
@@ -3,7 +3,8 @@
use crate::arch::Arch;
use crate::common::Signal;
use crate::common::Tid;
-use crate::target::{Target, TargetResult};
+use crate::target::Target;
+use crate::target::TargetResult;
/// Base required debugging operations for multi threaded targets.
pub trait MultiThreadBase: Target {
@@ -43,17 +44,25 @@ pub trait MultiThreadBase: Target {
None
}
- /// Read bytes from the specified address range.
+ /// Read bytes from the specified address range and return the number of
+ /// bytes that were read.
///
- /// If the requested address range could not be accessed (e.g: due to
- /// MMU protection, unhanded page fault, etc...), an appropriate non-fatal
- /// error should be returned.
+ /// Implementations may return a number `n` that is less than `data.len()`
+ /// to indicate that memory starting at `start_addr + n` cannot be
+ /// accessed.
+ ///
+ /// Implemenations may also return an appropriate non-fatal error if the
+ /// requested address range could not be accessed (e.g: due to MMU
+ /// protection, unhanded page fault, etc...).
+ ///
+ /// Implementations must guarantee that the returned number is less than or
+ /// equal `data.len()`.
fn read_addrs(
&mut self,
start_addr: <Self::Arch as Arch>::Usize,
data: &mut [u8],
tid: Tid,
- ) -> TargetResult<(), Self>;
+ ) -> TargetResult<usize, Self>;
/// Write bytes to the specified address range.
///
diff --git a/src/target/ext/base/single_register_access.rs b/src/target/ext/base/single_register_access.rs
index 2887fef..efe06c0 100644
--- a/src/target/ext/base/single_register_access.rs
+++ b/src/target/ext/base/single_register_access.rs
@@ -1,7 +1,8 @@
//! Support for single-register read/write access.
use crate::arch::Arch;
-use crate::target::{Target, TargetResult};
+use crate::target::Target;
+use crate::target::TargetResult;
/// Target Extension - Support for single-register access.
///
diff --git a/src/target/ext/base/singlethread.rs b/src/target/ext/base/singlethread.rs
index c949886..40b002e 100644
--- a/src/target/ext/base/singlethread.rs
+++ b/src/target/ext/base/singlethread.rs
@@ -2,7 +2,8 @@
use crate::arch::Arch;
use crate::common::Signal;
-use crate::target::{Target, TargetResult};
+use crate::target::Target;
+use crate::target::TargetResult;
/// Base required debugging operations for single threaded targets.
pub trait SingleThreadBase: Target {
@@ -32,16 +33,24 @@ pub trait SingleThreadBase: Target {
None
}
- /// Read bytes from the specified address range.
+ /// Read bytes from the specified address range and return the number of
+ /// bytes that were read.
///
- /// If the requested address range could not be accessed (e.g: due to
- /// MMU protection, unhanded page fault, etc...), an appropriate
- /// non-fatal error should be returned.
+ /// Implementations may return a number `n` that is less than `data.len()`
+ /// to indicate that memory starting at `start_addr + n` cannot be
+ /// accessed.
+ ///
+ /// Implemenations may also return an appropriate non-fatal error if the
+ /// requested address range could not be accessed (e.g: due to MMU
+ /// protection, unhanded page fault, etc...).
+ ///
+ /// Implementations must guarantee that the returned number is less than or
+ /// equal `data.len()`.
fn read_addrs(
&mut self,
start_addr: <Self::Arch as Arch>::Usize,
data: &mut [u8],
- ) -> TargetResult<(), Self>;
+ ) -> TargetResult<usize, Self>;
/// Write bytes to the specified address range.
///
diff --git a/src/target/ext/breakpoints.rs b/src/target/ext/breakpoints.rs
index 8b40a04..cd44d99 100644
--- a/src/target/ext/breakpoints.rs
+++ b/src/target/ext/breakpoints.rs
@@ -1,7 +1,8 @@
//! Add/Remove various kinds of breakpoints.
use crate::arch::Arch;
-use crate::target::{Target, TargetResult};
+use crate::target::Target;
+use crate::target::TargetResult;
/// Target Extension - Set/Remove Breakpoints.
pub trait Breakpoints: Target {
diff --git a/src/target/ext/catch_syscalls.rs b/src/target/ext/catch_syscalls.rs
index 694d8ad..b5f0ee9 100644
--- a/src/target/ext/catch_syscalls.rs
+++ b/src/target/ext/catch_syscalls.rs
@@ -1,7 +1,8 @@
//! Enable or disable catching syscalls from the inferior process.
use crate::arch::Arch;
-use crate::target::{Target, TargetResult};
+use crate::target::Target;
+use crate::target::TargetResult;
/// Target Extension - Enable and disable catching syscalls from the inferior
/// process.
diff --git a/src/target/ext/exec_file.rs b/src/target/ext/exec_file.rs
index 0db9874..a819638 100644
--- a/src/target/ext/exec_file.rs
+++ b/src/target/ext/exec_file.rs
@@ -1,7 +1,7 @@
//! Provide exec-file path for the target.
-use crate::target::{Target, TargetResult};
-
use crate::common::Pid;
+use crate::target::Target;
+use crate::target::TargetResult;
/// Target Extension - Provide current exec-file.
///
diff --git a/src/target/ext/extended_mode.rs b/src/target/ext/extended_mode.rs
index 817bec0..2c162ed 100644
--- a/src/target/ext/extended_mode.rs
+++ b/src/target/ext/extended_mode.rs
@@ -1,21 +1,10 @@
//! Enables [Extended Mode](https://sourceware.org/gdb/current/onlinedocs/gdb/Connecting.html)
//! functionality when connecting using `target extended-remote`, such as
//! spawning new processes and/or attaching to existing processes.
-//!
-//! # Disclaimer
-//!
-//! While this API has been end-to-end tested and confirmed working with a "toy"
-//! target implementation (see the included `armv4t` example), it has _not_ been
-//! "battle-tested" with a fully-featured extended-mode capable target.
-//!
-//! If you end up using this API to implement an extended-mode capable target,
-//! _please_ file an issue on the repo detailing any bugs / usability issues you
-//! may encountered while implementing this API! If everything happens to Just
-//! Work as expected, nonetheless file an issue so that this disclaimer can be
-//! removed in future releases!
use crate::common::*;
-use crate::target::{Target, TargetResult};
+use crate::target::Target;
+use crate::target::TargetResult;
/// Returned from `ExtendedMode::kill`
///
@@ -92,6 +81,14 @@ pub trait ExtendedMode: Target {
/// Attach to a new process with the specified PID.
///
+ /// Targets that wish to use `attach` are required to implement
+ /// [`CurrentActivePid`] (via `support_current_active_pid`), as the default
+ /// `gdbstub` behavior of always reporting a Pid of `1` will cause issues
+ /// when attaching to new processes.
+ ///
+ /// _Note:_ In the next API-breaking release of `gdbstub`, this coupling
+ /// will become a compile-time checked invariant.
+ ///
/// In all-stop mode, all threads in the attached process are stopped; in
/// non-stop mode, it may be attached without being stopped (if that is
/// supported by the target).
@@ -171,6 +168,13 @@ pub trait ExtendedMode: Target {
fn support_configure_working_dir(&mut self) -> Option<ConfigureWorkingDirOps<'_, Self>> {
None
}
+
+ /// Support for reporting the current active Pid. Must be implemented in
+ /// order to use `attach`.
+ #[inline(always)]
+ fn support_current_active_pid(&mut self) -> Option<CurrentActivePidOps<'_, Self>> {
+ None
+ }
}
define_ext!(ExtendedModeOps, ExtendedMode);
@@ -265,3 +269,24 @@ pub trait ConfigureWorkingDir: ExtendedMode {
}
define_ext!(ConfigureWorkingDirOps, ConfigureWorkingDir);
+
+/// Nested Target extension - Return the current active Pid.
+pub trait CurrentActivePid: ExtendedMode {
+ /// Report the current active Pid.
+ ///
+ /// When implementing gdbstub on a platform that supports multiple
+ /// processes, the active PID needs to match the attached process. Failing
+ /// to do so will cause GDB to fail to attach to the target process.
+ ///
+ /// This should reflect the currently-debugged process which should be
+ /// updated when switching processes after calling
+ /// [`attach()`](ExtendedMode::attach).
+ ///
+ /// _Note:_ `gdbstub` doesn't yet support debugging multiple processes
+ /// _simultaneously_. If this is a feature you're interested in, please
+ /// leave a comment on this [tracking
+ /// issue](https://github.com/daniel5151/gdbstub/issues/124).
+ fn current_active_pid(&mut self) -> Result<Pid, Self::Error>;
+}
+
+define_ext!(CurrentActivePidOps, CurrentActivePid);
diff --git a/src/target/ext/host_io.rs b/src/target/ext/host_io.rs
index 77dbed0..1f5cfc6 100644
--- a/src/target/ext/host_io.rs
+++ b/src/target/ext/host_io.rs
@@ -1,17 +1,20 @@
//! Provide Host I/O operations for the target.
-use bitflags::bitflags;
-
use crate::arch::Arch;
use crate::target::Target;
+use bitflags::bitflags;
+
+/// Host flags for opening files.
+///
+/// Extracted from the GDB documentation at
+/// [Open Flags](https://sourceware.org/gdb/current/onlinedocs/gdb/Open-Flags.html#Open-Flags),
+/// and the LLDB source code at
+/// [`lldb/include/lldb/Host/File.h`](https://github.com/llvm/llvm-project/blob/ec642ceebc1aacc8b16249df7734b8cf90ae2963/lldb/include/lldb/Host/File.h#L47-L66)
+#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[repr(transparent)]
+pub struct HostIoOpenFlags(u32);
bitflags! {
- /// Host flags for opening files.
- ///
- /// Extracted from the GDB documentation at
- /// [Open Flags](https://sourceware.org/gdb/current/onlinedocs/gdb/Open-Flags.html#Open-Flags),
- /// and the LLDB source code at
- /// [`lldb/include/lldb/Host/File.h`](https://github.com/llvm/llvm-project/blob/ec642ceebc1aacc8b16249df7734b8cf90ae2963/lldb/include/lldb/Host/File.h#L47-L66)
- pub struct HostIoOpenFlags: u32 {
+ impl HostIoOpenFlags: u32 {
/// A read-only file.
const O_RDONLY = 0x0;
/// A write-only file.
@@ -38,12 +41,16 @@ bitflags! {
}
}
+/// Host file permissions.
+///
+/// Extracted from the GDB documentation at
+/// [mode_t Values](https://sourceware.org/gdb/current/onlinedocs/gdb/mode_005ft-Values.html#mode_005ft-Values)
+#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[repr(transparent)]
+pub struct HostIoOpenMode(u32);
+
bitflags! {
- /// Host file permissions.
- ///
- /// Extracted from the GDB documentation at
- /// [mode_t Values](https://sourceware.org/gdb/current/onlinedocs/gdb/mode_005ft-Values.html#mode_005ft-Values)
- pub struct HostIoOpenMode: u32 {
+ impl HostIoOpenMode: u32 {
/// A regular file.
const S_IFREG = 0o100000;
/// A directory.
@@ -176,7 +183,7 @@ pub enum HostIoError<E> {
/// A target-specific fatal error.
///
/// **WARNING:** Returning this error will immediately halt the target's
- /// execution and return a `GdbStubError::TargetError`!
+ /// execution and return a [`GdbStubError`](crate::stub::GdbStubError)!
///
/// Note that returning this error will _not_ notify the GDB client that the
/// debugging session has been terminated, making it possible to resume
diff --git a/src/target/ext/lldb_register_info_override.rs b/src/target/ext/lldb_register_info_override.rs
index ccd1358..3c200da 100644
--- a/src/target/ext/lldb_register_info_override.rs
+++ b/src/target/ext/lldb_register_info_override.rs
@@ -38,10 +38,9 @@ impl<'a> Callback<'a> {
/// runtime-configurable target, it's unlikely that you'll need to implement
/// this extension.
pub trait LldbRegisterInfoOverride: Target {
- /// Invoke `reg_info.write(reg)` where `reg` is a
- /// [`Register`](crate::arch::lldb::Register) struct to write information of
- /// a single register or `reg_info.done()` if you want to end the
- /// `qRegisterInfo` packet exchange.
+ /// Invoke `reg_info.write(reg)` where `reg` is a [`Register`] struct to
+ /// write information of a single register or `reg_info.done()` if you want
+ /// to end the `qRegisterInfo` packet exchange.
fn lldb_register_info<'a>(
&mut self,
reg_id: usize,
diff --git a/src/target/ext/memory_map.rs b/src/target/ext/memory_map.rs
index 46ffd2a..2b918ce 100644
--- a/src/target/ext/memory_map.rs
+++ b/src/target/ext/memory_map.rs
@@ -1,5 +1,6 @@
//! Provide a memory map for the target.
-use crate::target::{Target, TargetResult};
+use crate::target::Target;
+use crate::target::TargetResult;
/// Target Extension - Read the target's memory map.
pub trait MemoryMap: Target {
diff --git a/src/target/ext/monitor_cmd.rs b/src/target/ext/monitor_cmd.rs
index 5317e67..c4bd20e 100644
--- a/src/target/ext/monitor_cmd.rs
+++ b/src/target/ext/monitor_cmd.rs
@@ -1,10 +1,11 @@
//! Create custom target-specific debugging commands accessible via GDB's
//! `monitor` command!
-use crate::target::Target;
-
+pub use crate::output;
+pub use crate::outputln;
pub use crate::protocol::ConsoleOutput;
-pub use crate::{output, outputln};
+
+use crate::target::Target;
/// Target Extension - Handle custom GDB `monitor` commands.
pub trait MonitorCmd: Target {
diff --git a/src/target/ext/target_description_xml_override.rs b/src/target/ext/target_description_xml_override.rs
index 7cb9011..79174b3 100644
--- a/src/target/ext/target_description_xml_override.rs
+++ b/src/target/ext/target_description_xml_override.rs
@@ -1,5 +1,6 @@
//! Override the target description XML specified by `Target::Arch`.
-use crate::target::{Target, TargetResult};
+use crate::target::Target;
+use crate::target::TargetResult;
/// Target Extension - Override the target description XML specified by
/// `Target::Arch`.
diff --git a/src/target/mod.rs b/src/target/mod.rs
index 985eea6..2b00d0b 100644
--- a/src/target/mod.rs
+++ b/src/target/mod.rs
@@ -151,7 +151,7 @@
//! &mut self,
//! start_addr: u32,
//! data: &mut [u8],
-//! ) -> TargetResult<(), Self> { todo!() }
+//! ) -> TargetResult<usize, Self> { todo!() }
//!
//! fn write_addrs(
//! &mut self,
@@ -251,7 +251,7 @@
//! type is being used. e.g: on a 32-bit target, instead of cluttering up a
//! method implementation with a parameter passed as `(addr: <Self::Arch as
//! Arch>::Usize)`, just write `(addr: u32)` directly.
-use crate::arch::{Arch, SingleStepGdbBehavior};
+use crate::arch::Arch;
pub mod ext;
@@ -321,7 +321,8 @@ pub enum TargetError<E> {
/// A target-specific fatal error.
///
/// **WARNING:** Returning this error will immediately terminate the GDB
- /// debugging session, and return a top-level `GdbStubError::TargetError`!
+ /// debugging session, and return a
+ /// [`GdbStubError`](crate::stub::GdbStubError)!
Fatal(E),
}
@@ -409,7 +410,7 @@ pub trait Target {
/// # &mut self,
/// # start_addr: u32,
/// # data: &mut [u8],
- /// # ) -> TargetResult<(), Self> { todo!() }
+ /// # ) -> TargetResult<usize, Self> { todo!() }
/// #
/// # fn write_addrs(
/// # &mut self,
@@ -430,10 +431,6 @@ pub trait Target {
/// handler must explicitly **opt-in** to this somewhat surprising GDB
/// feature by overriding this method to return `true`.
///
- /// If you are reading these docs after having encountered a
- /// [`GdbStubError::ImplicitSwBreakpoints`] error, it's quite likely that
- /// you'll want to implement explicit support for software breakpoints.
- ///
/// # Context
///
/// An "implicit" software breakpoint is set by the GDB client by manually
@@ -483,51 +480,41 @@ pub trait Target {
/// 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.
- ///
- /// [`GdbStubError::ImplicitSwBreakpoints`]:
- /// crate::stub::GdbStubError::ImplicitSwBreakpoints
#[inline(always)]
fn guard_rail_implicit_sw_breakpoints(&self) -> bool {
false
}
- /// Override the arch-level value for [`Arch::single_step_gdb_behavior`].
- ///
- /// If you are reading these docs after having encountered a
- /// [`GdbStubError::SingleStepGdbBehavior`] error, you may need to either:
- ///
- /// - implement support for single-step
- /// - disable existing support for single step
- /// - be a Good Citizen and perform a quick test to see what kind of
- /// behavior your Arch exhibits.
- ///
- /// # WARNING
+ /// Enable/disable support for activating "no ack mode".
///
- /// Unless you _really_ know what you're doing (e.g: working on a dynamic
- /// target implementation, attempting to fix the underlying bug, etc...),
- /// you should **not** override this method, and instead follow the advice
- /// the error gives you.
- ///
- /// Incorrectly setting this method may lead to "unexpected packet" runtime
- /// errors!
- ///
- /// # Details
- ///
- /// This method provides an "escape hatch" for disabling a workaround for a
- /// bug in the mainline GDB client implementation.
- ///
- /// To squelch all errors, this method can be set to return
- /// [`SingleStepGdbBehavior::Optional`] (though as mentioned above - you
- /// should only do so if you're sure that's the right behavior).
- ///
- /// For more information, see the documentation for
- /// [`Arch::single_step_gdb_behavior`].
+ /// By default, this method returns `true`.
///
- /// [`GdbStubError::SingleStepGdbBehavior`]:
- /// crate::stub::GdbStubError::SingleStepGdbBehavior
+ /// _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 guard_rail_single_step_gdb_behavior(&self) -> SingleStepGdbBehavior {
- <Self::Arch as Arch>::single_step_gdb_behavior()
+ fn use_no_ack_mode(&self) -> bool {
+ true
}
/// Enable/disable using the more efficient `X` packet to write to target
@@ -725,8 +712,8 @@ macro_rules! impl_dyn_target {
__delegate!(fn base_ops(&mut self) -> ext::base::BaseOps<'_, Self::Arch, Self::Error>);
__delegate!(fn guard_rail_implicit_sw_breakpoints(&self) -> bool);
- __delegate!(fn guard_rail_single_step_gdb_behavior(&self) -> SingleStepGdbBehavior);
+ __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);