about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-12-06 02:23:01 +0000
committerbors <bors@rust-lang.org>2023-12-06 02:23:01 +0000
commit84a554cda91d63c3b1241153f23eaa10ddd0292d (patch)
tree1af6add4a78c5553e27b7f7ff2de6e0df15c8612
parent28968414c57f12b827f01a5e6b99017b7ffa7370 (diff)
parent0773afc968d35bd6661bdbbe4c73fbb304c402ac (diff)
downloadrust-84a554cda91d63c3b1241153f23eaa10ddd0292d.tar.gz
rust-84a554cda91d63c3b1241153f23eaa10ddd0292d.zip
Auto merge of #117072 - betrusted-io:unwinding-crate-support, r=cuviper
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.
-rw-r--r--Cargo.lock12
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs2
-rw-r--r--library/panic_unwind/src/lib.rs1
-rw-r--r--library/std/src/sys/personality/mod.rs1
-rw-r--r--library/std/src/sys/xous/os.rs29
-rw-r--r--library/unwind/Cargo.toml5
-rw-r--r--library/unwind/src/lib.rs3
-rw-r--r--library/unwind/src/libunwind.rs13
-rw-r--r--library/unwind/src/unwinding.rs105
-rw-r--r--src/tools/tidy/src/deps.rs1
10 files changed, 164 insertions, 8 deletions
diff --git a/Cargo.lock b/Cargo.lock
index e1b5ea30f50..7f627e2ce6e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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]]
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs
index a263e5d5cde..ed0591ad918 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs
@@ -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()
         },
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs
index 9363fde5de2..7a0bae34642 100644
--- a/library/panic_unwind/src/lib.rs
+++ b/library/panic_unwind/src/lib.rs
@@ -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"),
diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs
index 386a399f532..0fff53f1887 100644
--- a/library/std/src/sys/personality/mod.rs
+++ b/library/std/src/sys/personality/mod.rs
@@ -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"),
diff --git a/library/std/src/sys/xous/os.rs b/library/std/src/sys/xous/os.rs
index 3d19fa4b31a..8d2eaee8aa6 100644
--- a/library/std/src/sys/xous/os.rs
+++ b/library/std/src/sys/xous/os.rs
@@ -8,6 +8,28 @@ 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;
     extern "C" {
@@ -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() });
     }
 
diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml
index 9aa552ed81a..b7418d1189c 100644
--- a/library/unwind/Cargo.toml
+++ b/library/unwind/Cargo.toml
@@ -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
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index 335bded71c1..eeee98f754e 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -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)
diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs
index dba64aa74ce..1b5f6f9dde3 100644
--- a/library/unwind/src/libunwind.rs
+++ b/library/unwind/src/libunwind.rs
@@ -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" {
diff --git a/library/unwind/src/unwinding.rs b/library/unwind/src/unwinding.rs
new file mode 100644
index 00000000000..1a4187b2220
--- /dev/null
+++ b/library/unwind/src/unwinding.rs
@@ -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) }
+}
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 6baf2e21604..b38d5436477 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -372,6 +372,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "unicode-security",
     "unicode-width",
     "unicode-xid",
+    "unwinding",
     "valuable",
     "version_check",
     "wasi",