Skip to content

Commit

Permalink
Auto merge of #117072 - betrusted-io:unwinding-crate-support, r=cuviper
Browse files Browse the repository at this point in the history
Use `unwinding` crate for unwinding on Xous platform

This patch adds support for using [unwinding](https://github.com/nbdd0121/unwinding) on platforms where libunwinding isn't viable. An example of such a platform is `riscv32imac-unknown-xous-elf`.

### Background

The Rust project maintains a fork of llvm at [llvm-project](https://github.com/rust-lang/llvm-project/) where it applies patches on top of the llvm project. This mostly seems to be to get unwinding support for the SGX project, and there may be other patches that I'm unaware of.

There is a lot of machinery in the build system to support compiling `libunwind` on other platforms, and I needed to add additional patches to llvm in order to add support for Xous.

Rather than continuing down this path, it seemed much easier to use a Rust-based library. The `unwinding` crate by `@nbdd0121` fits this description perfectly.

### Future work

This could potentially replace the custom patches for `libunwind` on other platforms such as SGX, and could enable unwinding support on many more exotic platforms.

### Anti-goals

This is not designed to replace `libunwind` on tier-one platforms or those where unwinding support already exists. There is already a well-established approach for unwinding there. Instead, this aims to enable unwinding on new platforms where C++ code may be difficult to compile.
  • Loading branch information
bors committed Dec 6, 2023
2 parents 2896841 + 0773afc commit 84a554c
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 8 deletions.
12 changes: 12 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5892,6 +5892,18 @@ dependencies = [
"compiler_builtins",
"core",
"libc",
"unwinding",
]

[[package]]
name = "unwinding"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b"
dependencies = [
"compiler_builtins",
"gimli",
"rustc-std-workspace-core",
]

[[package]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub fn target() -> Target {
cpu: "generic-rv32".into(),
max_atomic_width: Some(32),
features: "+m,+a,+c".into(),
panic_strategy: PanicStrategy::Abort,
panic_strategy: PanicStrategy::Unwind,
relocation_model: RelocModel::Static,
..Default::default()
},
Expand Down
1 change: 1 addition & 0 deletions library/panic_unwind/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ cfg_if::cfg_if! {
} else if #[cfg(any(
all(target_family = "windows", target_env = "gnu"),
target_os = "psp",
target_os = "xous",
target_os = "solid_asp3",
all(target_family = "unix", not(target_os = "espidf")),
all(target_vendor = "fortanix", target_env = "sgx"),
Expand Down
1 change: 1 addition & 0 deletions library/std/src/sys/personality/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ cfg_if::cfg_if! {
} else if #[cfg(any(
all(target_family = "windows", target_env = "gnu"),
target_os = "psp",
target_os = "xous",
target_os = "solid_asp3",
all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re")),
all(target_vendor = "fortanix", target_env = "sgx"),
Expand Down
29 changes: 28 additions & 1 deletion library/std/src/sys/xous/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,28 @@ use crate::marker::PhantomData;
use crate::os::xous::ffi::Error as XousError;
use crate::path::{self, PathBuf};

#[cfg(not(test))]
#[cfg(feature = "panic_unwind")]
mod eh_unwinding {
pub(crate) struct EhFrameFinder(usize /* eh_frame */);
pub(crate) static mut EH_FRAME_SETTINGS: EhFrameFinder = EhFrameFinder(0);
impl EhFrameFinder {
pub(crate) unsafe fn init(&mut self, eh_frame: usize) {
unsafe {
EH_FRAME_SETTINGS.0 = eh_frame;
}
}
}
unsafe impl unwind::EhFrameFinder for EhFrameFinder {
fn find(&self, _pc: usize) -> Option<unwind::FrameInfo> {
Some(unwind::FrameInfo {
text_base: None,
kind: unwind::FrameInfoKind::EhFrame(self.0),
})
}
}
}

#[cfg(not(test))]
mod c_compat {
use crate::os::xous::ffi::exit;
Expand All @@ -20,7 +42,12 @@ mod c_compat {
}

#[no_mangle]
pub extern "C" fn _start() {
pub extern "C" fn _start(eh_frame: usize) {
#[cfg(feature = "panic_unwind")]
unsafe {
super::eh_unwinding::EH_FRAME_SETTINGS.init(eh_frame);
unwind::set_custom_eh_frame_finder(&super::eh_unwinding::EH_FRAME_SETTINGS).ok();
}
exit(unsafe { main() });
}

Expand Down
5 changes: 4 additions & 1 deletion library/unwind/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions library/unwind/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
13 changes: 8 additions & 5 deletions library/unwind/src/libunwind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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" {
Expand Down Expand Up @@ -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" {
Expand Down Expand Up @@ -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" {
Expand Down
105 changes: 105 additions & 0 deletions library/unwind/src/unwinding.rs
Original file line number Diff line number Diff line change
@@ -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) }
}
1 change: 1 addition & 0 deletions src/tools/tidy/src/deps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
"unicode-security",
"unicode-width",
"unicode-xid",
"unwinding",
"valuable",
"version_check",
"wasi",
Expand Down

0 comments on commit 84a554c

Please sign in to comment.