unwind: add support for using unwinding crate

The `unwinding` crate supports processing unwinding data, and is written
entirely in Rust. This allows it to be ported to new platforms more
easily than using the llvm-based `libunwind`.

While `libunwind` is very well supported on major targets, it is
difficult to use on other targets. SGX is an example of this where Rust
carries custom patches in order to enable backtrace support.

This adds an alternative for supported architectures. Rather than
providing a custom target, `unwinding` allows for a solution that is
completely written in Rust.

This adds `xous` as the first consumer, and forthcoming patches will
modify libstd to take advantage of this.

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2023-11-05 21:33:43 +08:00
parent 57fb1e643a
commit ee870d6c82
4 changed files with 120 additions and 6 deletions

View File

@ -15,10 +15,13 @@ doc = false
[dependencies]
core = { path = "../core" }
libc = { version = "0.2.79", features = ['rustc-dep-of-std'], default-features = false }
libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false }
compiler_builtins = "0.1.0"
cfg-if = "1.0"
[target.'cfg(target_os = "xous")'.dependencies]
unwinding = { version = "0.2.1", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false }
[features]
# Only applies for Linux and Fuchsia targets

View File

@ -26,6 +26,9 @@ cfg_if::cfg_if! {
))] {
mod libunwind;
pub use libunwind::*;
} else if #[cfg(target_os = "xous")] {
mod unwinding;
pub use unwinding::*;
} else {
// no unwinder on the system!
// - wasm32 (not emscripten, which is "unix" family)

View File

@ -103,7 +103,10 @@ pub type _Unwind_Exception_Cleanup_Fn =
// and RFC 2841
#[cfg_attr(
any(
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
all(
feature = "llvm-libunwind",
any(target_os = "fuchsia", target_os = "linux", target_os = "xous")
),
all(target_os = "windows", target_env = "gnu", target_abi = "llvm")
),
link(name = "unwind", kind = "static", modifiers = "-bundle")
@ -134,7 +137,7 @@ if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", targe
pub use _Unwind_Action::*;
#[cfg_attr(
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")),
link(name = "unwind", kind = "static", modifiers = "-bundle")
)]
extern "C" {
@ -192,7 +195,7 @@ if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", targe
pub const UNWIND_IP_REG: c_int = 15;
#[cfg_attr(
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")),
link(name = "unwind", kind = "static", modifiers = "-bundle")
)]
extern "C" {
@ -258,14 +261,14 @@ cfg_if::cfg_if! {
if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
// Not 32-bit iOS
#[cfg_attr(
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")),
link(name = "unwind", kind = "static", modifiers = "-bundle")
)]
extern "C-unwind" {
pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
}
#[cfg_attr(
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")),
link(name = "unwind", kind = "static", modifiers = "-bundle")
)]
extern "C" {

View File

@ -0,0 +1,105 @@
#![allow(nonstandard_style)]
use libc::{c_int, c_void};
#[repr(C)]
#[derive(Copy, Clone, PartialEq)]
pub enum _Unwind_Action {
_UA_SEARCH_PHASE = 1,
_UA_CLEANUP_PHASE = 2,
_UA_HANDLER_FRAME = 4,
_UA_FORCE_UNWIND = 8,
_UA_END_OF_STACK = 16,
}
pub use _Unwind_Action::*;
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum _Unwind_Reason_Code {
_URC_NO_REASON = 0,
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
_URC_FATAL_PHASE2_ERROR = 2,
_URC_FATAL_PHASE1_ERROR = 3,
_URC_NORMAL_STOP = 4,
_URC_END_OF_STACK = 5,
_URC_HANDLER_FOUND = 6,
_URC_INSTALL_CONTEXT = 7,
_URC_CONTINUE_UNWIND = 8,
_URC_FAILURE = 9, // used only by ARM EHABI
}
pub use _Unwind_Reason_Code::*;
pub use unwinding::abi::UnwindContext;
pub use unwinding::abi::UnwindException;
pub enum _Unwind_Context {}
pub use unwinding::custom_eh_frame_finder::{
set_custom_eh_frame_finder, EhFrameFinder, FrameInfo, FrameInfoKind,
};
pub type _Unwind_Exception_Class = u64;
pub type _Unwind_Word = *const u8;
pub type _Unwind_Ptr = *const u8;
pub const unwinder_private_data_size: usize = core::mem::size_of::<UnwindException>()
- core::mem::size_of::<_Unwind_Exception_Class>()
- core::mem::size_of::<_Unwind_Exception_Cleanup_Fn>();
pub type _Unwind_Exception_Cleanup_Fn =
extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception);
#[repr(C)]
pub struct _Unwind_Exception {
pub exception_class: _Unwind_Exception_Class,
pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
pub private: [_Unwind_Word; unwinder_private_data_size],
}
pub unsafe fn _Unwind_GetDataRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr {
let ctx = unsafe { &mut *(ctx as *mut UnwindContext<'_>) };
unwinding::abi::_Unwind_GetDataRelBase(ctx) as _Unwind_Ptr
}
pub unsafe fn _Unwind_GetTextRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr {
let ctx = unsafe { &mut *(ctx as *mut UnwindContext<'_>) };
unwinding::abi::_Unwind_GetTextRelBase(ctx) as _Unwind_Ptr
}
pub unsafe fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr {
let ctx = unsafe { &mut *(ctx as *mut UnwindContext<'_>) };
unwinding::abi::_Unwind_GetRegionStart(ctx) as _Unwind_Ptr
}
pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) {
let ctx = unsafe { &mut *(ctx as *mut UnwindContext<'_>) };
unwinding::abi::_Unwind_SetGR(ctx, reg_index, value as usize)
}
pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word) {
let ctx = unsafe { &mut *(ctx as *mut UnwindContext<'_>) };
unwinding::abi::_Unwind_SetIP(ctx, value as usize)
}
pub unsafe fn _Unwind_GetIPInfo(
ctx: *mut _Unwind_Context,
ip_before_insn: *mut c_int,
) -> _Unwind_Word {
let ctx = unsafe { &mut *(ctx as *mut UnwindContext<'_>) };
let ip_before_insn = unsafe { &mut *(ip_before_insn as *mut c_int) };
unsafe { &*(unwinding::abi::_Unwind_GetIPInfo(ctx, ip_before_insn) as _Unwind_Word) }
}
pub unsafe fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void {
let ctx = unsafe { &mut *(ctx as *mut UnwindContext<'_>) };
unwinding::abi::_Unwind_GetLanguageSpecificData(ctx)
}
pub unsafe fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code {
let exception = unsafe { &mut *(exception as *mut UnwindException) };
unsafe { core::mem::transmute(unwinding::abi::_Unwind_RaiseException(exception)) }
}
pub unsafe fn _Unwind_DeleteException(exception: *mut _Unwind_Exception) {
let exception = unsafe { &mut *(exception as *mut UnwindException) };
unsafe { unwinding::abi::_Unwind_DeleteException(exception) }
}