diff options
| author | Vadim Chugunov <vadimcn@gmail.com> | 2016-07-23 17:25:25 -0700 |
|---|---|---|
| committer | Vadim Chugunov <vadimcn@gmail.com> | 2016-07-24 01:53:27 -0700 |
| commit | 6cef93d400b183d70c6c37856b46bb36d7bd8e16 (patch) | |
| tree | 19950ce8c9902c3960c6abc8f180e51da7920176 /src/libunwind | |
| parent | 2c50f4e484d1c871538ee99032ec2986177b8062 (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.rs | 292 |
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" {} |
