aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Vander Stoep <jeffv@google.com>2023-03-07 09:14:24 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-03-07 09:14:24 +0000
commitc0a7518181a9f9a735a2e10f4d842c5d821c3961 (patch)
treedf3567cef9442070f79b0ddd67ce6810f6f6a26e
parent4fa58910cc005ce805e594d8780704d179166a0c (diff)
parentfda7e1bf84e372f0d41e6aef48ead9e3d4c9486b (diff)
downloadgdbstub-c0a7518181a9f9a735a2e10f4d842c5d821c3961.tar.gz
Upgrade gdbstub to 0.6.4 am: 925e9a2e74 am: fda7e1bf84
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/gdbstub/+/2469443 Change-Id: Ie0c37b1c5cff7da25eb2b9bfd4843d6cbc3329ca Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--.github/workflows/ci.yml15
-rw-r--r--Android.bp2
-rw-r--r--CHANGELOG.md14
-rw-r--r--Cargo.toml2
-rw-r--r--Cargo.toml.orig2
-rw-r--r--METADATA14
-rw-r--r--README.md56
-rw-r--r--src/conn/impls/unixstream.rs12
-rw-r--r--src/lib.rs25
-rw-r--r--src/protocol/commands.rs1
-rw-r--r--src/protocol/commands/_m.rs2
-rw-r--r--src/protocol/commands/_m_upcase.rs2
-rw-r--r--src/protocol/commands/_vFile_open.rs2
-rw-r--r--src/protocol/commands/_vFile_pread.rs2
-rw-r--r--src/protocol/commands/_vFile_pwrite.rs4
-rw-r--r--src/protocol/commands/_vRun.rs2
-rw-r--r--src/protocol/commands/_x_upcase.rs4
-rw-r--r--src/protocol/commands/breakpoint.rs5
-rw-r--r--src/protocol/common/hex.rs131
-rw-r--r--src/protocol/console_output.rs3
-rw-r--r--src/protocol/packet.rs4
-rw-r--r--src/stub/core_impl/base.rs10
-rw-r--r--src/stub/core_impl/breakpoints.rs4
-rw-r--r--src/stub/core_impl/extended_mode.rs4
-rw-r--r--src/stub/core_impl/monitor_cmd.rs4
-rw-r--r--src/stub/core_impl/resume.rs6
-rw-r--r--src/stub/core_impl/single_register_access.rs4
-rw-r--r--src/stub/core_impl/target_xml.rs10
-rw-r--r--src/stub/core_impl/thread_extra_info.rs4
-rw-r--r--src/stub/core_impl/x_upcase_packet.rs4
-rw-r--r--src/target/mod.rs134
-rw-r--r--src/util/mod.rs1
-rw-r--r--src/util/no_panic_iter.rs126
34 files changed, 209 insertions, 408 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 4a80e34..a57d223 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
{
"git": {
- "sha1": "eb9d7be4a4095440171986b41d6ffc9fb3be1d74"
+ "sha1": "85ff370e018c031bc88438123bf2766c2c806d63"
},
"path_in_vcs": ""
} \ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3c2166a..b3b8e75 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -13,27 +13,34 @@ jobs:
profile: minimal
toolchain: stable
override: true
+
- name: cargo clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --workspace --tests --examples --features=std -- -D warnings
+
# don't forget the no_std example!
- name: cargo clippy (example_no_std)
uses: actions-rs/cargo@v1
with:
command: clippy
args: --manifest-path example_no_std/Cargo.toml
+
- name: cargo test
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace --features=std
+
+ - name: no panics in example_no_std
+ run: ./example_no_std/dump_asm.sh
+ shell: bash
+
- name: cargo doc
- uses: actions-rs/cargo@v1
- with:
- command: doc
- args: --workspace --features=std
+ run: cargo doc --workspace --features=std
+ env:
+ RUSTDOCFLAGS: "-Dwarnings"
rustfmt:
name: rustfmt (nightly)
diff --git a/Android.bp b/Android.bp
index c7537d7..edb194e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -23,7 +23,7 @@ rust_library {
host_supported: true,
crate_name: "gdbstub",
cargo_env_compat: true,
- cargo_pkg_version: "0.6.3",
+ cargo_pkg_version: "0.6.4",
srcs: ["src/lib.rs"],
edition: "2018",
features: [
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5166f1e..435154f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,20 @@ All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+# 0.6.4
+
+#### Bugfixes
+
+- Avoid truncating `X` packets that contain `:` and `,` as part of the payload. [\#121](https://github.com/daniel5151/gdbstub/pull/121) ([709924470](https://github.com/709924470))
+
+#### Internal Improvements
+
+- Various README tweaks
+- Remove some `unsafe` code
+- CI improvements
+ - Run no-panic checks on `example_no_std`
+ - Run CI on docs
+
# 0.6.3
#### New Features
diff --git a/Cargo.toml b/Cargo.toml
index 3b54beb..3dcdd43 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,7 +12,7 @@
[package]
edition = "2018"
name = "gdbstub"
-version = "0.6.3"
+version = "0.6.4"
authors = ["Daniel Prilik <danielprilik@gmail.com>"]
exclude = [
"examples/**/*.elf",
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index af1bb73..f448235 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.3"
+version = "0.6.4"
license = "MIT OR Apache-2.0"
edition = "2018"
readme = "README.md"
diff --git a/METADATA b/METADATA
index 88e139b..4b50ec0 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# 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
+
name: "gdbstub"
description: "An implementation of the GDB Remote Serial Protocol in Rust"
third_party {
@@ -7,13 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/gdbstub/gdbstub-0.6.3.crate"
+ value: "https://static.crates.io/crates/gdbstub/gdbstub-0.6.4.crate"
}
- version: "0.6.3"
+ version: "0.6.4"
license_type: NOTICE
last_upgrade_date {
- year: 2022
- month: 8
- day: 26
+ year: 2023
+ month: 3
+ day: 6
}
}
diff --git a/README.md b/README.md
index 3e11a06..c58e4f3 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ Why use `gdbstub`?
- "You don't pay for what you don't use": All code related to parsing/handling protocol extensions is guaranteed to be dead-code-eliminated from an optimized binary if left unimplemented. See the [Zero-overhead Protocol Extensions](#zero-overhead-protocol-extensions) section below for more details.
- `gdbstub`'s minimal configuration has an incredibly low binary size + RAM overhead, enabling it to be used on even the most resource-constrained microcontrollers.
- When compiled in release mode, using all the tricks outlined in [`min-sized-rust`](https://github.com/johnthagen/min-sized-rust), a baseline `gdbstub` implementation can weigh in at **_less than 10kb of `.text` + `.rodata`!_** \*
- - \*Exact numbers vary by target platform, compiler version, and `gdbstub` revision. Data was collected using the included `example_no_std` project compiled on x86_64.
+ - \*Exact numbers vary by target platform, compiler version, and `gdbstub` revision. In mixed-language projects, cross-language LTO may be required ([\#101](https://github.com/daniel5151/gdbstub/issues/101#issuecomment-1264444815)). Data was collected using the included `example_no_std` project compiled on x86_64.
### Can I Use `gdbstub` in Production?
@@ -137,14 +137,17 @@ If you end up using `gdbstub` in your project, consider opening a PR and adding
- [`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)
+ - [gamegirl](https://github.com/anellie/gamegirl) - A Gameboy (Color/Advance) emulator
- [bevy-atari](https://github.com/mrk-its/bevy-atari) - An Atari XL/XE Emulator (MOS 6502)
- [rmips](https://github.com/starfleetcadet75/rmips) - MIPS R3000 virtual machine simulator
- [clicky](https://github.com/daniel5151/clicky/) - Emulator for classic clickwheel iPods (dual-core ARMv4T)
- [ts7200](https://github.com/daniel5151/ts7200/) - Emulator for the TS-7200 SoC (ARMv4T)
- [vaporstation](https://github.com/Colin-Suckow/vaporstation) - A Playstation One emulator (MIPS)
- - [rustyboyadvance-ng](https://github.com/michelhe/rustboyadvance-ng/) - Nintendo GameBoy Advance emulator and debugger (ARMv4T)
- [microcorruption-emu](https://github.com/sapir/microcorruption-emu) - Emulator for the microcorruption.com ctf (MSP430)
- Other
+ - [probe-rs](https://probe.rs/) - A modern, embedded debugging toolkit
- [udbserver](https://github.com/bet4it/udbserver) - Plug-in GDB debugging for the [Unicorn Engine](https://www.unicorn-engine.org/) (Multi Architecture)
- [enarx](https://github.com/enarx/enarx) - An open source framework for running applications in Trusted Execution Environments
@@ -165,49 +168,48 @@ These examples are built as part of the CI, and are guaranteed to be kept up to
## `unsafe` in `gdbstub`
-`gdbstub` limits its use of `unsafe` to a bare minimum, with all uses of `unsafe` required to have a corresponding `// SAFETY` comment as justification. The following list exhaustively documents all uses of `unsafe` in `gdbstub`.
+`gdbstub` limits its use of `unsafe` to a bare minimum, with all uses of `unsafe` required to have a corresponding `// SAFETY` comment as justification.
-`rustc` + LLVM do a pretty incredible job at eliding bounds checks... most of the time. Unfortunately, there are a few places in the code where the compiler is not smart enough to "prove" that a bounds check isn't needed, and a bit of unsafe code is required to remove those bounds checks.
+For those paranoid about trusting third-party unsafe code, `gdbstub` comes with an opt-in `paranoid_unsafe` feature, which enables `#![forbid(unsafe_code)]` on the entire `gdbstub` crate, swapping out all instances of `unsafe` code with equivalent (albeit less-performant) alternatives.
-Enabling the `paranoid_unsafe` feature will swap out a handful of unsafe `get_unchecked_mut` operations with their safe equivalents, at the expense of introducing panicking code into `gdbstub`. This feature is **disabled** by default, as the unsafe code has been aggressively audited and tested for correctness. That said, if you're particularly paranoid about the use of unsafe code, enabling this feature may offer some piece of mind.
+The following list exhaustively documents all uses of `unsafe` in `gdbstub`:
-- When no cargo features are enabled:
- - A few trivially safe calls to `NonZeroUsize::new_unchecked()` when defining internal constants.
-
-- When the `paranoid_unsafe` feature is enabled, the following `unsafe` code is _removed_:
- - `src/protocol/packet.rs`: Swaps a couple slice-index methods in `PacketBuf` to use `get_unchecked_mut`. The public API of struct ensures that the bounds used to index into the array remain in-bounds.
- - `src/protocol/common/hex.rs`: Use an alternate implementation of `decode_hex_buf`/`decode_bin_buf` which uses unsafe slice indexing.
- - `src/common.rs`: Use a checked transmute to convert a `u8` to a `Signal`
+- With `default` features
+ - 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`. This manual implementation will be removed once [rust-lang/rust#76923](https://github.com/rust-lang/rust/issues/76923) is stabilized.
+ - `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.
+
## Writing panic-free code
Ideally, the Rust compiler would have some way to opt-in to a strict "no-panic" mode. Unfortunately, at the time of writing (2022/04/24), no such mode exists. As such, the only way to avoid the Rust compiler + stdlib's implicit panics is by being _very careful_ when writing code, and _manually checking_ that those panicking paths get optimized out!
-And when I say "manually checking", I actually mean "reading through [generated assembly](example_no_std/dump_asm.sh)".
+And when I say "manually checking", I mean [checking generated asm output](example_no_std/dump_asm.sh).
Why even go through this effort?
- Panic infrastructure can be _expensive_, and when you're optimizing for embedded, `no_std` use-cases, panic infrastructure brings in hundreds of additional bytes into the final binary.
- `gdbstub` can be used to implement low-level debuggers, and if the debugger itself panics, well... it's not like you can debug it all that easily!
-In conclusion, here is the `gdbstub` promise regarding panicking code:
-
-`gdbstub` will not introduce any additional panics into an existing binary, subject to the following conditions:
+As such, **`gdbstub` promises to introduce zero additional panics** into an existing project, subject to the following conditions:
-1. The binary is compiled in _release_ mode
- - Subject to the specific `rustc` version being used (as codegen and optimization can vary wildly between versions)
- - _Note:_ different hardware architectures may be subject to different compiler optimizations.
- - At this time, only `x86` has been confirmed panic-free
+1. The binary is compiled in release mode
+ - \*subject to the specific `rustc` version being used (codegen and optimization vary between versions)
+ - \*different hardware architectures may be subject to different compiler optimizations
+ - i.e: at this time, only `x86` is actively tested to be panic-free
2. `gdbstub`'s `paranoid_unsafe` cargo feature is _disabled_
- - See the [`unsafe` in `gdbstub`](#unsafe-in-gdbstub) section for more details.
+ - LLVM is unable to omit certain `panic` checks without requiring a bit of `unsafe` code
+ - See the [`unsafe` in `gdbstub`](#unsafe-in-gdbstub) section for more details
3. The `Arch` implementation being used doesn't include panicking code
- _Note:_ The arch implementations under `gdbstub_arch` are _not_ guaranteed to be panic free!
- If you do spot a panicking arch in `gdbstub_arch`, consider opening a PR to fix it
-If you're using `gdbstub` in a no-panic project and found that `gdbstub` has introduced some panicking code, please file an issue!
+If you're using `gdbstub` in a no-panic project and have determined that `gdbstub` is at fault for introducing a panicking code path, please file an issue!
## Future Plans + Roadmap to `1.0.0`
@@ -219,11 +221,10 @@ Not that this is _not_ an exhaustive list, and is subject to change.
- [ ] Implement GDB's various high-level operating modes:
- [x] Single/Multi Thread debugging
- [ ] Multiprocess Debugging
- - [ ] Will require adding a third `target::ext::base::multiprocess` API.
+ - [ ] 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`)
- [ ] [Non-Stop Mode](https://sourceware.org/gdb/onlinedocs/gdb/Remote-Non_002dStop.html#Remote-Non_002dStop)
- - This may require some breaking API changes and/or some internals rework -- more research is needed.
- [x] Have a working example of `gdbstub` running in a "bare-metal" `#![no_std]` environment.
Additionally, while not _strict_ blockers to `1.0.0`, it would be good to explore these features as well:
@@ -231,10 +232,9 @@ Additionally, while not _strict_ blockers to `1.0.0`, it would be good to explor
- [ ] Should `gdbstub` commit to a MSRV?
- [ ] Remove lingering instances of `RawRegId` from `gdbstub_arch` ([\#29](https://github.com/daniel5151/gdbstub/issues/29))
- [x] Exposing `async/await` interfaces (particularly wrt. handling GDB client interrupts) ([\#36](https://github.com/daniel5151/gdbstub/issues/36))
-- [ ] Supporting various [LLDB extensions](https://raw.githubusercontent.com/llvm-mirror/lldb/master/docs/lldb-gdb-remote.txt) to the GDB RSP
- - Skimming through the list, it doesn't seem like these extensions would require breaking API changes -- more research is needed.
+- [ ] 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 both x86 and x64 processes when running in extended mode
+ - 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...
diff --git a/src/conn/impls/unixstream.rs b/src/conn/impls/unixstream.rs
index 7f8191c..a810021 100644
--- a/src/conn/impls/unixstream.rs
+++ b/src/conn/impls/unixstream.rs
@@ -1,6 +1,4 @@
-use core::ffi::c_void;
use std::io;
-use std::os::unix::io::AsRawFd;
use std::os::unix::net::UnixStream;
use crate::conn::Connection;
@@ -12,8 +10,18 @@ trait PeekExt {
}
impl PeekExt for UnixStream {
+ #[cfg(feature = "paranoid_unsafe")]
+ #[allow(clippy::panic)]
+ fn peek(&self, _buf: &mut [u8]) -> io::Result<usize> {
+ panic!("cannot use `UnixStream::peek` with `paranoid_unsafe` until rust-lang/rust#73761 is stabilized");
+ }
+
+ #[cfg(not(feature = "paranoid_unsafe"))]
#[allow(non_camel_case_types)]
fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ use core::ffi::c_void;
+ use std::os::unix::io::AsRawFd;
+
// Define some libc types inline (to avoid bringing in entire libc dep)
// every platform supported by the libc crate uses c_int = i32
diff --git a/src/lib.rs b/src/lib.rs
index d51c23b..d71756b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -303,6 +303,7 @@
//! [`BlockingEventLoop`]: stub::run_blocking::BlockingEventLoop
#![cfg_attr(not(feature = "std"), no_std)]
+#![cfg_attr(feature = "paranoid_unsafe", forbid(unsafe_code))]
#[cfg(feature = "alloc")]
extern crate alloc;
@@ -322,12 +323,26 @@ pub mod conn;
pub mod stub;
pub mod target;
+// https://users.rust-lang.org/t/compile-time-const-unwrapping/51619/7
+//
+// This works from Rust 1.46.0 onwards, which stabilized branching and looping
+// in const contexts.
+macro_rules! unwrap {
+ ($e:expr $(,)*) => {
+ match $e {
+ ::core::option::Option::Some(x) => x,
+ ::core::option::Option::None => {
+ ["tried to unwrap a None"][99];
+ loop {}
+ }
+ }
+ };
+}
+
/// (Internal) The fake Tid that's used when running in single-threaded mode.
-// SAFETY: 1 is clearly non-zero.
-const SINGLE_THREAD_TID: common::Tid = unsafe { common::Tid::new_unchecked(1) };
-/// (Internal) The fake Pid reported to GDB (since `gdbstub` only supports
-/// debugging a single process).
-const FAKE_PID: common::Pid = unsafe { common::Pid::new_unchecked(1) };
+const SINGLE_THREAD_TID: common::Tid = unwrap!(common::Tid::new(1));
+/// (Internal) The fake Pid reported to GDB when running in multi-threaded mode.
+const FAKE_PID: common::Pid = unwrap!(common::Pid::new(1));
pub(crate) mod is_valid_tid {
pub trait IsValidTid {}
diff --git a/src/protocol/commands.rs b/src/protocol/commands.rs
index e00fc05..c42dccd 100644
--- a/src/protocol/commands.rs
+++ b/src/protocol/commands.rs
@@ -12,7 +12,6 @@ pub(self) mod prelude {
pub use crate::protocol::commands::ParseCommand;
pub use crate::protocol::common::hex::{decode_hex, decode_hex_buf};
pub use crate::protocol::packet::PacketBuf;
- pub use crate::util::no_panic_iter::SliceExt;
}
pub trait ParseCommand<'a>: Sized {
diff --git a/src/protocol/commands/_m.rs b/src/protocol/commands/_m.rs
index 59ebdb7..9271310 100644
--- a/src/protocol/commands/_m.rs
+++ b/src/protocol/commands/_m.rs
@@ -32,7 +32,7 @@ impl<'a> ParseCommand<'a> for m<'a> {
let (buf, body_range) = buf.into_raw_buf();
let body = buf.get_mut(body_range.start..body_range.end)?;
- let mut body = body.split_mut_no_panic(|b| *b == b',');
+ let mut body = body.split_mut(|b| *b == b',');
let addr = decode_hex_buf(body.next()?).ok()?;
let addr_len = addr.len();
diff --git a/src/protocol/commands/_m_upcase.rs b/src/protocol/commands/_m_upcase.rs
index b436a65..affe80d 100644
--- a/src/protocol/commands/_m_upcase.rs
+++ b/src/protocol/commands/_m_upcase.rs
@@ -12,7 +12,7 @@ impl<'a> ParseCommand<'a> for M<'a> {
fn from_packet(buf: PacketBuf<'a>) -> Option<Self> {
let body = buf.into_body();
- let mut body = body.split_mut_no_panic(|&b| b == b',' || b == b':');
+ let mut body = body.split_mut(|&b| b == b',' || b == b':');
let addr = decode_hex_buf(body.next()?).ok()?;
let len = decode_hex(body.next()?).ok()?;
let val = decode_hex_buf(body.next()?).ok()?;
diff --git a/src/protocol/commands/_vFile_open.rs b/src/protocol/commands/_vFile_open.rs
index d49995a..7497912 100644
--- a/src/protocol/commands/_vFile_open.rs
+++ b/src/protocol/commands/_vFile_open.rs
@@ -19,7 +19,7 @@ impl<'a> ParseCommand<'a> for vFileOpen<'a> {
match body {
[b':', body @ ..] => {
- let mut body = body.splitn_mut_no_panic(3, |b| *b == b',');
+ let mut body = body.splitn_mut(3, |b| *b == b',');
let filename = decode_hex_buf(body.next()?).ok()?;
let flags = HostIoOpenFlags::from_bits(decode_hex(body.next()?).ok()?)?;
let mode = HostIoOpenMode::from_bits(decode_hex(body.next()?).ok()?)?;
diff --git a/src/protocol/commands/_vFile_pread.rs b/src/protocol/commands/_vFile_pread.rs
index 7e40f50..314cb6a 100644
--- a/src/protocol/commands/_vFile_pread.rs
+++ b/src/protocol/commands/_vFile_pread.rs
@@ -21,7 +21,7 @@ impl<'a> ParseCommand<'a> for vFilePread<'a> {
match body {
[b':', body @ ..] => {
- let mut body = body.splitn_mut_no_panic(3, |b| *b == b',');
+ let mut body = body.splitn_mut(3, |b| *b == b',');
let fd = decode_hex(body.next()?).ok()?;
let count = decode_hex(body.next()?).ok()?;
let offset = decode_hex(body.next()?).ok()?;
diff --git a/src/protocol/commands/_vFile_pwrite.rs b/src/protocol/commands/_vFile_pwrite.rs
index 2dbf4b4..94cd34a 100644
--- a/src/protocol/commands/_vFile_pwrite.rs
+++ b/src/protocol/commands/_vFile_pwrite.rs
@@ -19,10 +19,10 @@ impl<'a> ParseCommand<'a> for vFilePwrite<'a> {
match body {
[b':', body @ ..] => {
- let mut body = body.splitn_mut_no_panic(3, |b| *b == b',');
+ let mut body = body.splitn_mut(3, |b| *b == b',');
let fd = decode_hex(body.next()?).ok()?;
let offset = decode_hex_buf(body.next()?).ok()?;
- let data = decode_bin_buf(body.next()?).ok()?;
+ let data = decode_bin_buf(body.next()?)?;
Some(vFilePwrite { fd, offset, data })
}
_ => None,
diff --git a/src/protocol/commands/_vRun.rs b/src/protocol/commands/_vRun.rs
index 26ced11..849c795 100644
--- a/src/protocol/commands/_vRun.rs
+++ b/src/protocol/commands/_vRun.rs
@@ -13,7 +13,7 @@ impl<'a> ParseCommand<'a> for vRun<'a> {
fn from_packet(buf: PacketBuf<'a>) -> Option<Self> {
let body = buf.into_body();
- let mut body = body.splitn_mut_no_panic(3, |b| *b == b';');
+ let mut body = body.splitn_mut(3, |b| *b == b';');
let _first_semi = body.next()?;
let filename = match decode_hex_buf(body.next()?).ok()? {
diff --git a/src/protocol/commands/_x_upcase.rs b/src/protocol/commands/_x_upcase.rs
index 32fe697..218c16c 100644
--- a/src/protocol/commands/_x_upcase.rs
+++ b/src/protocol/commands/_x_upcase.rs
@@ -14,10 +14,10 @@ impl<'a> ParseCommand<'a> for X<'a> {
fn from_packet(buf: PacketBuf<'a>) -> Option<Self> {
let body = buf.into_body();
- let mut body = body.split_mut_no_panic(|&b| b == b',' || b == b':');
+ let mut body = body.splitn_mut(3, |&b| b == b',' || b == b':');
let addr = decode_hex_buf(body.next()?).ok()?;
let len = decode_hex(body.next()?).ok()?;
- let val = decode_bin_buf(body.next()?).ok()?;
+ let val = decode_bin_buf(body.next()?)?;
Some(X { addr, len, val })
}
diff --git a/src/protocol/commands/breakpoint.rs b/src/protocol/commands/breakpoint.rs
index 46b9bb6..38ad046 100644
--- a/src/protocol/commands/breakpoint.rs
+++ b/src/protocol/commands/breakpoint.rs
@@ -1,5 +1,4 @@
use crate::protocol::common::hex::{decode_hex, decode_hex_buf};
-use crate::util::no_panic_iter::SliceExt;
// Breakpoint packets are split up like this:
//
@@ -24,7 +23,7 @@ pub struct BasicBreakpoint<'a> {
impl<'a> BasicBreakpoint<'a> {
pub fn from_slice(body: &'a mut [u8]) -> Option<BasicBreakpoint<'a>> {
- let mut body = body.splitn_mut_no_panic(4, |b| matches!(*b, b',' | b';'));
+ let mut body = body.splitn_mut(4, |b| matches!(*b, b',' | b';'));
let type_ = decode_hex(body.next()?).ok()?;
let addr = decode_hex_buf(body.next()?).ok()?;
let kind = decode_hex_buf(body.next()?).ok()?;
@@ -42,7 +41,7 @@ pub struct BytecodeBreakpoint<'a> {
impl<'a> BytecodeBreakpoint<'a> {
pub fn from_slice(body: &'a mut [u8]) -> Option<BytecodeBreakpoint<'a>> {
- let mut body = body.splitn_mut_no_panic(2, |b| *b == b';');
+ let mut body = body.splitn_mut(2, |b| *b == b';');
let base = BasicBreakpoint::from_slice(body.next()?)?;
diff --git a/src/protocol/common/hex.rs b/src/protocol/common/hex.rs
index 5c58605..ade9032 100644
--- a/src/protocol/common/hex.rs
+++ b/src/protocol/common/hex.rs
@@ -164,89 +164,34 @@ pub fn decode_hex_buf(base_buf: &mut [u8]) -> Result<&mut [u8], DecodeHexBufErro
for i in 0..decoded_len {
let b = ascii2byte(buf[i * 2]).ok_or(NotAscii)? << 4
| ascii2byte(buf[i * 2 + 1]).ok_or(NotAscii)?;
- buf[i] = b as u8;
+ buf[i] = b;
}
Ok(&mut base_buf[..decoded_len + odd_adust])
}
-#[derive(Debug)]
-pub enum DecodeBinBufError {
- UnexpectedEnd,
-}
-
/// Decode GDB escaped binary bytes into origin bytes _in place_.
-pub fn decode_bin_buf(buf: &mut [u8]) -> Result<&mut [u8], DecodeBinBufError> {
- use DecodeBinBufError::*;
+//
+// Thanks reddit!
+// https://www.reddit.com/r/rust/comments/110qzq9/any_idea_why_rust_isnt_able_to_elide_this_bounds/
+pub fn decode_bin_buf(buf: &mut [u8]) -> Option<&mut [u8]> {
let mut i = 0;
- let mut j = 0;
let len = buf.len();
- while i < len && j < len {
+ for j in 0..len {
+ if i >= len {
+ return Some(&mut buf[..j]);
+ }
+
if buf[i] == b'}' {
- if i + 1 >= len {
- return Err(UnexpectedEnd);
- } else {
- buf[j] = buf[i + 1] ^ 0x20;
- i += 1;
- }
+ buf[j] = buf.get(i + 1)? ^ 0x20;
+ i += 1;
} else {
buf[j] = buf[i];
}
i += 1;
- j += 1;
- }
-
- // SAFETY: by inspection, the value of j will never exceed buf.len().
- // Unfortunately, the LLVM optimizer isn't smart enough to see this, so
- // we have to manually elide the bounds check...
- if cfg!(feature = "paranoid_unsafe") {
- Ok(&mut buf[..j])
- } else {
- debug_assert!(j <= len);
- unsafe { Ok(buf.get_unchecked_mut(..j)) }
- }
-}
-
-#[derive(Debug)]
-pub enum EncodeHexBufError {
- SmallBuffer,
-}
-
-/// Encode a GDB hex string into a byte slice _in place_.
-///
-/// The data to be encoded should be copied into the buffer from
-/// `buf[start_idx..]`. The buffer itself must be at least `data.len() * 2`
-/// bytes in size, as each byte is expanded into a two byte hex string.
-#[allow(dead_code)]
-pub fn encode_hex_buf(buf: &mut [u8], start_idx: usize) -> Result<&mut [u8], EncodeHexBufError> {
- use EncodeHexBufError::*;
-
- let len = buf.len() - start_idx;
- let encoded_len = len * 2;
-
- if buf.len() < encoded_len {
- return Err(SmallBuffer);
}
- for i in 0..encoded_len {
- let byte = buf[start_idx + i / 2];
- let nybble = if i % 2 == 0 {
- // high
- (byte & 0xf0) >> 4
- } else {
- // low
- byte & 0x0f
- };
-
- buf[i] = match nybble {
- 0x0..=0x9 => b'0' + nybble,
- 0xa..=0xf => b'A' + (nybble - 0xa),
- #[allow(clippy::unreachable)] // will be optimized out
- _ => unreachable!(), // TODO: use unreachable_unchecked?
- };
- }
-
- Ok(&mut buf[..encoded_len])
+ Some(buf)
}
#[cfg(test)]
@@ -254,40 +199,6 @@ mod tests {
use super::*;
#[test]
- fn encode_hex_simple() {
- let payload = [0xde, 0xad, 0xbe, 0xef];
- let mut buf = [0; 16];
-
- let start_idx = buf.len() - payload.len();
-
- // copy the payload into the buffer
- buf[start_idx..].copy_from_slice(&payload);
- let out = encode_hex_buf(&mut buf, start_idx).unwrap();
-
- assert_eq!(out, b"DEADBEEF");
- }
-
- #[test]
- fn encode_hex_in_chunks() {
- let payload = (0..=255).collect::<Vec<u8>>();
- let mut out = Vec::new();
-
- let mut buf = [0; 30];
-
- for c in payload.chunks(15) {
- let start_idx = buf.len() - c.len();
-
- let data_buf = &mut buf[start_idx..];
- data_buf[..c.len()].copy_from_slice(c);
- out.extend_from_slice(encode_hex_buf(&mut buf, start_idx).unwrap());
- }
-
- let expect = (0..=255).map(|b| format!("{:02X?}", b)).collect::<String>();
-
- assert_eq!(out, expect.as_bytes())
- }
-
- #[test]
fn decode_hex_buf_odd() {
let mut payload = b"ffffff4".to_vec();
let res = decode_hex_buf(&mut payload).unwrap();
@@ -295,7 +206,14 @@ mod tests {
}
#[test]
- fn decode_hex_buf_2() {
+ fn decode_hex_buf_even() {
+ let mut payload = b"0123456789abcdef".to_vec();
+ let res = decode_hex_buf(&mut payload).unwrap();
+ assert_eq!(res, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
+ }
+
+ #[test]
+ fn decode_hex_buf_odd_alt() {
let mut payload = b"12345".to_vec();
let res = decode_hex_buf(&mut payload).unwrap();
assert_eq!(res, [0x1, 0x23, 0x45]);
@@ -309,6 +227,13 @@ mod tests {
}
#[test]
+ fn decode_hex_buf_empty() {
+ let mut payload = b"".to_vec();
+ let res = decode_hex_buf(&mut payload).unwrap();
+ assert_eq!(res, []);
+ }
+
+ #[test]
fn decode_bin_buf_escaped() {
let mut payload = b"}\x03}\x04}]}\n".to_vec();
let res = decode_bin_buf(&mut payload).unwrap();
diff --git a/src/protocol/console_output.rs b/src/protocol/console_output.rs
index 36c0ce9..16b30aa 100644
--- a/src/protocol/console_output.rs
+++ b/src/protocol/console_output.rs
@@ -15,6 +15,9 @@ use alloc::vec::Vec;
///
/// When the `alloc` feature is disabled, all output buffering is disabled, and
/// each call to `output!` will automatically flush data over the Connection.
+///
+/// [`output!`]: crate::output
+/// [`outputln!`]: crate::outputln
// TODO: support user-provided output buffers for no-`alloc` environments.
pub struct ConsoleOutput<'a> {
#[cfg(feature = "alloc")]
diff --git a/src/protocol/packet.rs b/src/protocol/packet.rs
index 84dd07b..468f38a 100644
--- a/src/protocol/packet.rs
+++ b/src/protocol/packet.rs
@@ -117,11 +117,11 @@ impl<'a> PacketBuf<'a> {
// always stays within the bounds of the provided buffer.
#[cfg(not(feature = "paranoid_unsafe"))]
unsafe {
- self.buf.get_unchecked_mut(self.body_range.clone())
+ self.buf.get_unchecked_mut(self.body_range)
}
#[cfg(feature = "paranoid_unsafe")]
- &mut self.buf[self.body_range.clone()]
+ &mut self.buf[self.body_range]
}
/// Return a mutable reference to the _entire_ underlying packet buffer, and
diff --git a/src/stub/core_impl/base.rs b/src/stub/core_impl/base.rs
index a87483b..e7d77dd 100644
--- a/src/stub/core_impl/base.rs
+++ b/src/stub/core_impl/base.rs
@@ -34,11 +34,11 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
Ok(tid)
}
- pub(crate) fn handle_base<'a>(
+ pub(crate) fn handle_base(
&mut self,
res: &mut ResponseWriter<'_, C>,
target: &mut T,
- command: Base<'a>,
+ command: Base<'_>,
) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
let handler_status = match command {
// ------------------ Handshaking and Queries ------------------- //
@@ -166,7 +166,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
pid: self
.features
.multiprocess()
- .then(|| SpecificIdKind::WithId(FAKE_PID)),
+ .then_some(SpecificIdKind::WithId(FAKE_PID)),
tid: SpecificIdKind::WithId(self.get_sane_any_tid(target)?),
})?;
res.write_str(";")?;
@@ -329,7 +329,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
pid: self
.features
.multiprocess()
- .then(|| SpecificIdKind::WithId(FAKE_PID)),
+ .then_some(SpecificIdKind::WithId(FAKE_PID)),
tid: SpecificIdKind::WithId(SINGLE_THREAD_TID),
})?,
BaseOps::MultiThread(ops) => {
@@ -346,7 +346,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
pid: self
.features
.multiprocess()
- .then(|| SpecificIdKind::WithId(FAKE_PID)),
+ .then_some(SpecificIdKind::WithId(FAKE_PID)),
tid: SpecificIdKind::WithId(tid),
})?;
Ok(())
diff --git a/src/stub/core_impl/breakpoints.rs b/src/stub/core_impl/breakpoints.rs
index f23c4b2..a54da71 100644
--- a/src/stub/core_impl/breakpoints.rs
+++ b/src/stub/core_impl/breakpoints.rs
@@ -76,11 +76,11 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
}
}
- pub(crate) fn handle_breakpoints<'a>(
+ pub(crate) fn handle_breakpoints(
&mut self,
_res: &mut ResponseWriter<'_, C>,
target: &mut T,
- command: Breakpoints<'a>,
+ command: Breakpoints<'_>,
) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
let ops = match target.support_breakpoints() {
Some(ops) => ops,
diff --git a/src/stub/core_impl/extended_mode.rs b/src/stub/core_impl/extended_mode.rs
index a87e08f..dbe3913 100644
--- a/src/stub/core_impl/extended_mode.rs
+++ b/src/stub/core_impl/extended_mode.rs
@@ -2,11 +2,11 @@ use super::prelude::*;
use crate::protocol::commands::ext::ExtendedMode;
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
- pub(crate) fn handle_extended_mode<'a>(
+ pub(crate) fn handle_extended_mode(
&mut self,
res: &mut ResponseWriter<'_, C>,
target: &mut T,
- command: ExtendedMode<'a>,
+ command: ExtendedMode<'_>,
) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
let ops = match target.support_extended_mode() {
Some(ops) => ops,
diff --git a/src/stub/core_impl/monitor_cmd.rs b/src/stub/core_impl/monitor_cmd.rs
index ea191ab..50425a2 100644
--- a/src/stub/core_impl/monitor_cmd.rs
+++ b/src/stub/core_impl/monitor_cmd.rs
@@ -4,11 +4,11 @@ use crate::protocol::commands::ext::MonitorCmd;
use crate::protocol::ConsoleOutput;
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
- pub(crate) fn handle_monitor_cmd<'a>(
+ pub(crate) fn handle_monitor_cmd(
&mut self,
res: &mut ResponseWriter<'_, C>,
target: &mut T,
- command: MonitorCmd<'a>,
+ command: MonitorCmd<'_>,
) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
let ops = match target.support_monitor_cmd() {
Some(ops) => ops,
diff --git a/src/stub/core_impl/resume.rs b/src/stub/core_impl/resume.rs
index 6f39eab..e63381a 100644
--- a/src/stub/core_impl/resume.rs
+++ b/src/stub/core_impl/resume.rs
@@ -14,11 +14,11 @@ use crate::FAKE_PID;
use super::DisconnectReason;
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
- pub(crate) fn handle_stop_resume<'a>(
+ pub(crate) fn handle_stop_resume(
&mut self,
res: &mut ResponseWriter<'_, C>,
target: &mut T,
- command: Resume<'a>,
+ command: Resume<'_>,
) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
let mut ops = match target.base_ops().resume_ops() {
Some(ops) => ops,
@@ -272,7 +272,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
pid: self
.features
.multiprocess()
- .then(|| SpecificIdKind::WithId(FAKE_PID)),
+ .then_some(SpecificIdKind::WithId(FAKE_PID)),
tid: SpecificIdKind::WithId(tid),
})?;
res.write_str(";")?;
diff --git a/src/stub/core_impl/single_register_access.rs b/src/stub/core_impl/single_register_access.rs
index 15ee90c..954a634 100644
--- a/src/stub/core_impl/single_register_access.rs
+++ b/src/stub/core_impl/single_register_access.rs
@@ -67,11 +67,11 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
Ok(handler_status)
}
- pub(crate) fn handle_single_register_access<'a>(
+ pub(crate) fn handle_single_register_access(
&mut self,
res: &mut ResponseWriter<'_, C>,
target: &mut T,
- command: SingleRegisterAccess<'a>,
+ command: SingleRegisterAccess<'_>,
) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
match target.base_ops() {
BaseOps::SingleThread(ops) => match ops.support_single_register_access() {
diff --git a/src/stub/core_impl/target_xml.rs b/src/stub/core_impl/target_xml.rs
index 15b1c35..2650ad2 100644
--- a/src/stub/core_impl/target_xml.rs
+++ b/src/stub/core_impl/target_xml.rs
@@ -30,12 +30,12 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
let xml_len = xml.len();
let start = xml_len.min(cmd.offset as usize);
- let end = xml_len.min(cmd.offset as usize + cmd.length);
+ let end = xml_len.min((cmd.offset as usize).saturating_add(cmd.length));
- // LLVM isn't smart enough to realize that `end` will always be greater than
- // `start`, and fails to elide the `slice_index_order_fail` check unless we
- // include this seemingly useless call to `max`.
- let data = &xml[start..end.max(start)];
+ // LLVM isn't smart enough to realize that `start <= end`, and fails to elide a
+ // `slice_end_index_len_fail` check unless we include this seemingly useless
+ // call to `min`.
+ let data = &xml[start.min(end)..end];
let n = data.len().min(cmd.buf.len());
cmd.buf[..n].copy_from_slice(&data[..n]);
diff --git a/src/stub/core_impl/thread_extra_info.rs b/src/stub/core_impl/thread_extra_info.rs
index 2e57137..124147d 100644
--- a/src/stub/core_impl/thread_extra_info.rs
+++ b/src/stub/core_impl/thread_extra_info.rs
@@ -3,11 +3,11 @@ use crate::protocol::commands::ext::ThreadExtraInfo;
use crate::target::ext::base::BaseOps;
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
- pub(crate) fn handle_thread_extra_info<'a>(
+ pub(crate) fn handle_thread_extra_info(
&mut self,
res: &mut ResponseWriter<'_, C>,
target: &mut T,
- command: ThreadExtraInfo<'a>,
+ command: ThreadExtraInfo<'_>,
) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
let ops = match target.base_ops() {
BaseOps::SingleThread(_) => return Ok(HandlerStatus::Handled),
diff --git a/src/stub/core_impl/x_upcase_packet.rs b/src/stub/core_impl/x_upcase_packet.rs
index f35f846..9d865e5 100644
--- a/src/stub/core_impl/x_upcase_packet.rs
+++ b/src/stub/core_impl/x_upcase_packet.rs
@@ -5,11 +5,11 @@ use crate::arch::Arch;
use crate::target::ext::base::BaseOps;
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
- pub(crate) fn handle_x_upcase_packet<'a>(
+ pub(crate) fn handle_x_upcase_packet(
&mut self,
_res: &mut ResponseWriter<'_, C>,
target: &mut T,
- command: XUpcasePacket<'a>,
+ command: XUpcasePacket<'_>,
) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
if !target.use_x_upcase_packet() {
return Ok(HandlerStatus::Handled);
diff --git a/src/target/mod.rs b/src/target/mod.rs
index a5d912b..985eea6 100644
--- a/src/target/mod.rs
+++ b/src/target/mod.rs
@@ -691,6 +691,28 @@ pub trait Target {
}
}
+macro_rules! __delegate {
+ (fn $op:ident(&mut $this:ident) $($sig:tt)*) => {
+ fn $op(&mut $this) $($sig)* {
+ (**$this).$op()
+ }
+ };
+
+ (fn $op:ident(&$this:ident) $($sig:tt)*) => {
+ fn $op(&$this) $($sig)* {
+ (**$this).$op()
+ }
+ }
+}
+
+macro_rules! __delegate_support {
+ ($ext:ident) => {
+ paste::paste! {
+ __delegate!(fn [<support_ $ext>](&mut self) -> Option<ext::$ext::[<$ext:camel Ops>]<'_, Self>>);
+ }
+ };
+}
+
macro_rules! impl_dyn_target {
($type:ty) => {
impl<A, E> Target for $type
@@ -700,96 +722,28 @@ macro_rules! impl_dyn_target {
type Arch = A;
type Error = E;
- fn base_ops(&mut self) -> ext::base::BaseOps<'_, Self::Arch, Self::Error> {
- (**self).base_ops()
- }
-
- fn guard_rail_implicit_sw_breakpoints(&self) -> bool {
- (**self).guard_rail_implicit_sw_breakpoints()
- }
-
- fn guard_rail_single_step_gdb_behavior(&self) -> SingleStepGdbBehavior {
- (**self).guard_rail_single_step_gdb_behavior()
- }
-
- fn use_x_upcase_packet(&self) -> bool {
- (**self).use_x_upcase_packet()
- }
-
- fn use_resume_stub(&self) -> bool {
- (**self).use_resume_stub()
- }
-
- fn use_rle(&self) -> bool {
- (**self).use_rle()
- }
-
- fn use_target_description_xml(&self) -> bool {
- (**self).use_target_description_xml()
- }
-
- fn use_lldb_register_info(&self) -> bool {
- (**self).use_lldb_register_info()
- }
-
- fn support_breakpoints(
- &mut self,
- ) -> Option<ext::breakpoints::BreakpointsOps<'_, Self>> {
- (**self).support_breakpoints()
- }
-
- fn support_monitor_cmd(&mut self) -> Option<ext::monitor_cmd::MonitorCmdOps<'_, Self>> {
- (**self).support_monitor_cmd()
- }
-
- fn support_extended_mode(
- &mut self,
- ) -> Option<ext::extended_mode::ExtendedModeOps<'_, Self>> {
- (**self).support_extended_mode()
- }
-
- fn support_section_offsets(
- &mut self,
- ) -> Option<ext::section_offsets::SectionOffsetsOps<'_, Self>> {
- (**self).support_section_offsets()
- }
-
- fn support_target_description_xml_override(
- &mut self,
- ) -> Option<
- ext::target_description_xml_override::TargetDescriptionXmlOverrideOps<'_, Self>,
- > {
- (**self).support_target_description_xml_override()
- }
-
- fn support_lldb_register_info_override(
- &mut self,
- ) -> Option<ext::lldb_register_info_override::LldbRegisterInfoOverrideOps<'_, Self>>
- {
- (**self).support_lldb_register_info_override()
- }
-
- fn support_memory_map(&mut self) -> Option<ext::memory_map::MemoryMapOps<'_, Self>> {
- (**self).support_memory_map()
- }
-
- fn support_catch_syscalls(
- &mut self,
- ) -> Option<ext::catch_syscalls::CatchSyscallsOps<'_, Self>> {
- (**self).support_catch_syscalls()
- }
-
- fn support_host_io(&mut self) -> Option<ext::host_io::HostIoOps<'_, Self>> {
- (**self).support_host_io()
- }
-
- fn support_exec_file(&mut self) -> Option<ext::exec_file::ExecFileOps<'_, Self>> {
- (**self).support_exec_file()
- }
-
- fn support_auxv(&mut self) -> Option<ext::auxv::AuxvOps<'_, Self>> {
- (**self).support_auxv()
- }
+ __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_x_upcase_packet(&self) -> bool);
+ __delegate!(fn use_resume_stub(&self) -> bool);
+ __delegate!(fn use_rle(&self) -> bool);
+ __delegate!(fn use_target_description_xml(&self) -> bool);
+ __delegate!(fn use_lldb_register_info(&self) -> bool);
+
+ __delegate_support!(breakpoints);
+ __delegate_support!(monitor_cmd);
+ __delegate_support!(extended_mode);
+ __delegate_support!(section_offsets);
+ __delegate_support!(target_description_xml_override);
+ __delegate_support!(lldb_register_info_override);
+ __delegate_support!(memory_map);
+ __delegate_support!(catch_syscalls);
+ __delegate_support!(host_io);
+ __delegate_support!(exec_file);
+ __delegate_support!(auxv);
}
};
}
diff --git a/src/util/mod.rs b/src/util/mod.rs
index 7539bbb..bbdf42e 100644
--- a/src/util/mod.rs
+++ b/src/util/mod.rs
@@ -4,6 +4,5 @@
//! libraries, and do not rely on any `gdbstub` specific infrastructure.
pub mod managed_vec;
-pub mod no_panic_iter;
pub(crate) mod dead_code_marker;
diff --git a/src/util/no_panic_iter.rs b/src/util/no_panic_iter.rs
deleted file mode 100644
index af1fb45..0000000
--- a/src/util/no_panic_iter.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-/// Slice extension trait that provides non-panicing variants of several
-/// standard library iterators.
-pub trait SliceExt<T> {
- /// Variant of [`core::slice::split_mut`] that elides bound checks.
- fn split_mut_no_panic<F>(&mut self, pred: F) -> SplitMut<'_, T, F>
- where
- F: FnMut(&T) -> bool;
-
- /// Variant of [`core::slice::splitn_mut`] that elides bound checks.
- fn splitn_mut_no_panic<F>(&mut self, n: usize, pred: F) -> SplitNMut<'_, T, F>
- where
- F: FnMut(&T) -> bool;
-}
-
-impl<T> SliceExt<T> for [T] {
- fn split_mut_no_panic<F>(&mut self, pred: F) -> SplitMut<'_, T, F>
- where
- F: FnMut(&T) -> bool,
- {
- SplitMut::new(self, pred)
- }
-
- fn splitn_mut_no_panic<F>(&mut self, n: usize, pred: F) -> SplitNMut<'_, T, F>
- where
- F: FnMut(&T) -> bool,
- {
- SplitNMut {
- iter: SplitMut::new(self, pred),
- count: n,
- }
- }
-}
-
-#[derive(Debug)]
-pub struct SplitMut<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- v: &'a mut [T],
- pred: P,
- finished: bool,
-}
-
-impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitMut<'a, T, P> {
- #[inline]
- pub fn new(slice: &'a mut [T], pred: P) -> Self {
- Self {
- v: slice,
- pred,
- finished: false,
- }
- }
-
- #[inline]
- fn finish(&mut self) -> Option<&'a mut [T]> {
- if self.finished {
- None
- } else {
- self.finished = true;
- Some(core::mem::take(&mut self.v))
- }
- }
-}
-
-impl<'a, T, P> Iterator for SplitMut<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- type Item = &'a mut [T];
-
- #[inline]
- fn next(&mut self) -> Option<&'a mut [T]> {
- if self.finished {
- return None;
- }
-
- let idx_opt = {
- // work around borrowck limitations
- let pred = &mut self.pred;
- self.v.iter().position(|x| (*pred)(x))
- };
- match idx_opt {
- None => self.finish(),
- Some(idx) => {
- let tmp = core::mem::take(&mut self.v);
- let (head, tail) = tmp.split_at_mut(idx);
- self.v = tail.get_mut(1..)?; // will never fail
- Some(head)
- }
- }
- }
-}
-
-/// An private iterator over subslices separated by elements that
-/// match a predicate function, splitting at most a fixed number of
-/// times.
-#[derive(Debug)]
-pub struct SplitNMut<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- iter: SplitMut<'a, T, P>,
- count: usize,
-}
-
-impl<'a, T, P> Iterator for SplitNMut<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- type Item = &'a mut [T];
-
- #[inline]
- fn next(&mut self) -> Option<&'a mut [T]> {
- match self.count {
- 0 => None,
- 1 => {
- self.count -= 1;
- self.iter.finish()
- }
- _ => {
- self.count -= 1;
- self.iter.next()
- }
- }
- }
-}