about summary refs log tree commit diff
path: root/src/libunwind
diff options
context:
space:
mode:
authorVadim Chugunov <vadimcn@gmail.com>2016-07-23 17:25:25 -0700
committerVadim Chugunov <vadimcn@gmail.com>2016-07-24 01:53:27 -0700
commit6cef93d400b183d70c6c37856b46bb36d7bd8e16 (patch)
tree19950ce8c9902c3960c6abc8f180e51da7920176 /src/libunwind
parent2c50f4e484d1c871538ee99032ec2986177b8062 (diff)
Implement ARM personality routine in Rust.
Remove the `eh_personality_catch` lang item.
Use a simplified version of `cfg_if!` in libunwind.
Diffstat (limited to 'src/libunwind')
-rw-r--r--src/libunwind/libunwind.rs292
1 files changed, 153 insertions, 139 deletions
diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs
index d9b6c9ed74d..5e242db0a88 100644
--- a/src/libunwind/libunwind.rs
+++ b/src/libunwind/libunwind.rs
@@ -10,38 +10,15 @@
 
 #![allow(bad_style)]
 
-use libc;
-
-#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
-pub use self::_Unwind_Action::*;
-#[cfg(target_arch = "arm")]
-pub use self::_Unwind_State::*;
-pub use self::_Unwind_Reason_Code::*;
-
-#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
-#[repr(C)]
-#[derive(Clone, Copy)]
-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,
+macro_rules! cfg_if {
+    ( $( if #[cfg( $meta:meta )] { $($it1:item)* } else { $($it2:item)* } )* ) =>
+        ( $( $( #[cfg($meta)] $it1)* $( #[cfg(not($meta))] $it2)* )* )
 }
 
-#[cfg(target_arch = "arm")]
-#[repr(C)]
-#[derive(Clone, Copy)]
-pub enum _Unwind_State {
-    _US_VIRTUAL_UNWIND_FRAME = 0,
-    _US_UNWIND_FRAME_STARTING = 1,
-    _US_UNWIND_FRAME_RESUME = 2,
-    _US_ACTION_MASK = 3,
-    _US_FORCE_UNWIND = 8,
-    _US_END_OF_STACK = 16,
-}
+use libc::{c_int, c_void, uintptr_t};
 
 #[repr(C)]
+#[derive(Copy, Clone, PartialEq)]
 pub enum _Unwind_Reason_Code {
     _URC_NO_REASON = 0,
     _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
@@ -52,17 +29,15 @@ pub enum _Unwind_Reason_Code {
     _URC_HANDLER_FOUND = 6,
     _URC_INSTALL_CONTEXT = 7,
     _URC_CONTINUE_UNWIND = 8,
-    _URC_FAILURE = 9, // used only by ARM EABI
+    _URC_FAILURE = 9, // used only by ARM EHABI
 }
+pub use self::_Unwind_Reason_Code::*;
 
 pub type _Unwind_Exception_Class = u64;
-
-pub type _Unwind_Word = libc::uintptr_t;
-pub type _Unwind_Ptr = libc::uintptr_t;
-
-pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut libc::c_void)
+pub type _Unwind_Word = uintptr_t;
+pub type _Unwind_Ptr = uintptr_t;
+pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void)
                                           -> _Unwind_Reason_Code;
-
 #[cfg(target_arch = "x86")]
 pub const unwinder_private_data_size: usize = 5;
 
@@ -99,91 +74,55 @@ pub enum _Unwind_Context {}
 
 pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reason_Code,
                                                       exception: *mut _Unwind_Exception);
-
-#[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")),
-               target_os = "freebsd",
-               target_os = "solaris",
-               all(target_os = "linux",
-                   target_env = "musl",
-                   not(target_arch = "x86"),
-                   not(target_arch = "x86_64"))),
-           link(name = "gcc_s"))]
-#[cfg_attr(all(target_os = "linux",
-               target_env = "musl",
-               any(target_arch = "x86", target_arch = "x86_64"),
-               not(test)),
-           link(name = "unwind", kind = "static"))]
-#[cfg_attr(any(target_os = "android", target_os = "openbsd"),
-           link(name = "gcc"))]
-#[cfg_attr(all(target_os = "netbsd", not(target_vendor = "rumprun")),
-           link(name = "gcc"))]
-#[cfg_attr(all(target_os = "netbsd", target_vendor = "rumprun"),
-           link(name = "unwind"))]
-#[cfg_attr(target_os = "dragonfly",
-           link(name = "gcc_pic"))]
-#[cfg_attr(target_os = "bitrig",
-           link(name = "c++abi"))]
-#[cfg_attr(all(target_os = "windows", target_env = "gnu"),
-           link(name = "gcc_eh"))]
-#[cfg(not(cargobuild))]
-extern "C" {}
-
 extern "C" {
-    // iOS on armv7 uses SjLj exceptions and requires to link
-    // against corresponding routine (..._SjLj_...)
-    #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
-    #[unwind]
-    pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
-
-    #[cfg(all(target_os = "ios", target_arch = "arm"))]
-    #[unwind]
-    fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
-
-    pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
-
     #[unwind]
     pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
-
-    // No native _Unwind_Backtrace on iOS
-    #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
-    pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
-                             trace_argument: *mut libc::c_void)
-                             -> _Unwind_Reason_Code;
-
-    // available since GCC 4.2.0, should be fine for our purpose
-    #[cfg(all(not(all(target_os = "android", target_arch = "arm")),
-              not(all(target_os = "linux", target_arch = "arm"))))]
-    pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
-                             ip_before_insn: *mut libc::c_int)
-                             -> libc::uintptr_t;
-
-    pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
+    pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
+    pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void;
     pub fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
     pub fn _Unwind_GetTextRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
     pub fn _Unwind_GetDataRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
-    pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: libc::c_int, value: _Unwind_Ptr);
-    pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Ptr);
-
-    #[cfg(all(not(target_os = "android"),
-              not(all(target_os = "linux", target_arch = "arm"))))]
-    pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) -> *mut libc::c_void;
 }
 
-// ... and now we just providing access to SjLj counterspart
-// through a standard name to hide those details from others
-// (see also comment above regarding _Unwind_RaiseException)
-#[cfg(all(target_os = "ios", target_arch = "arm"))]
-#[inline]
-pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception) -> _Unwind_Reason_Code {
-    _Unwind_SjLj_RaiseException(exc)
-}
+cfg_if! {
+if #[cfg(not(any(all(target_os = "android", target_arch = "arm"),
+                 all(target_os = "linux", target_arch = "arm"))))] {
+    // Not ARM EHABI
+    #[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 self::_Unwind_Action::*;
+
+    extern "C" {
+        pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word;
+        pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word);
+        pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> _Unwind_Word;
+        pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word);
+        pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, ip_before_insn: *mut c_int)
+                                 -> _Unwind_Word;
+        pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void;
+    }
+
+} else {
+    // ARM EHABI
+    #[repr(C)]
+    #[derive(Copy, Clone, PartialEq)]
+    pub enum _Unwind_State {
+        _US_VIRTUAL_UNWIND_FRAME = 0,
+        _US_UNWIND_FRAME_STARTING = 1,
+        _US_UNWIND_FRAME_RESUME = 2,
+        _US_ACTION_MASK = 3,
+        _US_FORCE_UNWIND = 8,
+        _US_END_OF_STACK = 16,
+    }
+    pub use self::_Unwind_State::*;
 
-// On android, the function _Unwind_GetIP is a macro, and this is the
-// expansion of the macro. This is all copy/pasted directly from the
-// header file with the definition of _Unwind_GetIP.
-#[cfg(any(all(target_os = "android", target_arch = "arm"),
-          all(target_os = "linux", target_arch = "arm")))]
-pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
     #[repr(C)]
     enum _Unwind_VRS_Result {
         _UVRSR_OK = 0,
@@ -198,6 +137,7 @@ pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
         _UVRSC_WMMXD = 3,
         _UVRSC_WMMXC = 4,
     }
+    use self::_Unwind_VRS_RegClass::*;
     #[repr(C)]
     enum _Unwind_VRS_DataRepresentation {
         _UVRSD_UINT32 = 0,
@@ -207,42 +147,116 @@ pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
         _UVRSD_FLOAT = 4,
         _UVRSD_DOUBLE = 5,
     }
+    use self::_Unwind_VRS_DataRepresentation::*;
+
+    pub const UNWIND_POINTER_REG: c_int = 12;
+    pub const UNWIND_IP_REG: c_int = 15;
 
-    type _Unwind_Word = libc::c_uint;
     extern "C" {
         fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
-                           klass: _Unwind_VRS_RegClass,
-                           word: _Unwind_Word,
+                           regclass: _Unwind_VRS_RegClass,
+                           regno: _Unwind_Word,
+                           repr: _Unwind_VRS_DataRepresentation,
+                           data: *mut c_void)
+                           -> _Unwind_VRS_Result;
+
+        fn _Unwind_VRS_Set(ctx: *mut _Unwind_Context,
+                           regclass: _Unwind_VRS_RegClass,
+                           regno: _Unwind_Word,
                            repr: _Unwind_VRS_DataRepresentation,
-                           data: *mut libc::c_void)
+                           data: *mut c_void)
                            -> _Unwind_VRS_Result;
     }
 
-    let mut val: _Unwind_Word = 0;
-    let ptr = &mut val as *mut _Unwind_Word;
-    let _ = _Unwind_VRS_Get(ctx,
-                            _Unwind_VRS_RegClass::_UVRSC_CORE,
-                            15,
-                            _Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
-                            ptr as *mut libc::c_void);
-    (val & !1) as libc::uintptr_t
-}
+    // On Android or ARM/Linux, these are implemented as macros:
+
+    pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word {
+        let mut val: _Unwind_Word = 0;
+        _Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
+                        &mut val as *mut _ as *mut c_void);
+        val
+    }
 
-// This function doesn't exist on Android or ARM/Linux, so make it same
-// to _Unwind_GetIP
-#[cfg(any(all(target_os = "android", target_arch = "arm"),
-          all(target_os = "linux", target_arch = "arm")))]
-pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
-                                ip_before_insn: *mut libc::c_int)
-                                -> libc::uintptr_t {
-    *ip_before_insn = 0;
-    _Unwind_GetIP(ctx)
+    pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) {
+        let mut value = value;
+        _Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
+                        &mut value as *mut _ as *mut c_void);
+    }
+
+    pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context)
+                                -> _Unwind_Word {
+        let val = _Unwind_GetGR(ctx, UNWIND_IP_REG);
+        (val & !1) as _Unwind_Word
+    }
+
+    pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context,
+                                value: _Unwind_Word) {
+        // Propagate thumb bit to instruction pointer
+        let thumb_state = _Unwind_GetGR(ctx, UNWIND_IP_REG) & 1;
+        let value = value | thumb_state;
+        _Unwind_SetGR(ctx, UNWIND_IP_REG, value);
+    }
+
+    pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
+                                    ip_before_insn: *mut c_int)
+                                    -> _Unwind_Word {
+        *ip_before_insn = 0;
+        _Unwind_GetIP(ctx)
+    }
+
+    // This function also doesn't exist on Android or ARM/Linux, so make it a no-op
+    pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
+        pc
+    }
 }
 
-// This function also doesn't exist on Android or ARM/Linux, so make it
-// a no-op
-#[cfg(any(target_os = "android",
-          all(target_os = "linux", target_arch = "arm")))]
-pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) -> *mut libc::c_void {
-    pc
+if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
+    // Not 32-bit iOS
+    extern "C" {
+        #[unwind]
+        pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
+        pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
+                                 trace_argument: *mut c_void)
+                                 -> _Unwind_Reason_Code;
+    }
+} else {
+    // 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace()
+    extern "C" {
+        #[unwind]
+        pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
+    }
+
+    #[inline]
+    pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception) -> _Unwind_Reason_Code {
+        _Unwind_SjLj_RaiseException(exc)
+    }
 }
+} // cfg_if!
+
+#[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")),
+               target_os = "freebsd",
+               target_os = "solaris",
+               all(target_os = "linux",
+                   target_env = "musl",
+                   not(target_arch = "x86"),
+                   not(target_arch = "x86_64"))),
+           link(name = "gcc_s"))]
+#[cfg_attr(all(target_os = "linux",
+               target_env = "musl",
+               any(target_arch = "x86", target_arch = "x86_64"),
+               not(test)),
+           link(name = "unwind", kind = "static"))]
+#[cfg_attr(any(target_os = "android", target_os = "openbsd"),
+           link(name = "gcc"))]
+#[cfg_attr(all(target_os = "netbsd", not(target_vendor = "rumprun")),
+           link(name = "gcc"))]
+#[cfg_attr(all(target_os = "netbsd", target_vendor = "rumprun"),
+           link(name = "unwind"))]
+#[cfg_attr(target_os = "dragonfly",
+           link(name = "gcc_pic"))]
+#[cfg_attr(target_os = "bitrig",
+           link(name = "c++abi"))]
+#[cfg_attr(all(target_os = "windows", target_env = "gnu"),
+           link(name = "gcc_eh"))]
+#[cfg(not(cargobuild))]
+extern "C" {}