diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2016-04-08 16:18:40 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2016-05-09 08:22:36 -0700 |
| commit | 0ec321f7b541fcbfbf20286beb497e6d9d3352b2 (patch) | |
| tree | 30abd6498f7e3ae65fa94057e2bd46f6c769fcf2 /src/libunwind | |
| parent | 32683ce1930ef1390f20e4ab72650e6804fd1c1b (diff) | |
| download | rust-0ec321f7b541fcbfbf20286beb497e6d9d3352b2.tar.gz rust-0ec321f7b541fcbfbf20286beb497e6d9d3352b2.zip | |
rustc: Implement custom panic runtimes
This commit is an implementation of [RFC 1513] which allows applications to alter the behavior of panics at compile time. A new compiler flag, `-C panic`, is added and accepts the values `unwind` or `panic`, with the default being `unwind`. This model affects how code is generated for the local crate, skipping generation of landing pads with `-C panic=abort`. [RFC 1513]: https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md Panic implementations are then provided by crates tagged with `#![panic_runtime]` and lazily required by crates with `#![needs_panic_runtime]`. The panic strategy (`-C panic` value) of the panic runtime must match the final product, and if the panic strategy is not `abort` then the entire DAG must have the same panic strategy. With the `-C panic=abort` strategy, users can expect a stable method to disable generation of landing pads, improving optimization in niche scenarios, decreasing compile time, and decreasing output binary size. With the `-C panic=unwind` strategy users can expect the existing ability to isolate failure in Rust code from the outside world. Organizationally, this commit dismantles the `sys_common::unwind` module in favor of some bits moving part of it to `libpanic_unwind` and the rest into the `panicking` module in libstd. The custom panic runtime support is pretty similar to the custom allocator support with the only major difference being how the panic runtime is injected (takes the `-C panic` flag into account).
Diffstat (limited to 'src/libunwind')
| -rw-r--r-- | src/libunwind/Cargo.toml | 13 | ||||
| -rw-r--r-- | src/libunwind/build.rs | 39 | ||||
| -rw-r--r-- | src/libunwind/lib.rs | 30 | ||||
| -rw-r--r-- | src/libunwind/libunwind.rs | 247 |
4 files changed, 329 insertions, 0 deletions
diff --git a/src/libunwind/Cargo.toml b/src/libunwind/Cargo.toml new file mode 100644 index 00000000000..dca222c49d0 --- /dev/null +++ b/src/libunwind/Cargo.toml @@ -0,0 +1,13 @@ +[package] +authors = ["The Rust Project Developers"] +name = "unwind" +version = "0.0.0" +build = "build.rs" + +[lib] +name = "unwind" +path = "lib.rs" + +[dependencies] +core = { path = "../libcore" } +libc = { path = "../rustc/libc_shim" } diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs new file mode 100644 index 00000000000..ebe6fd54799 --- /dev/null +++ b/src/libunwind/build.rs @@ -0,0 +1,39 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::env; + +fn main() { + println!("cargo:rustc-cfg=cargobuild"); + + let target = env::var("TARGET").unwrap(); + + if target.contains("linux") { + if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) { + println!("cargo:rustc-link-lib=static=unwind"); + } else if !target.contains("android") { + println!("cargo:rustc-link-lib=gcc_s"); + } + } else if target.contains("freebsd") { + println!("cargo:rustc-link-lib=gcc_s"); + } else if target.contains("rumprun") { + println!("cargo:rustc-link-lib=unwind"); + } else if target.contains("netbsd") { + println!("cargo:rustc-link-lib=gcc_s"); + } else if target.contains("openbsd") { + println!("cargo:rustc-link-lib=gcc"); + } else if target.contains("bitrig") { + println!("cargo:rustc-link-lib=c++abi"); + } else if target.contains("dragonfly") { + println!("cargo:rustc-link-lib=gcc_pic"); + } else if target.contains("windows-gnu") { + println!("cargo:rustc-link-lib=gcc_eh"); + } +} diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs new file mode 100644 index 00000000000..3ff61fd93d7 --- /dev/null +++ b/src/libunwind/lib.rs @@ -0,0 +1,30 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![no_std] +#![crate_name = "unwind"] +#![crate_type = "rlib"] +#![unstable(feature = "panic_unwind", issue = "32837")] +#![cfg_attr(not(stage0), deny(warnings))] + +#![feature(cfg_target_vendor)] +#![feature(staged_api)] +#![feature(unwind_attributes)] + +#![cfg_attr(not(target_env = "msvc"), feature(libc))] + +#[cfg(not(target_env = "msvc"))] +extern crate libc; + +#[cfg(not(target_env = "msvc"))] +mod libunwind; +#[cfg(not(target_env = "msvc"))] +pub use libunwind::*; + diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs new file mode 100644 index 00000000000..ce74e5de3d4 --- /dev/null +++ b/src/libunwind/libunwind.rs @@ -0,0 +1,247 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![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, +} + +#[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 +} + +#[repr(C)] +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 EABI +} + +pub type _Unwind_Exception_Class = u64; + +pub type _Unwind_Word = libc::uintptr_t; + +pub type _Unwind_Trace_Fn = + extern fn(ctx: *mut _Unwind_Context, + arg: *mut libc::c_void) -> _Unwind_Reason_Code; + +#[cfg(target_arch = "x86")] +pub const unwinder_private_data_size: usize = 5; + +#[cfg(target_arch = "x86_64")] +pub const unwinder_private_data_size: usize = 6; + +#[cfg(all(target_arch = "arm", not(target_os = "ios")))] +pub const unwinder_private_data_size: usize = 20; + +#[cfg(all(target_arch = "arm", target_os = "ios"))] +pub const unwinder_private_data_size: usize = 5; + +#[cfg(target_arch = "aarch64")] +pub const unwinder_private_data_size: usize = 2; + +#[cfg(target_arch = "mips")] +pub const unwinder_private_data_size: usize = 2; + +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +pub const unwinder_private_data_size: usize = 2; + +#[cfg(target_arch = "asmjs")] +// FIXME: Copied from arm. Need to confirm. +pub const unwinder_private_data_size: usize = 20; + +#[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 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 {} + +extern { + // 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; + + #[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) +} + +// 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, + _UVRSR_NOT_IMPLEMENTED = 1, + _UVRSR_FAILED = 2, + } + #[repr(C)] + enum _Unwind_VRS_RegClass { + _UVRSC_CORE = 0, + _UVRSC_VFP = 1, + _UVRSC_FPA = 2, + _UVRSC_WMMXD = 3, + _UVRSC_WMMXC = 4, + } + #[repr(C)] + enum _Unwind_VRS_DataRepresentation { + _UVRSD_UINT32 = 0, + _UVRSD_VFPX = 1, + _UVRSD_FPAX = 2, + _UVRSD_UINT64 = 3, + _UVRSD_FLOAT = 4, + _UVRSD_DOUBLE = 5, + } + + type _Unwind_Word = libc::c_uint; + extern { + fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context, + klass: _Unwind_VRS_RegClass, + word: _Unwind_Word, + repr: _Unwind_VRS_DataRepresentation, + data: *mut libc::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 +} + +// 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) +} + +// 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 +} |
