semihosting 0.1.25

Semihosting for AArch64, Arm, RISC-V, LoongArch, MIPS32, MIPS64, and Xtensa.
Documentation
// SPDX-License-Identifier: Apache-2.0 OR MIT

#[allow(clippy::used_underscore_binding)]
#[inline(never)]
#[cfg_attr(not(test), panic_handler)]
fn _panic(_info: &core::panic::PanicInfo<'_>) -> ! {
    #[cfg(feature = "stdio")]
    eprintln!("{_info}");

    #[cfg(feature = "panic-unwind")]
    {
        use crate::atomic::Ordering;
        // TODO(panic-unwind): PANICKED is global, so if panics occur concurrently on thread 1 and
        // thread 2 this could be mistakenly thought to be a double panic. However, I'm not sure if
        // there is a way to handle that well without thread local.
        if crate::experimental::panic::PANICKED.fetch_add(1, Ordering::AcqRel) != 0 {
            #[cfg(feature = "stdio")]
            eprintln!("panic during panic, aborting");
            crate::process::abort()
        }
    }

    #[cfg(feature = "backtrace")]
    {
        use core::{ffi::c_void, ptr};

        use unwinding::abi::{_Unwind_Backtrace, _Unwind_GetIP, UnwindContext, UnwindReasonCode};

        extern "C" fn callback(
            unwind_ctx: &UnwindContext<'_>,
            _arg: *mut c_void,
        ) -> UnwindReasonCode {
            let ip = _Unwind_GetIP(unwind_ctx);
            if ip == 0 {
                UnwindReasonCode::NORMAL_STOP
            } else {
                eprintln!("  {ip:#x}");
                UnwindReasonCode::NO_REASON
            }
        }

        eprintln!("stack backtrace:");
        _Unwind_Backtrace(callback, ptr::null_mut());
    }

    #[cfg(feature = "panic-unwind")]
    {
        let _code = unwinding::panic::begin_panic(alloc::boxed::Box::new(""));
        #[cfg(feature = "stdio")]
        eprintln!("failed to begin panic (unwind error code {})", _code.0);
    }

    crate::process::exit(101)
}