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>
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 @@
     #   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 @@
     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 @@
         "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 @@
 
 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 @@
 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 @@
 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 @@
     -   [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 @@
   - 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 @@
 -   [ ] 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 @@
 -   [ ] 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 @@
 
 > _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(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 @@
             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 @@
     }
 
     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 @@
     ) -> 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 @@
         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,11 +1,14 @@
-use gdbstub::arch::lldb::{Encoding, Format, Generic, Register};
-use gdbstub::arch::RegId;
-use gdbstub::target;
-use gdbstub::target::ext::lldb_register_info_override::{Callback, CallbackToken};
-use gdbstub_arch::arm::reg::id::ArmCoreRegId;
-
 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;
+use gdbstub::target::ext::lldb_register_info_override::CallbackToken;
+use gdbstub_arch::arm::reg::id::ArmCoreRegId;
 
 // (LLDB extension) This implementation is for illustrative purposes only.
 //
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 @@
         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 @@
 
 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 @@
                 }
             }
         }
-        // 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 @@
             }
             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 @@
         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 @@
             }
             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 @@
         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 @@
 
 /// (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 @@
                     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 @@
 
                     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 @@
                         } else {
                             None
                         }
-		    }
+                    }
 
                     fn support_resume(&mut self) -> Option<()> {
                         self.base_ops().resume_ops().map(drop)
@@ -160,6 +161,14 @@
                         }
                     }
 
+                    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 @@
         "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 @@
         "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 @@
 
     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 @@
             [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 @@
 
 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 @@
     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 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 @@
 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 @@
         /// 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 @@
                 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 @@
     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 @@
         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 @@
             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 @@
                     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 @@
         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 @@
     }
 }
 
+#[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 @@
                     }
                 })
                 .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 @@
                 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 @@
 
                 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 @@
 
                     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 @@
                     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 @@
                 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 @@
             }
             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 @@
                                     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 @@
                 HandlerStatus::Handled
             }
             ExtendedMode::vAttach(cmd) => {
-                ops.attach(cmd.pid).handle_error()?;
+                if ops.support_current_active_pid().is_none() {
+                    return Err(Error::MissingCurrentActivePidImpl);
+                }
 
-                // TODO: sends OK when running in Non-Stop mode
+                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),
+                })?;
+
                 HandlerStatus::Handled
             }
             ExtendedMode::vRun(cmd) => {
@@ -37,10 +88,7 @@
                     .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 @@
                 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 @@
                     }
                 };
                 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 @@
                 // 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 @@
     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 @@
                 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 @@
         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 @@
             }
             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 @@
             {
                 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 @@
             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 @@
             } 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 which may occur during a GDB debugging session.
+/// An error that may occur while interacting with a
+/// [`Connection`](crate::conn::Connection).
 #[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),
+pub enum ConnectionErrorKind {
+    /// Error initializing the session.
+    Init,
+    /// Error reading data.
+    Read,
+    /// Error writing data.
+    Write,
+}
 
-    /// Client nack'd the last packet, but `gdbstub` doesn't implement
-    /// re-transmission.
-    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,
+#[derive(Debug)]
+pub(crate) enum InternalError<T, C> {
+    /// Connection Error
+    Connection(C, ConnectionErrorKind),
     /// 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
+    ClientSentNack,
+    PacketBufferOverflow,
+    PacketParse(PacketParseError),
+    PacketUnexpected,
+    TargetMismatch,
+    UnsupportedStopReason,
+    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 @@
     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."),
+            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."),
-            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.")
-            },
+            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. End users should never see this! Please file an issue if you do!"),
+            NonFatalError(_) => write!(f, "Internal non-fatal error. You should never see this! Please file an issue if you do!"),
         }
     }
 }
@@ -123,7 +148,48 @@
 #[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 @@
 
 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 @@
     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 @@
             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 @@
 
                 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 @@
                         }
 
                         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 @@
     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 @@
                 .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 @@
         {
             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 @@
 // 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 @@
         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 @@
         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 @@
     }
 
     /// 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 @@
         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 @@
         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 @@
         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 @@
 
     /// 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 @@
     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 @@
 }
 
 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 @@
     }
 }
 
+/// 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 @@
     /// 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 @@
 /// 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 @@
     /// 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 @@
     /// #       &mut self,
     /// #       start_addr: u32,
     /// #       data: &mut [u8],
-    /// #   ) -> TargetResult<(), Self> { todo!() }
+    /// #   ) -> TargetResult<usize, Self> { todo!() }
     /// #
     /// #   fn write_addrs(
     /// #       &mut self,
@@ -430,10 +431,6 @@
     /// 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 @@
     /// 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`].
+    /// Enable/disable support for activating "no ack mode".
     ///
-    /// If you are reading these docs after having encountered a
-    /// [`GdbStubError::SingleStepGdbBehavior`] error, you may need to either:
+    /// By default, this method returns `true`.
     ///
-    /// - 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.
+    /// _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
+    /// **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.
     ///
-    /// 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.
+    /// # What is "No Ack Mode"?
     ///
-    /// Incorrectly setting this method may lead to "unexpected packet" runtime
-    /// errors!
+    /// From the [GDB RSP docs](https://sourceware.org/gdb/onlinedocs/gdb/Packet-Acknowledgment.html#Packet-Acknowledgment):
     ///
-    /// # 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`].
-    ///
-    /// [`GdbStubError::SingleStepGdbBehavior`]:
-    /// crate::stub::GdbStubError::SingleStepGdbBehavior
+    /// > 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 @@
             __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);