Semihosting for AArch64, ARM, RISC-V (RV32 & RV64), MIPS, and MIPS64.
This library provides access to semihosting, a mechanism for programs running on the real or virtual (e.g., QEMU) target to communicate with I/O facilities on the host system. See the ARM documentation for more information on semihosting.
APIs are categorized into the following four types:
The top-level API (semihosting::{io,fs,..}
) provides a subset of the standard library's similar APIs.
io
: Provide no-std io traits and std{in,out,err}
. (std{in,out,err}
requires stdio
feature)fs
: Provide methods to manipulate the contents of the host filesystem. (requires fs
feature)process
: Provide abort
and exit
.dbg!
/print{,ln}!
/eprint{,ln}!
: macros to output to stdout/stderr. (requires stdio
feature)Note that some APIs are not strictly a subset of the standard library.
core
such as Path
(technically, the same thing could be implemented, but it makes sense to use CStr
directly, because when converting a long Path
/OsStr
to CStr
, it needs to either do an allocation or return an error)std
(in no-std it makes sense to return Result
since panic=abort
is default)Helpers that are useful when using this library.
c!
: CStr
literal macro.semihosting::sys
module, which provides low-level access to platform-specific semihosting interfaces.
semihosting::experimental
module, which provides experimental APIs. See optional features for more.
Additionally, this library provides a panic handler for semihosting and -C panic=unwind
support, via optional features.
The following target architectures are supported:
| target_arch | Specification | semihosting::sys
module |
| ----------- | ------------- | ------------------------- |
| arm/aarch64 | Semihosting for AArch32 and AArch64 | sys::arm_compat
|
| riscv32/riscv64 | RISC-V Semihosting | sys::arm_compat
|
| mips/mips64 | Unified Hosting Interface (MD01069) | sys::mips
|
The host must be running an emulator or a debugger attached to the target.
The following targets have been tested on CI. (qemu-system has been tested on Linux, macOS, and Windows hosts, and qemu-user on Linux host.)
| target | exit | all-apis [1] (qemu-system) | all-apis [1] (qemu-user) | panic-unwind (qemu-system [2]) |
| ------------------------------------ | ---- | --------------------------- | ------------------------- | ------------------------------- |
| aarch64-unknown-none{,-softfloat}
| ✓ | ✓ | ✓ | ✓ |
| {arm,thumb}v4t-none-eabi
| ✓ | | ✓ | |
| {arm,thumb}v5te-none-eabi
| ✓ | ✓ | ✓ | |
| armv7a-none-eabi{,hf}
| ✓ | ✓ | ✓ | |
| armv7r-none-eabi{,hf}
| ✓ | ✓ | ✓ | |
| armebv7r-none-eabi{,hf}
| ✓ | | ✓ | |
| thumbv6m-none-eabi
| ✓ | ✓ | N/A | |
| thumbv7m-none-eabi
| ✓ | ✓ | N/A | |
| thumbv7em-none-eabi{,hf}
| ✓ | ✓ | N/A | |
| thumbv8m.base-none-eabi
| ✓ | ✓ [3] | N/A | |
| thumbv8m.main-none-eabi{,hf}
| ✓ | ✓ [3] | N/A | |
| riscv32*-unknown-none-elf
| ✓ | ✓ | ✓ | ✓ |
| riscv64*-unknown-none-elf
| ✓ | ✓ | ✓ | ✓ |
| mips{,el}-unknown-none
[5] | ✓ | ✓ [6] | N/A | |
| mips64{,el}-unknown-none
[5] | ✓ | ✓ [6] | N/A | |
[1] stdio
, fs
, time
, and args
.
[2] I'm not sure how to test panic-unwind on qemu-user.
[4] Worked on QEMU 6.2 and QEMU 8.0, failed on QEMU 7.2.
[5] Requires nightly due to #![feature(asm_experimental_arch)]
.
[6] It seems unsupported on QEMU 8.0.
All features are disabled by default.
In general use cases, you probably only need the stdio
feature that enables print-related macros and/or the panic-handler
feature that exits with a non-zero error code on panic.
toml
[dependencies]
semihosting = { version = "0.1", features = ["stdio", "panic-handler"] }
alloc
Use alloc
.
stdio
Enable semihosting::io::{stdin,stdout,stderr}
and semihosting::{print*,eprint*,dbg}
.
fs
Enable semihosting::fs
.
panic-handler
Provide panic handler based on semihosting::process::exit
.
If the stdio
feature is also enabled, this attempt to output panic message and
location to stderr.
portable-atomic
Use [portable-atomic]'s atomic types.
portable-atomic provides atomic CAS on targets where the standard library does not provide atomic CAS.
To use the panic-unwind
feature on such targets (e.g., RISC-V without A-extension), you need to enable this feature.
See the documentation for details.
args
Enable semihosting::experimental::env::args
.
Note:
time
Enable semihosting::experimental::time
.
Note:
panic-unwind
Provide -C panic=unwind
support for panic handler and enable
semihosting::experimental::panic::catch_unwind
.
This currently uses [unwinding] crate to support unwinding. See its documentation for supported platforms and requirements.
Note:
alloc
and panic-handler
features.portable-atomic
feature together if your target doesn't support atomic CAS (e.g., RISC-V without A-extension).-C panic=unwind
for catch_unwind
to work properly. The recommended way to
rebuild the standard library is passing -Z build-std="core,alloc"
option to cargo.backtrace
Provide backtrace support for panic handler.
This currently uses [unwinding] crate to support backtrace. See its documentation for supported platforms and requirements.
Note:
stdio
feature.panic-unwind
feature. Otherwise, a decent backtrace will not be displayed at this time. (Using -C force-unwind-tables
may work, but has not been tested yet.)text
panicked at 'a', src/main.rs:86:13
stack backtrace:
0x84dc0
0x8ed80
0x8332c
0x83654
0x80644
0x803cc
0x809dc
0x800bc
You can use addr2line
to resolve the addresses and [rustfilt] to demangle Rust symbols.
For example, run the following command (please replace <path/to/binary>
with your binary path), then paste the addresses:
sh
llvm-addr2line -fipe <path/to/binary> | rustfilt
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.