trap 0.2.3

Bare metal trapping.
Documentation
// Copyright 2025 Gabriel Bjørnager Jensen.

#![doc(html_logo_url = "https://gitlab.com/bjoernager/trap-rs/-/raw/master/DOCLOGO.svg")]

//! This library provides the [`trap`] function for aborting Rust programmes without the [`std`] crate.
//!
//! Fundamentally, the goal of this crate is to allow for abnormal programme termination with more or less the guarantee that execution of the current code path will stop.
//! Usually, [`std::process::abort`] is used for this, but on platforms or in crates without `std`, this is not possible.
//!
//! # Features
//!
//! The `std` feature can be enabled to allow for raising the [`SIGABRT`] signal when calling [`trap`].
//! Furthermore, the `nightly` feature can be enabled for more architectural support in cases where the [`std`] crate isn't available.
//!
//! [`SIGABRT`]: <https://pubs.opengroup.org/onlinepubs/7908799/xsh/signal.h.html>
//!
//! # Copyright & licence
//!
//! Copyright &#169; 2025 Gabriel Bj&#248;rnager Jensen.
//!
//! `trap-rs` is distributed under either an MIT licence (see `LICENCE-MIT.txt`) or version 2.0 of the Apache License (see `LICENCE-APACHE.txt`), at your option.

#![no_std]

#![allow(unused_imports)]

#![cfg_attr(feature = "nightly", allow(internal_features))]

#![cfg_attr(
	feature = "nightly",
	feature(
		asm_experimental_arch,
		core_intrinsics,
	),
)]

#[cfg(any(feature = "std", doc))]
extern crate std;

use core::arch::asm;
use core::hint::{spin_loop, unreachable_unchecked};

/// Exits the current process, indicating abnormal termination.
///
/// The exact behaviour of this function is unspecified.
///
/// # Platform support
///
/// The following, target architectures have special code paths that do not yield infinite loops by default:
///
/// * `aarch64`
/// * `arm`
/// * `loongarch32`
/// * `loongarch64`
/// * `riscv32`
/// * `riscv64`
/// * `x86`
/// * `x86_64`
///
/// Additionally, with the `nightly` feature enabled, the following architectures are supported as well:
///
/// * `powerpc`
/// * `powerpc64`
/// * `sparc`
/// * `sparc64`
/// * `wasm32`
///
/// Other targets will, by default, halt all execution in an infinite loop.
#[allow(unreachable_code)]
#[cold]
#[inline(never)]
#[track_caller]
pub fn trap() -> ! {
	// Use hosted abort, if possible.

	#[cfg(feature = "std")]
	std::process::abort();

	// Resort to an architectural abort instruction.

	#[cfg(target_arch = "aarch64")]
	unsafe { asm!("brk #1") };

	// `0xE7FFDEFE` is conventially seen as the "trap"
	// instruction, although it is just an undefined
	// instruction.
	#[cfg(target_arch = "arm")]
	unsafe { asm!(".inst 0xE7FFDEFE") };

	// Avoid `break 0` as it is more likely to be caught.
	// `amswap.w $zero, $ra, $zero` is the de-facto un-
	// catchable trap instruction: Using same `rd` and
	// `rj` yields Instruction Non-Defined Exception
	// for atomic operations.
	#[cfg(target_arch = "loongarch32")]
	unsafe { asm!("amswap.w $zero, $ra, $zero") };

	// See `loongarch32`.
	#[cfg(target_arch = "loongarch64")]
	unsafe { asm!("amswap.w $zero, $ra, $zero") };

	#[cfg(all(target_arch = "powerpc", feature = "nightly"))]
	unsafe { asm!("trap") };

	#[cfg(all(target_arch = "powerpc64", feature = "nightly"))]
	unsafe { asm!("trap") };

	#[cfg(target_arch = "riscv32")]
	unsafe { asm!("unimp") };

	#[cfg(target_arch = "riscv64")]
	unsafe { asm!("unimp") };

	#[cfg(all(target_arch = "sparc", feature = "nightly"))]
	unsafe { asm!("ta 5") };

	#[cfg(all(target_arch = "sparc64", feature = "nightly"))]
	unsafe { asm!("ta 5") };

	#[cfg(all(target_arch = "wasm32", feature = "nightly"))]
	unsafe { asm!("unreachable") };

	#[cfg(target_arch = "x86")]
	unsafe { asm!("ud2") };

	#[cfg(target_arch = "x86_64")]
	unsafe { asm!("ud2") };

	// Architectures without any appropriate trap in-
	// structions:
	// * s390x

	// Resort to the `abort` intrinsic if we couldn't
	// do anything better.

	#[cfg(feature = "nightly")]
	core::intrinsics::abort();

	// As an absolute last resort, do an infinite loop.

	loop {
		spin_loop();
	}
}