mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
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).
This commit is contained in:
parent
32683ce193
commit
0ec321f7b5
16
mk/crates.mk
16
mk/crates.mk
@ -53,7 +53,8 @@ TARGET_CRATES := libc std term \
|
||||
getopts collections test rand \
|
||||
core alloc \
|
||||
rustc_unicode rustc_bitflags \
|
||||
alloc_system alloc_jemalloc
|
||||
alloc_system alloc_jemalloc \
|
||||
panic_abort panic_unwind unwind
|
||||
RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \
|
||||
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
|
||||
rustc_data_structures rustc_platform_intrinsics \
|
||||
@ -72,10 +73,18 @@ DEPS_libc := core
|
||||
DEPS_rand := core
|
||||
DEPS_rustc_bitflags := core
|
||||
DEPS_rustc_unicode := core
|
||||
DEPS_panic_abort := libc alloc
|
||||
DEPS_panic_unwind := libc alloc unwind
|
||||
DEPS_unwind := libc
|
||||
|
||||
# FIXME(stage0): change this to just `RUSTFLAGS_panic_abort := ...`
|
||||
RUSTFLAGS1_panic_abort := -C panic=abort
|
||||
RUSTFLAGS2_panic_abort := -C panic=abort
|
||||
RUSTFLAGS3_panic_abort := -C panic=abort
|
||||
|
||||
DEPS_std := core libc rand alloc collections rustc_unicode \
|
||||
native:backtrace \
|
||||
alloc_system
|
||||
alloc_system panic_abort panic_unwind unwind
|
||||
DEPS_arena := std
|
||||
DEPS_glob := std
|
||||
DEPS_flate := std native:miniz
|
||||
@ -148,6 +157,9 @@ ONLY_RLIB_rustc_unicode := 1
|
||||
ONLY_RLIB_rustc_bitflags := 1
|
||||
ONLY_RLIB_alloc_system := 1
|
||||
ONLY_RLIB_alloc_jemalloc := 1
|
||||
ONLY_RLIB_panic_unwind := 1
|
||||
ONLY_RLIB_panic_abort := 1
|
||||
ONLY_RLIB_unwind := 1
|
||||
|
||||
TARGET_SPECIFIC_alloc_jemalloc := 1
|
||||
|
||||
|
@ -23,7 +23,8 @@ DEPS_collectionstest :=
|
||||
$(eval $(call RUST_CRATE,collectionstest))
|
||||
|
||||
TEST_TARGET_CRATES = $(filter-out core rustc_unicode alloc_system libc \
|
||||
alloc_jemalloc,$(TARGET_CRATES)) \
|
||||
alloc_jemalloc panic_unwind \
|
||||
panic_abort,$(TARGET_CRATES)) \
|
||||
collectionstest coretest
|
||||
TEST_DOC_CRATES = $(DOC_CRATES) arena flate fmt_macros getopts graphviz \
|
||||
log rand rbml serialize syntax term test
|
||||
|
@ -48,10 +48,11 @@ fn main() {
|
||||
} else {
|
||||
env::var_os("RUSTC_REAL").unwrap()
|
||||
};
|
||||
let stage = env::var("RUSTC_STAGE").unwrap();
|
||||
|
||||
let mut cmd = Command::new(rustc);
|
||||
cmd.args(&args)
|
||||
.arg("--cfg").arg(format!("stage{}", env::var("RUSTC_STAGE").unwrap()));
|
||||
.arg("--cfg").arg(format!("stage{}", stage));
|
||||
|
||||
if let Some(target) = target {
|
||||
// The stage0 compiler has a special sysroot distinct from what we
|
||||
@ -78,6 +79,22 @@ fn main() {
|
||||
cmd.args(&s.split(" ").filter(|s| !s.is_empty()).collect::<Vec<_>>());
|
||||
}
|
||||
|
||||
// If we're compiling specifically the `panic_abort` crate then we pass
|
||||
// the `-C panic=abort` option. Note that we do not do this for any
|
||||
// other crate intentionally as this is the only crate for now that we
|
||||
// ship with panic=abort.
|
||||
//
|
||||
// This... is a bit of a hack how we detect this. Ideally this
|
||||
// information should be encoded in the crate I guess? Would likely
|
||||
// require an RFC amendment to RFC 1513, however.
|
||||
let is_panic_abort = args.windows(2).any(|a| {
|
||||
&*a[0] == "--crate-name" && &*a[1] == "panic_abort"
|
||||
});
|
||||
// FIXME(stage0): remove this `stage != "0"` condition
|
||||
if is_panic_abort && stage != "0" {
|
||||
cmd.arg("-C").arg("panic=abort");
|
||||
}
|
||||
|
||||
// Set various options from config.toml to configure how we're building
|
||||
// code.
|
||||
if env::var("RUSTC_DEBUGINFO") == Ok("true".to_string()) {
|
||||
|
@ -18,10 +18,8 @@
|
||||
form or name",
|
||||
issue = "27783")]
|
||||
#![feature(allocator)]
|
||||
#![feature(libc)]
|
||||
#![feature(staged_api)]
|
||||
|
||||
extern crate libc;
|
||||
#![cfg_attr(unix, feature(libc))]
|
||||
|
||||
// The minimum alignment guaranteed by the architecture. This value is used to
|
||||
// add fast paths for low alignment values. In practice, the alignment is a
|
||||
@ -72,9 +70,10 @@ pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
|
||||
|
||||
#[cfg(unix)]
|
||||
mod imp {
|
||||
extern crate libc;
|
||||
|
||||
use core::cmp;
|
||||
use core::ptr;
|
||||
use libc;
|
||||
use MIN_ALIGN;
|
||||
|
||||
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
|
||||
|
11
src/libpanic_abort/Cargo.toml
Normal file
11
src/libpanic_abort/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
name = "panic_abort"
|
||||
version = "0.0.0"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
core = { path = "../libcore" }
|
||||
libc = { path = "../rustc/libc_shim" }
|
112
src/libpanic_abort/lib.rs
Normal file
112
src/libpanic_abort/lib.rs
Normal file
@ -0,0 +1,112 @@
|
||||
// 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.
|
||||
|
||||
//! Implementation of Rust panics via process aborts
|
||||
//!
|
||||
//! When compared to the implementation via unwinding, this crate is *much*
|
||||
//! simpler! That being said, it's not quite as versatile, but here goes!
|
||||
|
||||
#![no_std]
|
||||
#![crate_name = "panic_abort"]
|
||||
#![crate_type = "rlib"]
|
||||
#![unstable(feature = "panic_abort", issue = "32837")]
|
||||
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/",
|
||||
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
|
||||
#![feature(staged_api)]
|
||||
|
||||
#![cfg_attr(not(stage0), panic_runtime)]
|
||||
#![cfg_attr(not(stage0), feature(panic_runtime))]
|
||||
#![cfg_attr(unix, feature(libc))]
|
||||
#![cfg_attr(windows, feature(core_intrinsics))]
|
||||
|
||||
// Rust's "try" function, but if we're aborting on panics we just call the
|
||||
// function as there's nothing else we need to do here.
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8),
|
||||
data: *mut u8,
|
||||
_data_ptr: *mut usize,
|
||||
_vtable_ptr: *mut usize) -> u32 {
|
||||
f(data);
|
||||
0
|
||||
}
|
||||
|
||||
// "Leak" the payload and shim to the relevant abort on the platform in
|
||||
// question.
|
||||
//
|
||||
// For Unix we just use `abort` from libc as it'll trigger debuggers, core
|
||||
// dumps, etc, as one might expect. On Windows, however, the best option we have
|
||||
// is the `__fastfail` intrinsics, but that's unfortunately not defined in LLVM,
|
||||
// and the `RaiseFailFastException` function isn't available until Windows 7
|
||||
// which would break compat with XP. For now just use `intrinsics::abort` which
|
||||
// will kill us with an illegal instruction, which will do a good enough job for
|
||||
// now hopefully.
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 {
|
||||
return abort();
|
||||
|
||||
#[cfg(unix)]
|
||||
unsafe fn abort() -> ! {
|
||||
extern crate libc;
|
||||
libc::abort();
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
unsafe fn abort() -> ! {
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
}
|
||||
|
||||
// This... is a bit of an oddity. The tl;dr; is that this is required to link
|
||||
// correctly, the longer explanation is below.
|
||||
//
|
||||
// Right now the binaries of libcore/libstd that we ship are all compiled with
|
||||
// `-C panic=unwind`. This is done to ensure that the binaries are maximally
|
||||
// compatible with as many situations as possible. The compiler, however,
|
||||
// requires a "personality function" for all functions compiled with `-C
|
||||
// panic=unwind`. This personality function is hardcoded to the symbol
|
||||
// `rust_eh_personality` and is defined by the `eh_personality` lang item.
|
||||
//
|
||||
// So... why not just define that lang item here? Good question! The way that
|
||||
// panic runtimes are linked in is actually a little subtle in that they're
|
||||
// "sort of" in the compiler's crate store, but only actually linked if another
|
||||
// isn't actually linked. This ends up meaning that both this crate and the
|
||||
// panic_unwind crate can appear in the compiler's crate store, and if both
|
||||
// define the `eh_personality` lang item then that'll hit an error.
|
||||
//
|
||||
// To handle this the compiler only requires the `eh_personality` is defined if
|
||||
// the panic runtime being linked in is the unwinding runtime, and otherwise
|
||||
// it's not required to be defined (rightfully so). In this case, however, this
|
||||
// library just defines this symbol so there's at least some personality
|
||||
// somewhere.
|
||||
//
|
||||
// Essentially this symbol is just defined to get wired up to libcore/libstd
|
||||
// binaries, but it should never be called as we don't link in an unwinding
|
||||
// runtime at all.
|
||||
#[no_mangle]
|
||||
#[cfg(not(stage0))]
|
||||
pub extern fn rust_eh_personality() {}
|
||||
|
||||
// Similar to above, this corresponds to the `eh_unwind_resume` lang item that's
|
||||
// only used on Windows currently.
|
||||
#[no_mangle]
|
||||
#[cfg(all(not(stage0), target_os = "windows", target_env = "gnu"))]
|
||||
pub extern fn rust_eh_unwind_resume() {}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(all(target_os = "windows", target_env = "gnu", target_arch = "x86"))]
|
||||
pub extern fn rust_eh_register_frames() {}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(all(target_os = "windows", target_env = "gnu", target_arch = "x86"))]
|
||||
pub extern fn rust_eh_unregister_frames() {}
|
27
src/libpanic_unwind/Cargo.lock
generated
Normal file
27
src/libpanic_unwind/Cargo.lock
generated
Normal file
@ -0,0 +1,27 @@
|
||||
[root]
|
||||
name = "panic_unwind"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"alloc 0.0.0",
|
||||
"core 0.0.0",
|
||||
"libc 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloc"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"core 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"core 0.0.0",
|
||||
]
|
||||
|
13
src/libpanic_unwind/Cargo.toml
Normal file
13
src/libpanic_unwind/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
name = "panic_unwind"
|
||||
version = "0.0.0"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
alloc = { path = "../liballoc" }
|
||||
core = { path = "../libcore" }
|
||||
libc = { path = "../rustc/libc_shim" }
|
||||
unwind = { path = "../libunwind" }
|
@ -21,8 +21,7 @@
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(unused)]
|
||||
|
||||
use prelude::v1::*;
|
||||
use sys_common::dwarf::DwarfReader;
|
||||
use dwarf::DwarfReader;
|
||||
use core::mem;
|
||||
|
||||
pub const DW_EH_PE_omit : u8 = 0xFF;
|
@ -18,7 +18,6 @@
|
||||
|
||||
pub mod eh;
|
||||
|
||||
use prelude::v1::*;
|
||||
use core::mem;
|
||||
|
||||
pub struct DwarfReader {
|
@ -8,30 +8,76 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Implementation of panics backed by libgcc/libunwind (in some form)
|
||||
//!
|
||||
//! For background on exception handling and stack unwinding please see
|
||||
//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
|
||||
//! documents linked from it.
|
||||
//! These are also good reads:
|
||||
//! http://mentorembedded.github.io/cxx-abi/abi-eh.html
|
||||
//! http://monoinfinito.wordpress.com/series/exception-handling-in-c/
|
||||
//! http://www.airs.com/blog/index.php?s=exception+frames
|
||||
//!
|
||||
//! ## A brief summary
|
||||
//!
|
||||
//! Exception handling happens in two phases: a search phase and a cleanup
|
||||
//! phase.
|
||||
//!
|
||||
//! In both phases the unwinder walks stack frames from top to bottom using
|
||||
//! information from the stack frame unwind sections of the current process's
|
||||
//! modules ("module" here refers to an OS module, i.e. an executable or a
|
||||
//! dynamic library).
|
||||
//!
|
||||
//! For each stack frame, it invokes the associated "personality routine", whose
|
||||
//! address is also stored in the unwind info section.
|
||||
//!
|
||||
//! In the search phase, the job of a personality routine is to examine
|
||||
//! exception object being thrown, and to decide whether it should be caught at
|
||||
//! that stack frame. Once the handler frame has been identified, cleanup phase
|
||||
//! begins.
|
||||
//!
|
||||
//! In the cleanup phase, the unwinder invokes each personality routine again.
|
||||
//! This time it decides which (if any) cleanup code needs to be run for
|
||||
//! the current stack frame. If so, the control is transferred to a special
|
||||
//! branch in the function body, the "landing pad", which invokes destructors,
|
||||
//! frees memory, etc. At the end of the landing pad, control is transferred
|
||||
//! back to the unwinder and unwinding resumes.
|
||||
//!
|
||||
//! Once stack has been unwound down to the handler frame level, unwinding stops
|
||||
//! and the last personality routine transfers control to the catch block.
|
||||
//!
|
||||
//! ## `eh_personality` and `eh_unwind_resume`
|
||||
//!
|
||||
//! These language items are used by the compiler when generating unwind info.
|
||||
//! The first one is the personality routine described above. The second one
|
||||
//! allows compilation target to customize the process of resuming unwind at the
|
||||
//! end of the landing pads. `eh_unwind_resume` is used only if
|
||||
//! `custom_unwind_resume` flag in the target options is set.
|
||||
|
||||
#![allow(private_no_mangle_fns)]
|
||||
|
||||
use prelude::v1::*;
|
||||
use core::any::Any;
|
||||
use alloc::boxed::Box;
|
||||
|
||||
use any::Any;
|
||||
use sys_common::libunwind as uw;
|
||||
use unwind as uw;
|
||||
|
||||
#[repr(C)]
|
||||
struct Exception {
|
||||
uwe: uw::_Unwind_Exception,
|
||||
cause: Option<Box<Any + Send + 'static>>,
|
||||
_uwe: uw::_Unwind_Exception,
|
||||
cause: Option<Box<Any + Send>>,
|
||||
}
|
||||
|
||||
pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
|
||||
let exception: Box<_> = box Exception {
|
||||
uwe: uw::_Unwind_Exception {
|
||||
pub unsafe fn panic(data: Box<Any + Send>) -> u32 {
|
||||
let exception = Box::new(Exception {
|
||||
_uwe: uw::_Unwind_Exception {
|
||||
exception_class: rust_exception_class(),
|
||||
exception_cleanup: exception_cleanup,
|
||||
private: [0; uw::unwinder_private_data_size],
|
||||
},
|
||||
cause: Some(data),
|
||||
};
|
||||
});
|
||||
let exception_param = Box::into_raw(exception) as *mut uw::_Unwind_Exception;
|
||||
let error = uw::_Unwind_RaiseException(exception_param);
|
||||
rtabort!("Could not unwind stack, error = {}", error as isize);
|
||||
return uw::_Unwind_RaiseException(exception_param) as u32;
|
||||
|
||||
extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
|
||||
exception: *mut uw::_Unwind_Exception) {
|
||||
@ -45,7 +91,7 @@ pub fn payload() -> *mut u8 {
|
||||
0 as *mut u8
|
||||
}
|
||||
|
||||
pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
|
||||
pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
|
||||
let my_ep = ptr as *mut Exception;
|
||||
let cause = (*my_ep).cause.take();
|
||||
uw::_Unwind_DeleteException(ptr as *mut _);
|
||||
@ -59,7 +105,7 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
|
||||
0x4d4f5a_00_52555354
|
||||
}
|
||||
|
||||
// We could implement our personality routine in pure Rust, however exception
|
||||
// We could implement our personality routine in Rust, however exception
|
||||
// info decoding is tedious. More importantly, personality routines have to
|
||||
// handle various platform quirks, which are not fun to maintain. For this
|
||||
// reason, we attempt to reuse personality routine of the C language:
|
||||
@ -79,10 +125,9 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
|
||||
// See also: rustc_trans::trans::intrinsic::trans_gnu_try
|
||||
|
||||
#[cfg(all(not(target_arch = "arm"),
|
||||
not(all(windows, target_arch = "x86_64")),
|
||||
not(test)))]
|
||||
not(all(windows, target_arch = "x86_64"))))]
|
||||
pub mod eabi {
|
||||
use sys_common::libunwind as uw;
|
||||
use unwind as uw;
|
||||
use libc::c_int;
|
||||
|
||||
extern {
|
||||
@ -136,9 +181,9 @@ pub mod eabi {
|
||||
// iOS on armv7 is using SjLj exceptions and therefore requires to use
|
||||
// a specialized personality routine: __gcc_personality_sj0
|
||||
|
||||
#[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
|
||||
#[cfg(all(target_os = "ios", target_arch = "arm"))]
|
||||
pub mod eabi {
|
||||
use sys_common::libunwind as uw;
|
||||
use unwind as uw;
|
||||
use libc::c_int;
|
||||
|
||||
extern {
|
||||
@ -191,9 +236,9 @@ pub mod eabi {
|
||||
|
||||
// ARM EHABI uses a slightly different personality routine signature,
|
||||
// but otherwise works the same.
|
||||
#[cfg(all(target_arch = "arm", not(target_os = "ios"), not(test)))]
|
||||
#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
|
||||
pub mod eabi {
|
||||
use sys_common::libunwind as uw;
|
||||
use unwind as uw;
|
||||
use libc::c_int;
|
||||
|
||||
extern {
|
||||
@ -242,19 +287,31 @@ pub mod eabi {
|
||||
}
|
||||
|
||||
// See docs in the `unwind` module.
|
||||
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu", not(test)))]
|
||||
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
|
||||
#[lang = "eh_unwind_resume"]
|
||||
#[unwind]
|
||||
unsafe extern fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! {
|
||||
uw::_Unwind_Resume(panic_ctx as *mut uw::_Unwind_Exception);
|
||||
}
|
||||
|
||||
// Frame unwind info registration
|
||||
//
|
||||
// Each module's image contains a frame unwind info section (usually
|
||||
// ".eh_frame"). When a module is loaded/unloaded into the process, the
|
||||
// unwinder must be informed about the location of this section in memory. The
|
||||
// methods of achieving that vary by the platform. On some (e.g. Linux), the
|
||||
// unwinder can discover unwind info sections on its own (by dynamically
|
||||
// enumerating currently loaded modules via the dl_iterate_phdr() API and
|
||||
// finding their ".eh_frame" sections); Others, like Windows, require modules
|
||||
// to actively register their unwind info sections via unwinder API.
|
||||
//
|
||||
// This module defines two symbols which are referenced and called from
|
||||
// rsbegin.rs to reigster our information with the GCC runtime. The
|
||||
// implementation of stack unwinding is (for now) deferred to libgcc_eh, however
|
||||
// Rust crates use these Rust-specific entry points to avoid potential clashes
|
||||
// with any GCC runtime.
|
||||
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
|
||||
pub mod eh_frame_registry {
|
||||
// The implementation of stack unwinding is (for now) deferred to libgcc_eh, however Rust
|
||||
// crates use these Rust-specific entry points to avoid potential clashes with GCC runtime.
|
||||
// See also: rtbegin.rs, `unwind` module.
|
||||
|
||||
#[link(name = "gcc_eh")]
|
||||
#[cfg(not(cargobuild))]
|
||||
extern {}
|
||||
@ -263,16 +320,14 @@ pub mod eh_frame_registry {
|
||||
fn __register_frame_info(eh_frame_begin: *const u8, object: *mut u8);
|
||||
fn __deregister_frame_info(eh_frame_begin: *const u8, object: *mut u8);
|
||||
}
|
||||
#[cfg(not(test))]
|
||||
|
||||
#[no_mangle]
|
||||
#[unstable(feature = "libstd_sys_internals", issue = "0")]
|
||||
pub unsafe extern fn rust_eh_register_frames(eh_frame_begin: *const u8,
|
||||
object: *mut u8) {
|
||||
__register_frame_info(eh_frame_begin, object);
|
||||
}
|
||||
#[cfg(not(test))]
|
||||
|
||||
#[no_mangle]
|
||||
#[unstable(feature = "libstd_sys_internals", issue = "0")]
|
||||
pub unsafe extern fn rust_eh_unregister_frames(eh_frame_begin: *const u8,
|
||||
object: *mut u8) {
|
||||
__deregister_frame_info(eh_frame_begin, object);
|
109
src/libpanic_unwind/lib.rs
Normal file
109
src/libpanic_unwind/lib.rs
Normal file
@ -0,0 +1,109 @@
|
||||
// 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.
|
||||
|
||||
//! Implementation of panics via stack unwinding
|
||||
//!
|
||||
//! This crate is an implementation of panics in Rust using "most native" stack
|
||||
//! unwinding mechanism of the platform this is being compiled for. This
|
||||
//! essentially gets categorized into three buckets currently:
|
||||
//!
|
||||
//! 1. MSVC targets use SEH in the `seh.rs` file.
|
||||
//! 2. The 64-bit MinGW target half-uses SEH and half-use gcc-like information
|
||||
//! in the `seh64_gnu.rs` module.
|
||||
//! 3. All other targets use libunwind/libgcc in the `gcc/mod.rs` module.
|
||||
//!
|
||||
//! More documentation about each implementation can be found in the respective
|
||||
//! module.
|
||||
|
||||
#![no_std]
|
||||
#![crate_name = "panic_unwind"]
|
||||
#![crate_type = "rlib"]
|
||||
#![unstable(feature = "panic_unwind", issue = "32837")]
|
||||
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/",
|
||||
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
|
||||
#![feature(alloc)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(lang_items)]
|
||||
#![feature(libc)]
|
||||
#![feature(panic_unwind)]
|
||||
#![feature(raw)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(unwind_attributes)]
|
||||
#![cfg_attr(target_env = "msvc", feature(raw))]
|
||||
|
||||
#![cfg_attr(not(stage0), panic_runtime)]
|
||||
#![cfg_attr(not(stage0), feature(panic_runtime))]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate libc;
|
||||
extern crate unwind;
|
||||
|
||||
use core::intrinsics;
|
||||
use core::mem;
|
||||
use core::raw;
|
||||
|
||||
// Rust runtime's startup objects depend on these symbols, so make them public.
|
||||
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
|
||||
pub use imp::eh_frame_registry::*;
|
||||
|
||||
// *-pc-windows-msvc
|
||||
#[cfg(target_env = "msvc")]
|
||||
#[path = "seh.rs"]
|
||||
mod imp;
|
||||
|
||||
// x86_64-pc-windows-gnu
|
||||
#[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))]
|
||||
#[path = "seh64_gnu.rs"]
|
||||
mod imp;
|
||||
|
||||
// i686-pc-windows-gnu and all others
|
||||
#[cfg(any(unix, all(windows, target_arch = "x86", target_env = "gnu")))]
|
||||
#[path = "gcc.rs"]
|
||||
mod imp;
|
||||
|
||||
mod dwarf;
|
||||
mod windows;
|
||||
|
||||
// Entry point for catching an exception, implemented using the `try` intrinsic
|
||||
// in the compiler.
|
||||
//
|
||||
// The interaction between the `payload` function and the compiler is pretty
|
||||
// hairy and tightly coupled, for more information see the compiler's
|
||||
// implementation of this.
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8),
|
||||
data: *mut u8,
|
||||
data_ptr: *mut usize,
|
||||
vtable_ptr: *mut usize)
|
||||
-> u32 {
|
||||
let mut payload = imp::payload();
|
||||
if intrinsics::try(f, data, &mut payload as *mut _ as *mut _) == 0 {
|
||||
0
|
||||
} else {
|
||||
let obj = mem::transmute::<_, raw::TraitObject>(imp::cleanup(payload));
|
||||
*data_ptr = obj.data as usize;
|
||||
*vtable_ptr = obj.vtable as usize;
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
// Entry point for raising an exception, just delegates to the platform-specific
|
||||
// implementation.
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn __rust_start_panic(data: usize, vtable: usize) -> u32 {
|
||||
imp::panic(mem::transmute(raw::TraitObject {
|
||||
data: data as *mut (),
|
||||
vtable: vtable as *mut (),
|
||||
}))
|
||||
}
|
@ -45,7 +45,7 @@
|
||||
//! the precise codegen for this was lifted from an LLVM test case for SEH
|
||||
//! (this is the `__rust_try_filter` function below).
|
||||
//! * We've got some data to transmit across the unwinding boundary,
|
||||
//! specifically a `Box<Any + Send + 'static>`. Like with Dwarf exceptions
|
||||
//! specifically a `Box<Any + Send>`. Like with Dwarf exceptions
|
||||
//! these two pointers are stored as a payload in the exception itself. On
|
||||
//! MSVC, however, there's no need for an extra allocation because the call
|
||||
//! stack is preserved while filter functions are being executed. This means
|
||||
@ -56,90 +56,84 @@
|
||||
//! [win64]: http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx
|
||||
//! [llvm]: http://llvm.org/docs/ExceptionHandling.html#background-on-windows-exceptions
|
||||
|
||||
use sys::c;
|
||||
use alloc::boxed::Box;
|
||||
use core::any::Any;
|
||||
use core::intrinsics;
|
||||
use core::mem;
|
||||
use core::raw;
|
||||
|
||||
use windows as c;
|
||||
|
||||
// A code which indicates panics that originate from Rust. Note that some of the
|
||||
// upper bits are used by the system so we just set them to 0 and ignore them.
|
||||
// 0x 0 R S T
|
||||
const RUST_PANIC: c::DWORD = 0x00525354;
|
||||
|
||||
pub use self::imp::*;
|
||||
|
||||
mod imp {
|
||||
use prelude::v1::*;
|
||||
|
||||
use any::Any;
|
||||
use mem;
|
||||
use raw;
|
||||
use super::RUST_PANIC;
|
||||
use sys::c;
|
||||
|
||||
pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
|
||||
// As mentioned above, the call stack here is preserved while the filter
|
||||
// functions are running, so it's ok to pass stack-local arrays into
|
||||
// `RaiseException`.
|
||||
//
|
||||
// The two pointers of the `data` trait object are written to the stack,
|
||||
// passed to `RaiseException`, and they're later extracted by the filter
|
||||
// function below in the "custom exception information" section of the
|
||||
// `EXCEPTION_RECORD` type.
|
||||
let ptrs = mem::transmute::<_, raw::TraitObject>(data);
|
||||
let ptrs = [ptrs.data, ptrs.vtable];
|
||||
c::RaiseException(RUST_PANIC, 0, 2, ptrs.as_ptr() as *mut _);
|
||||
rtabort!("could not unwind stack");
|
||||
}
|
||||
|
||||
pub fn payload() -> [usize; 2] {
|
||||
[0; 2]
|
||||
}
|
||||
|
||||
pub unsafe fn cleanup(payload: [usize; 2]) -> Box<Any + Send + 'static> {
|
||||
mem::transmute(raw::TraitObject {
|
||||
data: payload[0] as *mut _,
|
||||
vtable: payload[1] as *mut _,
|
||||
})
|
||||
}
|
||||
|
||||
// This is quite a special function, and it's not literally passed in as the
|
||||
// filter function for the `catchpad` of the `try` intrinsic. The compiler
|
||||
// actually generates its own filter function wrapper which will delegate to
|
||||
// this for the actual execution logic for whether the exception should be
|
||||
// caught. The reasons for this are:
|
||||
pub unsafe fn panic(data: Box<Any + Send>) -> u32 {
|
||||
// As mentioned above, the call stack here is preserved while the filter
|
||||
// functions are running, so it's ok to pass stack-local arrays into
|
||||
// `RaiseException`.
|
||||
//
|
||||
// * Each architecture has a slightly different ABI for the filter function
|
||||
// here. For example on x86 there are no arguments but on x86_64 there are
|
||||
// two.
|
||||
// * This function needs access to the stack frame of the `try` intrinsic
|
||||
// which is using this filter as a catch pad. This is because the payload
|
||||
// of this exception, `Box<Any>`, needs to be transmitted to that
|
||||
// location.
|
||||
//
|
||||
// Both of these differences end up using a ton of weird llvm-specific
|
||||
// intrinsics, so it's actually pretty difficult to express the entire
|
||||
// filter function in Rust itself. As a compromise, the compiler takes care
|
||||
// of all the weird LLVM-specific and platform-specific stuff, getting to
|
||||
// the point where this function makes the actual decision about what to
|
||||
// catch given two parameters.
|
||||
//
|
||||
// The first parameter is `*mut EXCEPTION_POINTERS` which is some contextual
|
||||
// information about the exception being filtered, and the second pointer is
|
||||
// `*mut *mut [usize; 2]` (the payload here). This value points directly
|
||||
// into the stack frame of the `try` intrinsic itself, and we use it to copy
|
||||
// information from the exception onto the stack.
|
||||
#[lang = "msvc_try_filter"]
|
||||
#[cfg(not(test))]
|
||||
unsafe extern fn __rust_try_filter(eh_ptrs: *mut u8,
|
||||
payload: *mut u8) -> i32 {
|
||||
let eh_ptrs = eh_ptrs as *mut c::EXCEPTION_POINTERS;
|
||||
let payload = payload as *mut *mut [usize; 2];
|
||||
let record = &*(*eh_ptrs).ExceptionRecord;
|
||||
if record.ExceptionCode != RUST_PANIC {
|
||||
return 0
|
||||
}
|
||||
(**payload)[0] = record.ExceptionInformation[0] as usize;
|
||||
(**payload)[1] = record.ExceptionInformation[1] as usize;
|
||||
return 1
|
||||
// The two pointers of the `data` trait object are written to the stack,
|
||||
// passed to `RaiseException`, and they're later extracted by the filter
|
||||
// function below in the "custom exception information" section of the
|
||||
// `EXCEPTION_RECORD` type.
|
||||
let ptrs = mem::transmute::<_, raw::TraitObject>(data);
|
||||
let ptrs = [ptrs.data, ptrs.vtable];
|
||||
c::RaiseException(RUST_PANIC, 0, 2, ptrs.as_ptr() as *mut _);
|
||||
u32::max_value()
|
||||
}
|
||||
|
||||
pub fn payload() -> [usize; 2] {
|
||||
[0; 2]
|
||||
}
|
||||
|
||||
pub unsafe fn cleanup(payload: [usize; 2]) -> Box<Any + Send> {
|
||||
mem::transmute(raw::TraitObject {
|
||||
data: payload[0] as *mut _,
|
||||
vtable: payload[1] as *mut _,
|
||||
})
|
||||
}
|
||||
|
||||
// This is quite a special function, and it's not literally passed in as the
|
||||
// filter function for the `catchpad` of the `try` intrinsic. The compiler
|
||||
// actually generates its own filter function wrapper which will delegate to
|
||||
// this for the actual execution logic for whether the exception should be
|
||||
// caught. The reasons for this are:
|
||||
//
|
||||
// * Each architecture has a slightly different ABI for the filter function
|
||||
// here. For example on x86 there are no arguments but on x86_64 there are
|
||||
// two.
|
||||
// * This function needs access to the stack frame of the `try` intrinsic
|
||||
// which is using this filter as a catch pad. This is because the payload
|
||||
// of this exception, `Box<Any>`, needs to be transmitted to that
|
||||
// location.
|
||||
//
|
||||
// Both of these differences end up using a ton of weird llvm-specific
|
||||
// intrinsics, so it's actually pretty difficult to express the entire
|
||||
// filter function in Rust itself. As a compromise, the compiler takes care
|
||||
// of all the weird LLVM-specific and platform-specific stuff, getting to
|
||||
// the point where this function makes the actual decision about what to
|
||||
// catch given two parameters.
|
||||
//
|
||||
// The first parameter is `*mut EXCEPTION_POINTERS` which is some contextual
|
||||
// information about the exception being filtered, and the second pointer is
|
||||
// `*mut *mut [usize; 2]` (the payload here). This value points directly
|
||||
// into the stack frame of the `try` intrinsic itself, and we use it to copy
|
||||
// information from the exception onto the stack.
|
||||
#[lang = "msvc_try_filter"]
|
||||
#[cfg(not(test))]
|
||||
unsafe extern fn __rust_try_filter(eh_ptrs: *mut u8,
|
||||
payload: *mut u8) -> i32 {
|
||||
let eh_ptrs = eh_ptrs as *mut c::EXCEPTION_POINTERS;
|
||||
let payload = payload as *mut *mut [usize; 2];
|
||||
let record = &*(*eh_ptrs).ExceptionRecord;
|
||||
if record.ExceptionCode != RUST_PANIC {
|
||||
return 0
|
||||
}
|
||||
(**payload)[0] = record.ExceptionInformation[0] as usize;
|
||||
(**payload)[1] = record.ExceptionInformation[1] as usize;
|
||||
return 1
|
||||
}
|
||||
|
||||
// This is required by the compiler to exist (e.g. it's a lang item), but
|
||||
@ -149,5 +143,5 @@ mod imp {
|
||||
#[lang = "eh_personality"]
|
||||
#[cfg(not(test))]
|
||||
fn rust_eh_personality() {
|
||||
unsafe { ::intrinsics::abort() }
|
||||
unsafe { intrinsics::abort() }
|
||||
}
|
@ -14,13 +14,12 @@
|
||||
#![allow(bad_style)]
|
||||
#![allow(private_no_mangle_fns)]
|
||||
|
||||
use prelude::v1::*;
|
||||
use alloc::boxed::Box;
|
||||
|
||||
use any::Any;
|
||||
use sys_common::dwarf::eh;
|
||||
use core::mem;
|
||||
use core::ptr;
|
||||
use sys::c;
|
||||
use core::any::Any;
|
||||
use core::intrinsics;
|
||||
use dwarf::eh;
|
||||
use windows as c;
|
||||
|
||||
// Define our exception codes:
|
||||
// according to http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx,
|
||||
@ -37,24 +36,24 @@ const RUST_PANIC: c::DWORD = ETYPE | (1 << 24) | MAGIC;
|
||||
|
||||
#[repr(C)]
|
||||
struct PanicData {
|
||||
data: Box<Any + Send + 'static>
|
||||
data: Box<Any + Send>
|
||||
}
|
||||
|
||||
pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
|
||||
pub unsafe fn panic(data: Box<Any + Send>) -> u32 {
|
||||
let panic_ctx = Box::new(PanicData { data: data });
|
||||
let params = [Box::into_raw(panic_ctx) as c::ULONG_PTR];
|
||||
c::RaiseException(RUST_PANIC,
|
||||
c::EXCEPTION_NONCONTINUABLE,
|
||||
params.len() as c::DWORD,
|
||||
¶ms as *const c::ULONG_PTR);
|
||||
rtabort!("could not unwind stack");
|
||||
u32::max_value()
|
||||
}
|
||||
|
||||
pub fn payload() -> *mut u8 {
|
||||
0 as *mut u8
|
||||
}
|
||||
|
||||
pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
|
||||
pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
|
||||
let panic_ctx = Box::from_raw(ptr as *mut PanicData);
|
||||
return panic_ctx.data;
|
||||
}
|
||||
@ -115,14 +114,12 @@ unsafe extern fn rust_eh_personality(
|
||||
er.ExceptionInformation[0] as c::LPVOID, // pointer to PanicData
|
||||
contextRecord,
|
||||
dc.HistoryTable);
|
||||
rtabort!("could not unwind");
|
||||
}
|
||||
}
|
||||
}
|
||||
c::ExceptionContinueSearch
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[lang = "eh_unwind_resume"]
|
||||
#[unwind]
|
||||
unsafe extern fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! {
|
||||
@ -131,7 +128,7 @@ unsafe extern fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! {
|
||||
c::EXCEPTION_NONCONTINUABLE,
|
||||
params.len() as c::DWORD,
|
||||
¶ms as *const c::ULONG_PTR);
|
||||
rtabort!("could not resume unwind");
|
||||
intrinsics::abort();
|
||||
}
|
||||
|
||||
unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option<usize> {
|
96
src/libpanic_unwind/windows.rs
Normal file
96
src/libpanic_unwind/windows.rs
Normal file
@ -0,0 +1,96 @@
|
||||
// Copyright 2014 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)]
|
||||
#![allow(dead_code)]
|
||||
#![cfg(windows)]
|
||||
|
||||
use libc::{c_void, c_ulong, c_long, c_ulonglong};
|
||||
|
||||
pub use self::EXCEPTION_DISPOSITION::*;
|
||||
pub type DWORD = c_ulong;
|
||||
pub type LONG = c_long;
|
||||
pub type ULONG_PTR = c_ulonglong;
|
||||
pub type LPVOID = *mut c_void;
|
||||
|
||||
pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
|
||||
pub const EXCEPTION_NONCONTINUABLE: DWORD = 0x1; // Noncontinuable exception
|
||||
pub const EXCEPTION_UNWINDING: DWORD = 0x2; // Unwind is in progress
|
||||
pub const EXCEPTION_EXIT_UNWIND: DWORD = 0x4; // Exit unwind is in progress
|
||||
pub const EXCEPTION_TARGET_UNWIND: DWORD = 0x20; // Target unwind in progress
|
||||
pub const EXCEPTION_COLLIDED_UNWIND: DWORD = 0x40; // Collided exception handler call
|
||||
pub const EXCEPTION_UNWIND: DWORD = EXCEPTION_UNWINDING |
|
||||
EXCEPTION_EXIT_UNWIND |
|
||||
EXCEPTION_TARGET_UNWIND |
|
||||
EXCEPTION_COLLIDED_UNWIND;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct EXCEPTION_RECORD {
|
||||
pub ExceptionCode: DWORD,
|
||||
pub ExceptionFlags: DWORD,
|
||||
pub ExceptionRecord: *mut EXCEPTION_RECORD,
|
||||
pub ExceptionAddress: LPVOID,
|
||||
pub NumberParameters: DWORD,
|
||||
pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS]
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct EXCEPTION_POINTERS {
|
||||
pub ExceptionRecord: *mut EXCEPTION_RECORD,
|
||||
pub ContextRecord: *mut CONTEXT,
|
||||
}
|
||||
|
||||
pub enum UNWIND_HISTORY_TABLE {}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RUNTIME_FUNCTION {
|
||||
pub BeginAddress: DWORD,
|
||||
pub EndAddress: DWORD,
|
||||
pub UnwindData: DWORD,
|
||||
}
|
||||
|
||||
pub enum CONTEXT {}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct DISPATCHER_CONTEXT {
|
||||
pub ControlPc: LPVOID,
|
||||
pub ImageBase: LPVOID,
|
||||
pub FunctionEntry: *const RUNTIME_FUNCTION,
|
||||
pub EstablisherFrame: LPVOID,
|
||||
pub TargetIp: LPVOID,
|
||||
pub ContextRecord: *const CONTEXT,
|
||||
pub LanguageHandler: LPVOID,
|
||||
pub HandlerData: *const u8,
|
||||
pub HistoryTable: *const UNWIND_HISTORY_TABLE,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[allow(dead_code)] // we only use some variants
|
||||
pub enum EXCEPTION_DISPOSITION {
|
||||
ExceptionContinueExecution,
|
||||
ExceptionContinueSearch,
|
||||
ExceptionNestedException,
|
||||
ExceptionCollidedUnwind
|
||||
}
|
||||
|
||||
extern "system" {
|
||||
#[unwind]
|
||||
pub fn RaiseException(dwExceptionCode: DWORD,
|
||||
dwExceptionFlags: DWORD,
|
||||
nNumberOfArguments: DWORD,
|
||||
lpArguments: *const ULONG_PTR);
|
||||
#[unwind]
|
||||
pub fn RtlUnwindEx(TargetFrame: LPVOID,
|
||||
TargetIp: LPVOID,
|
||||
ExceptionRecord: *const EXCEPTION_RECORD,
|
||||
ReturnValue: LPVOID,
|
||||
OriginalContext: *const CONTEXT,
|
||||
HistoryTable: *const UNWIND_HISTORY_TABLE);
|
||||
}
|
@ -31,6 +31,7 @@ use hir::def_id::{DefId, DefIndex};
|
||||
use mir::repr::Mir;
|
||||
use mir::mir_map::MirMap;
|
||||
use session::Session;
|
||||
use session::config::PanicStrategy;
|
||||
use session::search_paths::PathKind;
|
||||
use util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
|
||||
use std::any::Any;
|
||||
@ -222,6 +223,8 @@ pub trait CrateStore<'tcx> : Any {
|
||||
fn is_staged_api(&self, cnum: ast::CrateNum) -> bool;
|
||||
fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool;
|
||||
fn is_allocator(&self, cnum: ast::CrateNum) -> bool;
|
||||
fn is_panic_runtime(&self, cnum: ast::CrateNum) -> bool;
|
||||
fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy;
|
||||
fn extern_crate(&self, cnum: ast::CrateNum) -> Option<ExternCrate>;
|
||||
fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>;
|
||||
/// The name of the crate as it is referred to in source code of the current
|
||||
@ -408,6 +411,10 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
|
||||
fn is_staged_api(&self, cnum: ast::CrateNum) -> bool { bug!("is_staged_api") }
|
||||
fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool { bug!("is_explicitly_linked") }
|
||||
fn is_allocator(&self, cnum: ast::CrateNum) -> bool { bug!("is_allocator") }
|
||||
fn is_panic_runtime(&self, cnum: ast::CrateNum) -> bool { bug!("is_panic_runtime") }
|
||||
fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy {
|
||||
bug!("panic_strategy")
|
||||
}
|
||||
fn extern_crate(&self, cnum: ast::CrateNum) -> Option<ExternCrate> { bug!("extern_crate") }
|
||||
fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>
|
||||
{ bug!("crate_attrs") }
|
||||
|
@ -64,7 +64,7 @@
|
||||
use syntax::ast;
|
||||
|
||||
use session;
|
||||
use session::config;
|
||||
use session::config::{self, PanicStrategy};
|
||||
use middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic};
|
||||
use util::nodemap::FnvHashMap;
|
||||
|
||||
@ -193,10 +193,15 @@ fn calculate_type(sess: &session::Session,
|
||||
}
|
||||
|
||||
// We've gotten this far because we're emitting some form of a final
|
||||
// artifact which means that we're going to need an allocator of some form.
|
||||
// No allocator may have been required or linked so far, so activate one
|
||||
// here if one isn't set.
|
||||
activate_allocator(sess, &mut ret);
|
||||
// artifact which means that we may need to inject dependencies of some
|
||||
// form.
|
||||
//
|
||||
// Things like allocators and panic runtimes may not have been activated
|
||||
// quite yet, so do so here.
|
||||
activate_injected_dep(sess.injected_allocator.get(), &mut ret,
|
||||
&|cnum| sess.cstore.is_allocator(cnum));
|
||||
activate_injected_dep(sess.injected_panic_runtime.get(), &mut ret,
|
||||
&|cnum| sess.cstore.is_panic_runtime(cnum));
|
||||
|
||||
// When dylib B links to dylib A, then when using B we must also link to A.
|
||||
// It could be the case, however, that the rlib for A is present (hence we
|
||||
@ -270,40 +275,42 @@ fn attempt_static(sess: &session::Session) -> Option<DependencyList> {
|
||||
}
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
// Our allocator may not have been activated as it's not flagged with
|
||||
// explicitly_linked, so flag it here if necessary.
|
||||
activate_allocator(sess, &mut ret);
|
||||
// Our allocator/panic runtime may not have been linked above if it wasn't
|
||||
// explicitly linked, which is the case for any injected dependency. Handle
|
||||
// that here and activate them.
|
||||
activate_injected_dep(sess.injected_allocator.get(), &mut ret,
|
||||
&|cnum| sess.cstore.is_allocator(cnum));
|
||||
activate_injected_dep(sess.injected_panic_runtime.get(), &mut ret,
|
||||
&|cnum| sess.cstore.is_panic_runtime(cnum));
|
||||
|
||||
Some(ret)
|
||||
}
|
||||
|
||||
// Given a list of how to link upstream dependencies so far, ensure that an
|
||||
// allocator is activated. This will not do anything if one was transitively
|
||||
// included already (e.g. via a dylib or explicitly so).
|
||||
// injected dependency is activated. This will not do anything if one was
|
||||
// transitively included already (e.g. via a dylib or explicitly so).
|
||||
//
|
||||
// If an allocator was not found then we're guaranteed the metadata::creader
|
||||
// module has injected an allocator dependency (not listed as a required
|
||||
// dependency) in the session's `injected_allocator` field. If this field is not
|
||||
// set then this compilation doesn't actually need an allocator and we can also
|
||||
// skip this step entirely.
|
||||
fn activate_allocator(sess: &session::Session, list: &mut DependencyList) {
|
||||
let mut allocator_found = false;
|
||||
// If an injected dependency was not found then we're guaranteed the
|
||||
// metadata::creader module has injected that dependency (not listed as
|
||||
// a required dependency) in one of the session's field. If this field is not
|
||||
// set then this compilation doesn't actually need the dependency and we can
|
||||
// also skip this step entirely.
|
||||
fn activate_injected_dep(injected: Option<ast::CrateNum>,
|
||||
list: &mut DependencyList,
|
||||
replaces_injected: &Fn(ast::CrateNum) -> bool) {
|
||||
for (i, slot) in list.iter().enumerate() {
|
||||
let cnum = (i + 1) as ast::CrateNum;
|
||||
if !sess.cstore.is_allocator(cnum) {
|
||||
if !replaces_injected(cnum) {
|
||||
continue
|
||||
}
|
||||
if let Linkage::NotLinked = *slot {
|
||||
continue
|
||||
if *slot != Linkage::NotLinked {
|
||||
return
|
||||
}
|
||||
allocator_found = true;
|
||||
}
|
||||
if !allocator_found {
|
||||
if let Some(injected_allocator) = sess.injected_allocator.get() {
|
||||
let idx = injected_allocator as usize - 1;
|
||||
assert_eq!(list[idx], Linkage::NotLinked);
|
||||
list[idx] = Linkage::Static;
|
||||
}
|
||||
if let Some(injected) = injected {
|
||||
let idx = injected as usize - 1;
|
||||
assert_eq!(list[idx], Linkage::NotLinked);
|
||||
list[idx] = Linkage::Static;
|
||||
}
|
||||
}
|
||||
|
||||
@ -314,21 +321,75 @@ fn verify_ok(sess: &session::Session, list: &[Linkage]) {
|
||||
return
|
||||
}
|
||||
let mut allocator = None;
|
||||
let mut panic_runtime = None;
|
||||
for (i, linkage) in list.iter().enumerate() {
|
||||
let cnum = (i + 1) as ast::CrateNum;
|
||||
if !sess.cstore.is_allocator(cnum) {
|
||||
continue
|
||||
}
|
||||
if let Linkage::NotLinked = *linkage {
|
||||
continue
|
||||
}
|
||||
if let Some(prev_alloc) = allocator {
|
||||
let prev_name = sess.cstore.crate_name(prev_alloc);
|
||||
let cur_name = sess.cstore.crate_name(cnum);
|
||||
sess.err(&format!("cannot link together two \
|
||||
allocators: {} and {}",
|
||||
prev_name, cur_name));
|
||||
let cnum = (i + 1) as ast::CrateNum;
|
||||
if sess.cstore.is_allocator(cnum) {
|
||||
if let Some(prev) = allocator {
|
||||
let prev_name = sess.cstore.crate_name(prev);
|
||||
let cur_name = sess.cstore.crate_name(cnum);
|
||||
sess.err(&format!("cannot link together two \
|
||||
allocators: {} and {}",
|
||||
prev_name, cur_name));
|
||||
}
|
||||
allocator = Some(cnum);
|
||||
}
|
||||
|
||||
if sess.cstore.is_panic_runtime(cnum) {
|
||||
if let Some((prev, _)) = panic_runtime {
|
||||
let prev_name = sess.cstore.crate_name(prev);
|
||||
let cur_name = sess.cstore.crate_name(cnum);
|
||||
sess.err(&format!("cannot link together two \
|
||||
panic runtimes: {} and {}",
|
||||
prev_name, cur_name));
|
||||
}
|
||||
panic_runtime = Some((cnum, sess.cstore.panic_strategy(cnum)));
|
||||
}
|
||||
}
|
||||
|
||||
// If we found a panic runtime, then we know by this point that it's the
|
||||
// only one, but we perform validation here that all the panic strategy
|
||||
// compilation modes for the whole DAG are valid.
|
||||
if let Some((cnum, found_strategy)) = panic_runtime {
|
||||
let desired_strategy = sess.opts.cg.panic.clone();
|
||||
|
||||
// First up, validate that our selected panic runtime is indeed exactly
|
||||
// our same strategy.
|
||||
if found_strategy != desired_strategy {
|
||||
sess.err(&format!("the linked panic runtime `{}` is \
|
||||
not compiled with this crate's \
|
||||
panic strategy `{}`",
|
||||
sess.cstore.crate_name(cnum),
|
||||
desired_strategy.desc()));
|
||||
}
|
||||
|
||||
// Next up, verify that all other crates are compatible with this panic
|
||||
// strategy. If the dep isn't linked, we ignore it, and if our strategy
|
||||
// is abort then it's compatible with everything. Otherwise all crates'
|
||||
// panic strategy must match our own.
|
||||
for (i, linkage) in list.iter().enumerate() {
|
||||
if let Linkage::NotLinked = *linkage {
|
||||
continue
|
||||
}
|
||||
if desired_strategy == PanicStrategy::Abort {
|
||||
continue
|
||||
}
|
||||
let cnum = (i + 1) as ast::CrateNum;
|
||||
let found_strategy = sess.cstore.panic_strategy(cnum);
|
||||
if desired_strategy == found_strategy {
|
||||
continue
|
||||
}
|
||||
|
||||
sess.err(&format!("the crate `{}` is compiled with the \
|
||||
panic strategy `{}` which is \
|
||||
incompatible with this crate's \
|
||||
strategy of `{}`",
|
||||
sess.cstore.crate_name(cnum),
|
||||
found_strategy.desc(),
|
||||
desired_strategy.desc()));
|
||||
}
|
||||
allocator = Some(cnum);
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
//! Validity checking for weak lang items
|
||||
|
||||
use session::config;
|
||||
use session::config::{self, PanicStrategy};
|
||||
use session::Session;
|
||||
use middle::lang_items;
|
||||
|
||||
@ -75,7 +75,9 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) {
|
||||
config::CrateTypeRlib => false,
|
||||
}
|
||||
});
|
||||
if !needs_check { return }
|
||||
if !needs_check {
|
||||
return
|
||||
}
|
||||
|
||||
let mut missing = HashSet::new();
|
||||
for cnum in sess.cstore.crates() {
|
||||
@ -84,8 +86,19 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) {
|
||||
}
|
||||
}
|
||||
|
||||
// If we're not compiling with unwinding, we won't actually need these
|
||||
// symbols. Other panic runtimes ensure that the relevant symbols are
|
||||
// available to link things together, but they're never exercised.
|
||||
let mut whitelisted = HashSet::new();
|
||||
if sess.opts.cg.panic != PanicStrategy::Unwind {
|
||||
whitelisted.insert(lang_items::EhPersonalityLangItem);
|
||||
whitelisted.insert(lang_items::EhUnwindResumeLangItem);
|
||||
}
|
||||
|
||||
$(
|
||||
if missing.contains(&lang_items::$item) && items.$name().is_none() {
|
||||
if missing.contains(&lang_items::$item) &&
|
||||
!whitelisted.contains(&lang_items::$item) &&
|
||||
items.$name().is_none() {
|
||||
sess.err(&format!("language item required, but not found: `{}`",
|
||||
stringify!($name)));
|
||||
|
||||
|
@ -317,6 +317,21 @@ impl Passes {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum PanicStrategy {
|
||||
Unwind,
|
||||
Abort,
|
||||
}
|
||||
|
||||
impl PanicStrategy {
|
||||
pub fn desc(&self) -> &str {
|
||||
match *self {
|
||||
PanicStrategy::Unwind => "unwind",
|
||||
PanicStrategy::Abort => "abort",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Declare a macro that will define all CodegenOptions/DebuggingOptions fields and parsers all
|
||||
/// at once. The goal of this macro is to define an interface that can be
|
||||
/// programmatically used by the option parser in order to initialize the struct
|
||||
@ -402,11 +417,13 @@ macro_rules! options {
|
||||
Some("a space-separated list of passes, or `all`");
|
||||
pub const parse_opt_uint: Option<&'static str> =
|
||||
Some("a number");
|
||||
pub const parse_panic_strategy: Option<&'static str> =
|
||||
Some("either `panic` or `abort`");
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod $mod_set {
|
||||
use super::{$struct_name, Passes, SomePasses, AllPasses};
|
||||
use super::{$struct_name, Passes, SomePasses, AllPasses, PanicStrategy};
|
||||
|
||||
$(
|
||||
pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
|
||||
@ -510,6 +527,15 @@ macro_rules! options {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
|
||||
match v {
|
||||
Some("unwind") => *slot = PanicStrategy::Unwind,
|
||||
Some("abort") => *slot = PanicStrategy::Abort,
|
||||
_ => return false
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
) }
|
||||
|
||||
@ -575,6 +601,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
|
||||
"explicitly enable the cfg(debug_assertions) directive"),
|
||||
inline_threshold: Option<usize> = (None, parse_opt_uint,
|
||||
"set the inlining threshold for"),
|
||||
panic: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy,
|
||||
"panic strategy to compile crate with"),
|
||||
}
|
||||
|
||||
|
||||
|
@ -12,6 +12,7 @@ use lint;
|
||||
use middle::cstore::CrateStore;
|
||||
use middle::dependency_format;
|
||||
use session::search_paths::PathKind;
|
||||
use session::config::PanicStrategy;
|
||||
use ty::tls;
|
||||
use util::nodemap::{NodeMap, FnvHashMap};
|
||||
use mir::transform as mir_pass;
|
||||
@ -82,9 +83,11 @@ pub struct Session {
|
||||
/// operations such as auto-dereference and monomorphization.
|
||||
pub recursion_limit: Cell<usize>,
|
||||
|
||||
/// The metadata::creader module may inject an allocator dependency if it
|
||||
/// didn't already find one, and this tracks what was injected.
|
||||
/// The metadata::creader module may inject an allocator/panic_runtime
|
||||
/// dependency if it didn't already find one, and this tracks what was
|
||||
/// injected.
|
||||
pub injected_allocator: Cell<Option<ast::CrateNum>>,
|
||||
pub injected_panic_runtime: Cell<Option<ast::CrateNum>>,
|
||||
|
||||
/// Names of all bang-style macros and syntax extensions
|
||||
/// available in this crate
|
||||
@ -295,7 +298,8 @@ impl Session {
|
||||
self.opts.cg.lto
|
||||
}
|
||||
pub fn no_landing_pads(&self) -> bool {
|
||||
self.opts.debugging_opts.no_landing_pads
|
||||
self.opts.debugging_opts.no_landing_pads ||
|
||||
self.opts.cg.panic == PanicStrategy::Abort
|
||||
}
|
||||
pub fn unstable_options(&self) -> bool {
|
||||
self.opts.debugging_opts.unstable_options
|
||||
@ -502,6 +506,7 @@ pub fn build_session_(sopts: config::Options,
|
||||
recursion_limit: Cell::new(64),
|
||||
next_node_id: Cell::new(1),
|
||||
injected_allocator: Cell::new(None),
|
||||
injected_panic_runtime: Cell::new(None),
|
||||
available_macros: RefCell::new(HashSet::new()),
|
||||
imported_macro_spans: RefCell::new(HashMap::new()),
|
||||
};
|
||||
|
@ -250,3 +250,5 @@ pub fn rustc_version() -> String {
|
||||
option_env!("CFG_VERSION").unwrap_or("unknown version")
|
||||
)
|
||||
}
|
||||
|
||||
pub const tag_panic_strategy: usize = 0x114;
|
||||
|
@ -20,6 +20,7 @@ use loader::{self, CratePaths};
|
||||
use rustc::hir::svh::Svh;
|
||||
use rustc::dep_graph::{DepGraph, DepNode};
|
||||
use rustc::session::{config, Session};
|
||||
use rustc::session::config::PanicStrategy;
|
||||
use rustc::session::search_paths::PathKind;
|
||||
use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
|
||||
use rustc::util::nodemap::FnvHashMap;
|
||||
@ -630,6 +631,85 @@ impl<'a> CrateReader<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
|
||||
// If we're only compiling an rlib, then there's no need to select a
|
||||
// panic runtime, so we just skip this section entirely.
|
||||
let any_non_rlib = self.sess.crate_types.borrow().iter().any(|ct| {
|
||||
*ct != config::CrateTypeRlib
|
||||
});
|
||||
if !any_non_rlib {
|
||||
info!("panic runtime injection skipped, only generating rlib");
|
||||
return
|
||||
}
|
||||
|
||||
// If we need a panic runtime, we try to find an existing one here. At
|
||||
// the same time we perform some general validation of the DAG we've got
|
||||
// going such as ensuring everything has a compatible panic strategy.
|
||||
//
|
||||
// The logic for finding the panic runtime here is pretty much the same
|
||||
// as the allocator case with the only addition that the panic strategy
|
||||
// compilation mode also comes into play.
|
||||
let desired_strategy = self.sess.opts.cg.panic.clone();
|
||||
let mut runtime_found = false;
|
||||
let mut needs_panic_runtime = attr::contains_name(&krate.attrs,
|
||||
"needs_panic_runtime");
|
||||
self.cstore.iter_crate_data(|cnum, data| {
|
||||
needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime();
|
||||
if data.is_panic_runtime() {
|
||||
// Inject a dependency from all #![needs_panic_runtime] to this
|
||||
// #![panic_runtime] crate.
|
||||
self.inject_dependency_if(cnum, "a panic runtime",
|
||||
&|data| data.needs_panic_runtime());
|
||||
runtime_found = runtime_found || data.explicitly_linked.get();
|
||||
}
|
||||
});
|
||||
|
||||
// If an explicitly linked and matching panic runtime was found, or if
|
||||
// we just don't need one at all, then we're done here and there's
|
||||
// nothing else to do.
|
||||
if !needs_panic_runtime || runtime_found {
|
||||
return
|
||||
}
|
||||
|
||||
// By this point we know that we (a) need a panic runtime and (b) no
|
||||
// panic runtime was explicitly linked. Here we just load an appropriate
|
||||
// default runtime for our panic strategy and then inject the
|
||||
// dependencies.
|
||||
//
|
||||
// We may resolve to an already loaded crate (as the crate may not have
|
||||
// been explicitly linked prior to this) and we may re-inject
|
||||
// dependencies again, but both of those situations are fine.
|
||||
//
|
||||
// Also note that we have yet to perform validation of the crate graph
|
||||
// in terms of everyone has a compatible panic runtime format, that's
|
||||
// performed later as part of the `dependency_format` module.
|
||||
let name = match desired_strategy {
|
||||
PanicStrategy::Unwind => "panic_unwind",
|
||||
PanicStrategy::Abort => "panic_abort",
|
||||
};
|
||||
info!("panic runtime not found -- loading {}", name);
|
||||
|
||||
let (cnum, data, _) = self.resolve_crate(&None, name, name, None,
|
||||
codemap::DUMMY_SP,
|
||||
PathKind::Crate, false);
|
||||
|
||||
// Sanity check the loaded crate to ensure it is indeed a panic runtime
|
||||
// and the panic strategy is indeed what we thought it was.
|
||||
if !data.is_panic_runtime() {
|
||||
self.sess.err(&format!("the crate `{}` is not a panic runtime",
|
||||
name));
|
||||
}
|
||||
if data.panic_strategy() != desired_strategy {
|
||||
self.sess.err(&format!("the crate `{}` does not have the panic \
|
||||
strategy `{}`",
|
||||
name, desired_strategy.desc()));
|
||||
}
|
||||
|
||||
self.sess.injected_panic_runtime.set(Some(cnum));
|
||||
self.inject_dependency_if(cnum, "a panic runtime",
|
||||
&|data| data.needs_panic_runtime());
|
||||
}
|
||||
|
||||
fn inject_allocator_crate(&mut self) {
|
||||
// Make sure that we actually need an allocator, if none of our
|
||||
// dependencies need one then we definitely don't!
|
||||
@ -641,8 +721,9 @@ impl<'a> CrateReader<'a> {
|
||||
self.cstore.iter_crate_data(|cnum, data| {
|
||||
needs_allocator = needs_allocator || data.needs_allocator();
|
||||
if data.is_allocator() {
|
||||
debug!("{} required by rlib and is an allocator", data.name());
|
||||
self.inject_allocator_dependency(cnum);
|
||||
info!("{} required by rlib and is an allocator", data.name());
|
||||
self.inject_dependency_if(cnum, "an allocator",
|
||||
&|data| data.needs_allocator());
|
||||
found_required_allocator = found_required_allocator ||
|
||||
data.explicitly_linked.get();
|
||||
}
|
||||
@ -692,58 +773,68 @@ impl<'a> CrateReader<'a> {
|
||||
codemap::DUMMY_SP,
|
||||
PathKind::Crate, false);
|
||||
|
||||
// To ensure that the `-Z allocation-crate=foo` option isn't abused, and
|
||||
// to ensure that the allocator is indeed an allocator, we verify that
|
||||
// the crate loaded here is indeed tagged #![allocator].
|
||||
// Sanity check the crate we loaded to ensure that it is indeed an
|
||||
// allocator.
|
||||
if !data.is_allocator() {
|
||||
self.sess.err(&format!("the allocator crate `{}` is not tagged \
|
||||
with #![allocator]", data.name()));
|
||||
}
|
||||
|
||||
self.sess.injected_allocator.set(Some(cnum));
|
||||
self.inject_allocator_dependency(cnum);
|
||||
self.inject_dependency_if(cnum, "an allocator",
|
||||
&|data| data.needs_allocator());
|
||||
}
|
||||
|
||||
fn inject_allocator_dependency(&self, allocator: ast::CrateNum) {
|
||||
// Before we inject any dependencies, make sure we don't inject a
|
||||
// circular dependency by validating that this allocator crate doesn't
|
||||
// transitively depend on any `#![needs_allocator]` crates.
|
||||
validate(self, allocator, allocator);
|
||||
fn inject_dependency_if(&self,
|
||||
krate: ast::CrateNum,
|
||||
what: &str,
|
||||
needs_dep: &Fn(&cstore::crate_metadata) -> bool) {
|
||||
// don't perform this validation if the session has errors, as one of
|
||||
// those errors may indicate a circular dependency which could cause
|
||||
// this to stack overflow.
|
||||
if self.sess.has_errors() {
|
||||
return
|
||||
}
|
||||
|
||||
// All crates tagged with `needs_allocator` do not explicitly depend on
|
||||
// the allocator selected for this compile, but in order for this
|
||||
// compilation to be successfully linked we need to inject a dependency
|
||||
// (to order the crates on the command line correctly).
|
||||
//
|
||||
// Here we inject a dependency from all crates with #![needs_allocator]
|
||||
// to the crate tagged with #![allocator] for this compilation unit.
|
||||
// Before we inject any dependencies, make sure we don't inject a
|
||||
// circular dependency by validating that this crate doesn't
|
||||
// transitively depend on any crates satisfying `needs_dep`.
|
||||
validate(self, krate, krate, what, needs_dep);
|
||||
|
||||
// All crates satisfying `needs_dep` do not explicitly depend on the
|
||||
// crate provided for this compile, but in order for this compilation to
|
||||
// be successfully linked we need to inject a dependency (to order the
|
||||
// crates on the command line correctly).
|
||||
self.cstore.iter_crate_data(|cnum, data| {
|
||||
if !data.needs_allocator() {
|
||||
if !needs_dep(data) {
|
||||
return
|
||||
}
|
||||
|
||||
info!("injecting a dep from {} to {}", cnum, allocator);
|
||||
info!("injecting a dep from {} to {}", cnum, krate);
|
||||
let mut cnum_map = data.cnum_map.borrow_mut();
|
||||
let remote_cnum = cnum_map.len() + 1;
|
||||
let prev = cnum_map.insert(remote_cnum as ast::CrateNum, allocator);
|
||||
let prev = cnum_map.insert(remote_cnum as ast::CrateNum, krate);
|
||||
assert!(prev.is_none());
|
||||
});
|
||||
|
||||
fn validate(me: &CrateReader, krate: ast::CrateNum,
|
||||
allocator: ast::CrateNum) {
|
||||
fn validate(me: &CrateReader,
|
||||
krate: ast::CrateNum,
|
||||
root: ast::CrateNum,
|
||||
what: &str,
|
||||
needs_dep: &Fn(&cstore::crate_metadata) -> bool) {
|
||||
let data = me.cstore.get_crate_data(krate);
|
||||
if data.needs_allocator() {
|
||||
if needs_dep(&data) {
|
||||
let krate_name = data.name();
|
||||
let data = me.cstore.get_crate_data(allocator);
|
||||
let alloc_name = data.name();
|
||||
me.sess.err(&format!("the allocator crate `{}` cannot depend \
|
||||
on a crate that needs an allocator, but \
|
||||
it depends on `{}`", alloc_name,
|
||||
let data = me.cstore.get_crate_data(root);
|
||||
let root_name = data.name();
|
||||
me.sess.err(&format!("the crate `{}` cannot depend \
|
||||
on a crate that needs {}, but \
|
||||
it depends on `{}`", root_name, what,
|
||||
krate_name));
|
||||
}
|
||||
|
||||
for (_, &dep) in data.cnum_map.borrow().iter() {
|
||||
validate(me, dep, allocator);
|
||||
validate(me, dep, root, what, needs_dep);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -774,6 +865,7 @@ impl<'a> LocalCrateReader<'a> {
|
||||
self.process_crate(self.krate);
|
||||
visit::walk_crate(self, self.krate);
|
||||
self.creader.inject_allocator_crate();
|
||||
self.creader.inject_panic_runtime(self.krate);
|
||||
|
||||
if log_enabled!(log::INFO) {
|
||||
dump_crates(&self.cstore);
|
||||
|
@ -24,6 +24,7 @@ use rustc::hir::map as hir_map;
|
||||
use rustc::mir::repr::Mir;
|
||||
use rustc::mir::mir_map::MirMap;
|
||||
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
|
||||
use rustc::session::config::PanicStrategy;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
@ -306,6 +307,15 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
|
||||
self.get_crate_data(cnum).is_allocator()
|
||||
}
|
||||
|
||||
fn is_panic_runtime(&self, cnum: ast::CrateNum) -> bool
|
||||
{
|
||||
self.get_crate_data(cnum).is_panic_runtime()
|
||||
}
|
||||
|
||||
fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy {
|
||||
self.get_crate_data(cnum).panic_strategy()
|
||||
}
|
||||
|
||||
fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>
|
||||
{
|
||||
decoder::get_crate_attributes(self.get_crate_data(cnum).data())
|
||||
|
@ -23,6 +23,7 @@ use loader;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::svh::Svh;
|
||||
use rustc::middle::cstore::{ExternCrate};
|
||||
use rustc::session::config::PanicStrategy;
|
||||
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
|
||||
|
||||
use std::cell::{RefCell, Ref, Cell};
|
||||
@ -281,6 +282,20 @@ impl crate_metadata {
|
||||
let attrs = decoder::get_crate_attributes(self.data());
|
||||
attr::contains_name(&attrs, "needs_allocator")
|
||||
}
|
||||
|
||||
pub fn is_panic_runtime(&self) -> bool {
|
||||
let attrs = decoder::get_crate_attributes(self.data());
|
||||
attr::contains_name(&attrs, "panic_runtime")
|
||||
}
|
||||
|
||||
pub fn needs_panic_runtime(&self) -> bool {
|
||||
let attrs = decoder::get_crate_attributes(self.data());
|
||||
attr::contains_name(&attrs, "needs_panic_runtime")
|
||||
}
|
||||
|
||||
pub fn panic_strategy(&self) -> PanicStrategy {
|
||||
decoder::get_panic_strategy(self.data())
|
||||
}
|
||||
}
|
||||
|
||||
impl MetadataBlob {
|
||||
|
@ -27,6 +27,7 @@ use rustc::hir::svh::Svh;
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::util::nodemap::FnvHashMap;
|
||||
use rustc::hir;
|
||||
use rustc::session::config::PanicStrategy;
|
||||
|
||||
use middle::cstore::{LOCAL_CRATE, FoundAst, InlinedItem, LinkagePreference};
|
||||
use middle::cstore::{DefLike, DlDef, DlField, DlImpl, tls};
|
||||
@ -1760,3 +1761,13 @@ pub fn def_path(cdata: Cmd, id: DefIndex) -> hir_map::DefPath {
|
||||
debug!("def_path(id={:?})", id);
|
||||
hir_map::DefPath::make(cdata.cnum, id, |parent| def_key(cdata, parent))
|
||||
}
|
||||
|
||||
pub fn get_panic_strategy(data: &[u8]) -> PanicStrategy {
|
||||
let crate_doc = rbml::Doc::new(data);
|
||||
let strat_doc = reader::get_doc(crate_doc, tag_panic_strategy);
|
||||
match reader::doc_as_u8(strat_doc) {
|
||||
b'U' => PanicStrategy::Unwind,
|
||||
b'A' => PanicStrategy::Abort,
|
||||
b => panic!("unknown panic strategy in metadata: {}", b),
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ use rustc::ty::util::IntTypeExt;
|
||||
|
||||
use rustc::hir::svh::Svh;
|
||||
use rustc::mir::mir_map::MirMap;
|
||||
use rustc::session::config;
|
||||
use rustc::session::config::{self, PanicStrategy};
|
||||
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet};
|
||||
|
||||
use rustc_serialize::Encodable;
|
||||
@ -1828,6 +1828,17 @@ fn encode_dylib_dependency_formats(rbml_w: &mut Encoder, ecx: &EncodeContext) {
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_panic_strategy(rbml_w: &mut Encoder, ecx: &EncodeContext) {
|
||||
match ecx.tcx.sess.opts.cg.panic {
|
||||
PanicStrategy::Unwind => {
|
||||
rbml_w.wr_tagged_u8(tag_panic_strategy, b'U');
|
||||
}
|
||||
PanicStrategy::Abort => {
|
||||
rbml_w.wr_tagged_u8(tag_panic_strategy, b'A');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Increment this as you change the metadata encoding version.
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2 ];
|
||||
@ -1915,6 +1926,7 @@ fn encode_metadata_inner(rbml_w: &mut Encoder,
|
||||
encode_hash(rbml_w, &ecx.link_meta.crate_hash);
|
||||
encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.crate_disambiguator.get().as_str());
|
||||
encode_dylib_dependency_formats(rbml_w, &ecx);
|
||||
encode_panic_strategy(rbml_w, &ecx);
|
||||
|
||||
let mut i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
|
||||
encode_attributes(rbml_w, &krate.attrs);
|
||||
|
@ -1829,7 +1829,9 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
}
|
||||
|
||||
let _icx = push_ctxt("trans_closure");
|
||||
attributes::emit_uwtable(llfndecl, true);
|
||||
if !ccx.sess().no_landing_pads() {
|
||||
attributes::emit_uwtable(llfndecl, true);
|
||||
}
|
||||
|
||||
debug!("trans_closure(..., {})", instance);
|
||||
|
||||
|
@ -14,11 +14,14 @@ test = false
|
||||
alloc = { path = "../liballoc" }
|
||||
alloc_jemalloc = { path = "../liballoc_jemalloc", optional = true }
|
||||
alloc_system = { path = "../liballoc_system" }
|
||||
panic_unwind = { path = "../libpanic_unwind" }
|
||||
panic_abort = { path = "../libpanic_abort" }
|
||||
collections = { path = "../libcollections" }
|
||||
core = { path = "../libcore" }
|
||||
libc = { path = "../rustc/libc_shim" }
|
||||
rand = { path = "../librand" }
|
||||
rustc_unicode = { path = "../librustc_unicode" }
|
||||
unwind = { path = "../libunwind" }
|
||||
|
||||
[build-dependencies]
|
||||
build_helper = { path = "../build_helper" }
|
||||
|
@ -28,9 +28,7 @@ fn main() {
|
||||
}
|
||||
|
||||
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") {
|
||||
if target.contains("android") {
|
||||
println!("cargo:rustc-link-lib=dl");
|
||||
println!("cargo:rustc-link-lib=log");
|
||||
println!("cargo:rustc-link-lib=gcc");
|
||||
@ -38,27 +36,13 @@ fn main() {
|
||||
println!("cargo:rustc-link-lib=dl");
|
||||
println!("cargo:rustc-link-lib=rt");
|
||||
println!("cargo:rustc-link-lib=pthread");
|
||||
println!("cargo:rustc-link-lib=gcc_s");
|
||||
}
|
||||
} else if target.contains("freebsd") {
|
||||
println!("cargo:rustc-link-lib=execinfo");
|
||||
println!("cargo:rustc-link-lib=pthread");
|
||||
println!("cargo:rustc-link-lib=gcc_s");
|
||||
} else if target.contains("dragonfly") || target.contains("bitrig") ||
|
||||
target.contains("netbsd") || target.contains("openbsd") {
|
||||
println!("cargo:rustc-link-lib=pthread");
|
||||
|
||||
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("apple-darwin") {
|
||||
println!("cargo:rustc-link-lib=System");
|
||||
} else if target.contains("apple-ios") {
|
||||
@ -67,9 +51,6 @@ fn main() {
|
||||
println!("cargo:rustc-link-lib=framework=Security");
|
||||
println!("cargo:rustc-link-lib=framework=Foundation");
|
||||
} else if target.contains("windows") {
|
||||
if target.contains("windows-gnu") {
|
||||
println!("cargo:rustc-link-lib=gcc_eh");
|
||||
}
|
||||
println!("cargo:rustc-link-lib=advapi32");
|
||||
println!("cargo:rustc-link-lib=ws2_32");
|
||||
println!("cargo:rustc-link-lib=userenv");
|
||||
|
@ -245,6 +245,7 @@
|
||||
#![feature(on_unimplemented)]
|
||||
#![feature(oom)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![feature(panic_unwind)]
|
||||
#![feature(placement_in_syntax)]
|
||||
#![feature(rand)]
|
||||
#![feature(raw)]
|
||||
@ -283,6 +284,13 @@
|
||||
#![allow(unused_features)] // std may use features in a platform-specific way
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
|
||||
// FIXME(stage0): after a snapshot, move needs_panic_runtime up above and remove
|
||||
// this `extern crate` declaration and feature(panic_unwind)
|
||||
#![cfg_attr(not(stage0), needs_panic_runtime)]
|
||||
#![cfg_attr(not(stage0), feature(needs_panic_runtime))]
|
||||
#[cfg(stage0)]
|
||||
extern crate panic_unwind as __please_just_link_me_dont_reference_me;
|
||||
|
||||
#[cfg(test)] extern crate test;
|
||||
|
||||
// We want to reexport a few macros from core but libcore has already been
|
||||
@ -301,6 +309,9 @@ extern crate alloc;
|
||||
extern crate rustc_unicode;
|
||||
extern crate libc;
|
||||
|
||||
// We always need an unwinder currently for backtraces
|
||||
extern crate unwind;
|
||||
|
||||
#[cfg(stage0)]
|
||||
extern crate alloc_system;
|
||||
|
||||
|
@ -17,9 +17,9 @@
|
||||
/// The entry point for panic of Rust threads.
|
||||
///
|
||||
/// This macro is used to inject panic into a Rust thread, causing the thread to
|
||||
/// unwind and panic entirely. Each thread's panic can be reaped as the
|
||||
/// `Box<Any>` type, and the single-argument form of the `panic!` macro will be
|
||||
/// the value which is transmitted.
|
||||
/// panic entirely. Each thread's panic can be reaped as the `Box<Any>` type,
|
||||
/// and the single-argument form of the `panic!` macro will be the value which
|
||||
/// is transmitted.
|
||||
///
|
||||
/// The multi-argument form of this macro panics with a string and has the
|
||||
/// `format!` syntax for building a string.
|
||||
@ -41,14 +41,14 @@ macro_rules! panic {
|
||||
panic!("explicit panic")
|
||||
});
|
||||
($msg:expr) => ({
|
||||
$crate::rt::begin_unwind($msg, {
|
||||
$crate::rt::begin_panic($msg, {
|
||||
// static requires less code at runtime, more constant data
|
||||
static _FILE_LINE: (&'static str, u32) = (file!(), line!());
|
||||
&_FILE_LINE
|
||||
})
|
||||
});
|
||||
($fmt:expr, $($arg:tt)+) => ({
|
||||
$crate::rt::begin_unwind_fmt(format_args!($fmt, $($arg)+), {
|
||||
$crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+), {
|
||||
// The leading _'s are to avoid dead code warnings if this is
|
||||
// used inside a dead function. Just `#[allow(dead_code)]` is
|
||||
// insufficient, since the user may have
|
||||
|
@ -16,10 +16,10 @@ use any::Any;
|
||||
use boxed::Box;
|
||||
use cell::UnsafeCell;
|
||||
use ops::{Deref, DerefMut};
|
||||
use panicking;
|
||||
use ptr::{Unique, Shared};
|
||||
use rc::Rc;
|
||||
use sync::{Arc, Mutex, RwLock};
|
||||
use sys_common::unwind;
|
||||
use thread::Result;
|
||||
|
||||
#[unstable(feature = "panic_handler", issue = "30449")]
|
||||
@ -383,12 +383,9 @@ impl<R, F: FnOnce() -> R> FnOnce<()> for AssertRecoverSafe<F> {
|
||||
/// ```
|
||||
#[stable(feature = "catch_unwind", since = "1.9.0")]
|
||||
pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||
let mut result = None;
|
||||
unsafe {
|
||||
let result = &mut result;
|
||||
unwind::try(move || *result = Some(f()))?
|
||||
panicking::try(f)
|
||||
}
|
||||
Ok(result.unwrap())
|
||||
}
|
||||
|
||||
/// Deprecated, renamed to `catch_unwind`
|
||||
@ -425,7 +422,7 @@ pub fn recover<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||
/// ```
|
||||
#[stable(feature = "resume_unwind", since = "1.9.0")]
|
||||
pub fn resume_unwind(payload: Box<Any + Send>) -> ! {
|
||||
unwind::rust_panic(payload)
|
||||
panicking::rust_panic(payload)
|
||||
}
|
||||
|
||||
/// Deprecated, use resume_unwind instead
|
||||
|
@ -8,13 +8,25 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Implementation of various bits and pieces of the `panic!` macro and
|
||||
//! associated runtime pieces.
|
||||
//!
|
||||
//! Specifically, this module contains the implementation of:
|
||||
//!
|
||||
//! * Panic hooks
|
||||
//! * Executing a panic up to doing the actual implementation
|
||||
//! * Shims around "try"
|
||||
|
||||
use prelude::v1::*;
|
||||
use io::prelude::*;
|
||||
|
||||
use any::Any;
|
||||
use cell::Cell;
|
||||
use cell::RefCell;
|
||||
use fmt;
|
||||
use intrinsics;
|
||||
use mem;
|
||||
use raw;
|
||||
use sync::StaticRwLock;
|
||||
use sync::atomic::{AtomicBool, Ordering};
|
||||
use sys::stdio::Stderr;
|
||||
@ -23,14 +35,33 @@ use sys_common::thread_info;
|
||||
use sys_common::util;
|
||||
use thread;
|
||||
|
||||
thread_local! { pub static PANIC_COUNT: Cell<usize> = Cell::new(0) }
|
||||
|
||||
thread_local! {
|
||||
pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = {
|
||||
RefCell::new(None)
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! { pub static PANIC_COUNT: Cell<usize> = Cell::new(0) }
|
||||
|
||||
// Binary interface to the panic runtime that the standard library depends on.
|
||||
//
|
||||
// The standard library is tagged with `#![needs_panic_runtime]` (introduced in
|
||||
// RFC 1513) to indicate that it requires some other crate tagged with
|
||||
// `#![panic_runtime]` to exist somewhere. Each panic runtime is intended to
|
||||
// implement these symbols (with the same signatures) so we can get matched up
|
||||
// to them.
|
||||
//
|
||||
// One day this may look a little less ad-hoc with the compiler helping out to
|
||||
// hook up these functions, but it is not this day!
|
||||
extern {
|
||||
fn __rust_maybe_catch_panic(f: fn(*mut u8),
|
||||
data: *mut u8,
|
||||
data_ptr: *mut usize,
|
||||
vtable_ptr: *mut usize) -> u32;
|
||||
#[unwind]
|
||||
fn __rust_start_panic(data: usize, vtable: usize) -> u32;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum Hook {
|
||||
Default,
|
||||
@ -57,7 +88,7 @@ static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if called from a panicking thread.
|
||||
#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
|
||||
#[unstable(feature = "panic_handler", issue = "30449")]
|
||||
pub fn set_hook(hook: Box<Fn(&PanicInfo) + 'static + Sync + Send>) {
|
||||
if thread::panicking() {
|
||||
panic!("cannot modify the panic hook from a panicking thread");
|
||||
@ -82,7 +113,7 @@ pub fn set_hook(hook: Box<Fn(&PanicInfo) + 'static + Sync + Send>) {
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if called from a panicking thread.
|
||||
#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
|
||||
#[unstable(feature = "panic_handler", issue = "30449")]
|
||||
pub fn take_hook() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> {
|
||||
if thread::panicking() {
|
||||
panic!("cannot modify the panic hook from a panicking thread");
|
||||
@ -102,7 +133,7 @@ pub fn take_hook() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> {
|
||||
}
|
||||
|
||||
/// A struct providing information about a panic.
|
||||
#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
|
||||
#[unstable(feature = "panic_handler", issue = "30449")]
|
||||
pub struct PanicInfo<'a> {
|
||||
payload: &'a (Any + Send),
|
||||
location: Location<'a>,
|
||||
@ -112,7 +143,7 @@ impl<'a> PanicInfo<'a> {
|
||||
/// Returns the payload associated with the panic.
|
||||
///
|
||||
/// This will commonly, but not always, be a `&'static str` or `String`.
|
||||
#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
|
||||
#[unstable(feature = "panic_handler", issue = "30449")]
|
||||
pub fn payload(&self) -> &(Any + Send) {
|
||||
self.payload
|
||||
}
|
||||
@ -122,14 +153,14 @@ impl<'a> PanicInfo<'a> {
|
||||
///
|
||||
/// This method will currently always return `Some`, but this may change
|
||||
/// in future versions.
|
||||
#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
|
||||
#[unstable(feature = "panic_handler", issue = "30449")]
|
||||
pub fn location(&self) -> Option<&Location> {
|
||||
Some(&self.location)
|
||||
}
|
||||
}
|
||||
|
||||
/// A struct containing information about the location of a panic.
|
||||
#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
|
||||
#[unstable(feature = "panic_handler", issue = "30449")]
|
||||
pub struct Location<'a> {
|
||||
file: &'a str,
|
||||
line: u32,
|
||||
@ -137,20 +168,20 @@ pub struct Location<'a> {
|
||||
|
||||
impl<'a> Location<'a> {
|
||||
/// Returns the name of the source file from which the panic originated.
|
||||
#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
|
||||
#[unstable(feature = "panic_handler", issue = "30449")]
|
||||
pub fn file(&self) -> &str {
|
||||
self.file
|
||||
}
|
||||
|
||||
/// Returns the line number from which the panic originated.
|
||||
#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
|
||||
#[unstable(feature = "panic_handler", issue = "30449")]
|
||||
pub fn line(&self) -> u32 {
|
||||
self.line
|
||||
}
|
||||
}
|
||||
|
||||
fn default_hook(info: &PanicInfo) {
|
||||
let panics = PANIC_COUNT.with(|s| s.get());
|
||||
let panics = PANIC_COUNT.with(|c| c.get());
|
||||
|
||||
// If this is a double panic, make sure that we print a backtrace
|
||||
// for this panic. Otherwise only print it if logging is enabled.
|
||||
@ -195,33 +226,143 @@ fn default_hook(info: &PanicInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
|
||||
let panics = PANIC_COUNT.with(|s| {
|
||||
let count = s.get() + 1;
|
||||
s.set(count);
|
||||
count
|
||||
/// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
|
||||
pub unsafe fn try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<Any + Send>> {
|
||||
let mut slot = None;
|
||||
let mut f = Some(f);
|
||||
let ret = PANIC_COUNT.with(|s| {
|
||||
let prev = s.get();
|
||||
s.set(0);
|
||||
|
||||
let mut to_run = || {
|
||||
slot = Some(f.take().unwrap()());
|
||||
};
|
||||
let fnptr = get_call(&mut to_run);
|
||||
let dataptr = &mut to_run as *mut _ as *mut u8;
|
||||
let mut any_data = 0;
|
||||
let mut any_vtable = 0;
|
||||
let fnptr = mem::transmute::<fn(&mut _), fn(*mut u8)>(fnptr);
|
||||
let r = __rust_maybe_catch_panic(fnptr,
|
||||
dataptr,
|
||||
&mut any_data,
|
||||
&mut any_vtable);
|
||||
s.set(prev);
|
||||
|
||||
if r == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(mem::transmute(raw::TraitObject {
|
||||
data: any_data as *mut _,
|
||||
vtable: any_vtable as *mut _,
|
||||
}))
|
||||
}
|
||||
});
|
||||
|
||||
// If this is the third nested call, on_panic triggered the last panic,
|
||||
// otherwise the double-panic check would have aborted the process.
|
||||
// Even if it is likely that on_panic was unable to log the backtrace,
|
||||
// abort immediately to avoid infinite recursion, so that attaching a
|
||||
// debugger provides a useable stacktrace.
|
||||
if panics >= 3 {
|
||||
return ret.map(|()| {
|
||||
slot.take().unwrap()
|
||||
});
|
||||
|
||||
fn get_call<F: FnMut()>(_: &mut F) -> fn(&mut F) {
|
||||
call
|
||||
}
|
||||
|
||||
fn call<F: FnMut()>(f: &mut F) {
|
||||
f()
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines whether the current thread is unwinding because of panic.
|
||||
pub fn panicking() -> bool {
|
||||
PANIC_COUNT.with(|c| c.get() != 0)
|
||||
}
|
||||
|
||||
/// Entry point of panic from the libcore crate.
|
||||
#[cfg(not(test))]
|
||||
#[lang = "panic_fmt"]
|
||||
#[unwind]
|
||||
pub extern fn rust_begin_panic(msg: fmt::Arguments,
|
||||
file: &'static str,
|
||||
line: u32) -> ! {
|
||||
begin_panic_fmt(&msg, &(file, line))
|
||||
}
|
||||
|
||||
/// The entry point for panicking with a formatted message.
|
||||
///
|
||||
/// This is designed to reduce the amount of code required at the call
|
||||
/// site as much as possible (so that `panic!()` has as low an impact
|
||||
/// on (e.g.) the inlining of other functions as possible), by moving
|
||||
/// the actual formatting into this shared place.
|
||||
#[unstable(feature = "libstd_sys_internals",
|
||||
reason = "used by the panic! macro",
|
||||
issue = "0")]
|
||||
#[inline(never)] #[cold]
|
||||
pub fn begin_panic_fmt(msg: &fmt::Arguments,
|
||||
file_line: &(&'static str, u32)) -> ! {
|
||||
use fmt::Write;
|
||||
|
||||
// We do two allocations here, unfortunately. But (a) they're
|
||||
// required with the current scheme, and (b) we don't handle
|
||||
// panic + OOM properly anyway (see comment in begin_panic
|
||||
// below).
|
||||
|
||||
let mut s = String::new();
|
||||
let _ = s.write_fmt(*msg);
|
||||
begin_panic(s, file_line)
|
||||
}
|
||||
|
||||
/// This is the entry point of panicking for panic!() and assert!().
|
||||
#[unstable(feature = "libstd_sys_internals",
|
||||
reason = "used by the panic! macro",
|
||||
issue = "0")]
|
||||
#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
|
||||
pub fn begin_panic<M: Any + Send>(msg: M, file_line: &(&'static str, u32)) -> ! {
|
||||
// Note that this should be the only allocation performed in this code path.
|
||||
// Currently this means that panic!() on OOM will invoke this code path,
|
||||
// but then again we're not really ready for panic on OOM anyway. If
|
||||
// we do start doing this, then we should propagate this allocation to
|
||||
// be performed in the parent of this thread instead of the thread that's
|
||||
// panicking.
|
||||
|
||||
rust_panic_with_hook(Box::new(msg), file_line)
|
||||
}
|
||||
|
||||
/// Executes the primary logic for a panic, including checking for recursive
|
||||
/// panics and panic hooks.
|
||||
///
|
||||
/// This is the entry point or panics from libcore, formatted panics, and
|
||||
/// `Box<Any>` panics. Here we'll verify that we're not panicking recursively,
|
||||
/// run panic hooks, and then delegate to the actual implementation of panics.
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn rust_panic_with_hook(msg: Box<Any + Send>,
|
||||
file_line: &(&'static str, u32)) -> ! {
|
||||
let (file, line) = *file_line;
|
||||
|
||||
let panics = PANIC_COUNT.with(|c| {
|
||||
let prev = c.get();
|
||||
c.set(prev + 1);
|
||||
prev
|
||||
});
|
||||
|
||||
// If this is the third nested call (e.g. panics == 2, this is 0-indexed),
|
||||
// the panic hook probably triggered the last panic, otherwise the
|
||||
// double-panic check would have aborted the process. In this case abort the
|
||||
// process real quickly as we don't want to try calling it again as it'll
|
||||
// probably just panic again.
|
||||
if panics > 1 {
|
||||
util::dumb_print(format_args!("thread panicked while processing \
|
||||
panic. aborting.\n"));
|
||||
unsafe { intrinsics::abort() }
|
||||
}
|
||||
|
||||
let info = PanicInfo {
|
||||
payload: obj,
|
||||
location: Location {
|
||||
file: file,
|
||||
line: line,
|
||||
},
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let info = PanicInfo {
|
||||
payload: &*msg,
|
||||
location: Location {
|
||||
file: file,
|
||||
line: line,
|
||||
},
|
||||
};
|
||||
let _lock = HOOK_LOCK.read();
|
||||
match HOOK {
|
||||
Hook::Default => default_hook(&info),
|
||||
@ -229,7 +370,7 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
|
||||
}
|
||||
}
|
||||
|
||||
if panics >= 2 {
|
||||
if panics > 0 {
|
||||
// If a thread panics while it's already unwinding then we
|
||||
// have limited options. Currently our preference is to
|
||||
// just abort. In the future we may consider resuming
|
||||
@ -238,4 +379,17 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
|
||||
aborting.\n"));
|
||||
unsafe { intrinsics::abort() }
|
||||
}
|
||||
|
||||
rust_panic(msg)
|
||||
}
|
||||
|
||||
/// A private no-mangle function on which to slap yer breakpoints.
|
||||
#[no_mangle]
|
||||
#[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints
|
||||
pub fn rust_panic(msg: Box<Any + Send>) -> ! {
|
||||
let code = unsafe {
|
||||
let obj = mem::transmute::<_, raw::TraitObject>(msg);
|
||||
__rust_start_panic(obj.data as usize, obj.vtable as usize)
|
||||
};
|
||||
rtabort!("failed to initiate panic, error {}", code)
|
||||
}
|
||||
|
@ -25,12 +25,10 @@
|
||||
|
||||
|
||||
// Reexport some of our utilities which are expected by other crates.
|
||||
pub use sys_common::unwind::{begin_unwind, begin_unwind_fmt};
|
||||
pub use panicking::{begin_panic, begin_panic_fmt};
|
||||
|
||||
// Rust runtime's startup objects depend on these symbols, so they must be public.
|
||||
// Since sys_common isn't public, we have to re-export them here.
|
||||
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
|
||||
pub use sys_common::unwind::imp::eh_frame_registry::*;
|
||||
#[cfg(stage0)]
|
||||
pub use panicking::begin_panic as begin_unwind;
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[lang = "start"]
|
||||
|
@ -30,9 +30,7 @@ pub mod args;
|
||||
pub mod at_exit_imp;
|
||||
pub mod backtrace;
|
||||
pub mod condvar;
|
||||
pub mod dwarf;
|
||||
pub mod io;
|
||||
pub mod libunwind;
|
||||
pub mod mutex;
|
||||
pub mod net;
|
||||
pub mod poison;
|
||||
@ -41,7 +39,6 @@ pub mod rwlock;
|
||||
pub mod thread;
|
||||
pub mod thread_info;
|
||||
pub mod thread_local;
|
||||
pub mod unwind;
|
||||
pub mod util;
|
||||
pub mod wtf8;
|
||||
|
||||
|
@ -1,241 +0,0 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
//! Implementation of Rust stack unwinding
|
||||
//!
|
||||
//! For background on exception handling and stack unwinding please see
|
||||
//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
|
||||
//! documents linked from it.
|
||||
//! These are also good reads:
|
||||
//! http://mentorembedded.github.io/cxx-abi/abi-eh.html
|
||||
//! http://monoinfinito.wordpress.com/series/exception-handling-in-c/
|
||||
//! http://www.airs.com/blog/index.php?s=exception+frames
|
||||
//!
|
||||
//! ## A brief summary
|
||||
//!
|
||||
//! Exception handling happens in two phases: a search phase and a cleanup phase.
|
||||
//!
|
||||
//! In both phases the unwinder walks stack frames from top to bottom using
|
||||
//! information from the stack frame unwind sections of the current process's
|
||||
//! modules ("module" here refers to an OS module, i.e. an executable or a
|
||||
//! dynamic library).
|
||||
//!
|
||||
//! For each stack frame, it invokes the associated "personality routine", whose
|
||||
//! address is also stored in the unwind info section.
|
||||
//!
|
||||
//! In the search phase, the job of a personality routine is to examine exception
|
||||
//! object being thrown, and to decide whether it should be caught at that stack
|
||||
//! frame. Once the handler frame has been identified, cleanup phase begins.
|
||||
//!
|
||||
//! In the cleanup phase, the unwinder invokes each personality routine again.
|
||||
//! This time it decides which (if any) cleanup code needs to be run for
|
||||
//! the current stack frame. If so, the control is transferred to a special branch
|
||||
//! in the function body, the "landing pad", which invokes destructors, frees memory,
|
||||
//! etc. At the end of the landing pad, control is transferred back to the unwinder
|
||||
//! and unwinding resumes.
|
||||
//!
|
||||
//! Once stack has been unwound down to the handler frame level, unwinding stops
|
||||
//! and the last personality routine transfers control to the catch block.
|
||||
//!
|
||||
//! ## `eh_personality` and `eh_unwind_resume`
|
||||
//!
|
||||
//! These language items are used by the compiler when generating unwind info.
|
||||
//! The first one is the personality routine described above. The second one
|
||||
//! allows compilation target to customize the process of resuming unwind at the
|
||||
//! end of the landing pads. `eh_unwind_resume` is used only if `custom_unwind_resume`
|
||||
//! flag in the target options is set.
|
||||
//!
|
||||
//! ## Frame unwind info registration
|
||||
//!
|
||||
//! Each module's image contains a frame unwind info section (usually ".eh_frame").
|
||||
//! When a module is loaded/unloaded into the process, the unwinder must be informed
|
||||
//! about the location of this section in memory. The methods of achieving that vary
|
||||
//! by the platform.
|
||||
//! On some (e.g. Linux), the unwinder can discover unwind info sections on its own
|
||||
//! (by dynamically enumerating currently loaded modules via the dl_iterate_phdr() API
|
||||
//! and finding their ".eh_frame" sections);
|
||||
//! Others, like Windows, require modules to actively register their unwind info
|
||||
//! sections via unwinder API (see `rust_eh_register_frames`/`rust_eh_unregister_frames`).
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use prelude::v1::*;
|
||||
|
||||
use any::Any;
|
||||
use boxed;
|
||||
use cmp;
|
||||
use panicking::{self,PANIC_COUNT};
|
||||
use fmt;
|
||||
use intrinsics;
|
||||
use mem;
|
||||
use sync::atomic::{self, Ordering};
|
||||
use sys_common::mutex::Mutex;
|
||||
|
||||
// The actual unwinding implementation is cfg'd here, and we've got two current
|
||||
// implementations. One goes through SEH on Windows and the other goes through
|
||||
// libgcc via the libunwind-like API.
|
||||
|
||||
// *-pc-windows-msvc
|
||||
#[cfg(target_env = "msvc")]
|
||||
#[path = "seh.rs"] #[doc(hidden)]
|
||||
pub mod imp;
|
||||
|
||||
// x86_64-pc-windows-gnu
|
||||
#[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))]
|
||||
#[path = "seh64_gnu.rs"] #[doc(hidden)]
|
||||
pub mod imp;
|
||||
|
||||
// i686-pc-windows-gnu and all others
|
||||
#[cfg(any(unix, all(windows, target_arch = "x86", target_env = "gnu")))]
|
||||
#[path = "gcc.rs"] #[doc(hidden)]
|
||||
pub mod imp;
|
||||
|
||||
/// Invoke a closure, capturing the cause of panic if one occurs.
|
||||
///
|
||||
/// This function will return `Ok(())` if the closure did not panic, and will
|
||||
/// return `Err(cause)` if the closure panics. The `cause` returned is the
|
||||
/// object with which panic was originally invoked.
|
||||
///
|
||||
/// This function also is unsafe for a variety of reasons:
|
||||
///
|
||||
/// * This is not safe to call in a nested fashion. The unwinding
|
||||
/// interface for Rust is designed to have at most one try/catch block per
|
||||
/// thread, not multiple. No runtime checking is currently performed to uphold
|
||||
/// this invariant, so this function is not safe. A nested try/catch block
|
||||
/// may result in corruption of the outer try/catch block's state, especially
|
||||
/// if this is used within a thread itself.
|
||||
///
|
||||
/// * It is not sound to trigger unwinding while already unwinding. Rust threads
|
||||
/// have runtime checks in place to ensure this invariant, but it is not
|
||||
/// guaranteed that a rust thread is in place when invoking this function.
|
||||
/// Unwinding twice can lead to resource leaks where some destructors are not
|
||||
/// run.
|
||||
pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
|
||||
let mut f = Some(f);
|
||||
return inner_try(try_fn::<F>, &mut f as *mut _ as *mut u8);
|
||||
|
||||
fn try_fn<F: FnOnce()>(opt_closure: *mut u8) {
|
||||
let opt_closure = opt_closure as *mut Option<F>;
|
||||
unsafe { (*opt_closure).take().unwrap()(); }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
|
||||
-> Result<(), Box<Any + Send>> {
|
||||
PANIC_COUNT.with(|s| {
|
||||
let prev = s.get();
|
||||
s.set(0);
|
||||
|
||||
// The "payload" here is a platform-specific region of memory which is
|
||||
// used to transmit information about the exception being thrown from
|
||||
// the point-of-throw back to this location.
|
||||
//
|
||||
// A pointer to this data is passed to the `try` intrinsic itself,
|
||||
// allowing this function, the `try` intrinsic, imp::payload(), and
|
||||
// imp::cleanup() to all work in concert to transmit this information.
|
||||
//
|
||||
// More information about what this pointer actually is can be found in
|
||||
// each implementation as well as browsing the compiler source itself.
|
||||
let mut payload = imp::payload();
|
||||
let r = intrinsics::try(f, data, &mut payload as *mut _ as *mut _);
|
||||
s.set(prev);
|
||||
if r == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(imp::cleanup(payload))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Determines whether the current thread is unwinding because of panic.
|
||||
pub fn panicking() -> bool {
|
||||
PANIC_COUNT.with(|s| s.get() != 0)
|
||||
}
|
||||
|
||||
// An uninlined, unmangled function upon which to slap yer breakpoints
|
||||
#[inline(never)]
|
||||
#[no_mangle]
|
||||
#[allow(private_no_mangle_fns)]
|
||||
pub fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
|
||||
unsafe {
|
||||
imp::panic(cause)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
/// Entry point of panic from the libcore crate.
|
||||
#[lang = "panic_fmt"]
|
||||
#[unwind]
|
||||
pub extern fn rust_begin_unwind(msg: fmt::Arguments,
|
||||
file: &'static str, line: u32) -> ! {
|
||||
begin_unwind_fmt(msg, &(file, line))
|
||||
}
|
||||
|
||||
/// The entry point for unwinding with a formatted message.
|
||||
///
|
||||
/// This is designed to reduce the amount of code required at the call
|
||||
/// site as much as possible (so that `panic!()` has as low an impact
|
||||
/// on (e.g.) the inlining of other functions as possible), by moving
|
||||
/// the actual formatting into this shared place.
|
||||
#[unstable(feature = "libstd_sys_internals",
|
||||
reason = "used by the panic! macro",
|
||||
issue = "0")]
|
||||
#[inline(never)] #[cold]
|
||||
pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, u32)) -> ! {
|
||||
use fmt::Write;
|
||||
|
||||
// We do two allocations here, unfortunately. But (a) they're
|
||||
// required with the current scheme, and (b) we don't handle
|
||||
// panic + OOM properly anyway (see comment in begin_unwind
|
||||
// below).
|
||||
|
||||
let mut s = String::new();
|
||||
let _ = s.write_fmt(msg);
|
||||
begin_unwind_inner(Box::new(s), file_line)
|
||||
}
|
||||
|
||||
/// This is the entry point of unwinding for panic!() and assert!().
|
||||
#[unstable(feature = "libstd_sys_internals",
|
||||
reason = "used by the panic! macro",
|
||||
issue = "0")]
|
||||
#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
|
||||
pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, u32)) -> ! {
|
||||
// Note that this should be the only allocation performed in this code path.
|
||||
// Currently this means that panic!() on OOM will invoke this code path,
|
||||
// but then again we're not really ready for panic on OOM anyway. If
|
||||
// we do start doing this, then we should propagate this allocation to
|
||||
// be performed in the parent of this thread instead of the thread that's
|
||||
// panicking.
|
||||
|
||||
// see below for why we do the `Any` coercion here.
|
||||
begin_unwind_inner(Box::new(msg), file_line)
|
||||
}
|
||||
|
||||
/// The core of the unwinding.
|
||||
///
|
||||
/// This is non-generic to avoid instantiation bloat in other crates
|
||||
/// (which makes compilation of small crates noticeably slower). (Note:
|
||||
/// we need the `Any` object anyway, we're not just creating it to
|
||||
/// avoid being generic.)
|
||||
///
|
||||
/// Doing this split took the LLVM IR line counts of `fn main() { panic!()
|
||||
/// }` from ~1900/3700 (-O/no opts) to 180/590.
|
||||
#[inline(never)] #[cold] // this is the slow path, please never inline this
|
||||
fn begin_unwind_inner(msg: Box<Any + Send>,
|
||||
file_line: &(&'static str, u32)) -> ! {
|
||||
let (file, line) = *file_line;
|
||||
|
||||
// First, invoke the default panic handler.
|
||||
panicking::on_panic(&*msg, file, line);
|
||||
|
||||
// Finally, perform the unwinding.
|
||||
rust_panic(msg);
|
||||
}
|
@ -15,6 +15,7 @@ use mem;
|
||||
use sync::StaticMutex;
|
||||
|
||||
use super::super::printing::print;
|
||||
use unwind as uw;
|
||||
|
||||
#[inline(never)] // if we know this is a function call, we can skip it when
|
||||
// tracing
|
||||
@ -102,126 +103,3 @@ pub fn write(w: &mut Write) -> io::Result<()> {
|
||||
uw::_URC_NO_REASON
|
||||
}
|
||||
}
|
||||
|
||||
/// Unwind library interface used for backtraces
|
||||
///
|
||||
/// Note that dead code is allowed as here are just bindings
|
||||
/// iOS doesn't use all of them it but adding more
|
||||
/// platform-specific configs pollutes the code too much
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(non_snake_case)]
|
||||
mod uw {
|
||||
pub use self::_Unwind_Reason_Code::*;
|
||||
|
||||
use libc;
|
||||
|
||||
#[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 enum _Unwind_Context {}
|
||||
|
||||
pub type _Unwind_Trace_Fn =
|
||||
extern fn(ctx: *mut _Unwind_Context,
|
||||
arg: *mut libc::c_void) -> _Unwind_Reason_Code;
|
||||
|
||||
extern {
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
@ -277,21 +277,6 @@ pub const CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
|
||||
pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
|
||||
pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
|
||||
pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
|
||||
#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
|
||||
pub const EXCEPTION_NONCONTINUABLE: DWORD = 0x1; // Noncontinuable exception
|
||||
#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
|
||||
pub const EXCEPTION_UNWINDING: DWORD = 0x2; // Unwind is in progress
|
||||
#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
|
||||
pub const EXCEPTION_EXIT_UNWIND: DWORD = 0x4; // Exit unwind is in progress
|
||||
#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
|
||||
pub const EXCEPTION_TARGET_UNWIND: DWORD = 0x20; // Target unwind in progress
|
||||
#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
|
||||
pub const EXCEPTION_COLLIDED_UNWIND: DWORD = 0x40; // Collided exception handler call
|
||||
#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
|
||||
pub const EXCEPTION_UNWIND: DWORD = EXCEPTION_UNWINDING |
|
||||
EXCEPTION_EXIT_UNWIND |
|
||||
EXCEPTION_TARGET_UNWIND |
|
||||
EXCEPTION_COLLIDED_UNWIND;
|
||||
|
||||
pub const PIPE_ACCESS_INBOUND: DWORD = 0x00000001;
|
||||
pub const FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000;
|
||||
@ -813,31 +798,6 @@ pub struct in6_addr {
|
||||
pub s6_addr: [u8; 16],
|
||||
}
|
||||
|
||||
#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
|
||||
pub enum UNWIND_HISTORY_TABLE {}
|
||||
|
||||
#[repr(C)]
|
||||
#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
|
||||
pub struct RUNTIME_FUNCTION {
|
||||
pub BeginAddress: DWORD,
|
||||
pub EndAddress: DWORD,
|
||||
pub UnwindData: DWORD,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
|
||||
pub struct DISPATCHER_CONTEXT {
|
||||
pub ControlPc: LPVOID,
|
||||
pub ImageBase: LPVOID,
|
||||
pub FunctionEntry: *const RUNTIME_FUNCTION,
|
||||
pub EstablisherFrame: LPVOID,
|
||||
pub TargetIp: LPVOID,
|
||||
pub ContextRecord: *const CONTEXT,
|
||||
pub LanguageHandler: LPVOID,
|
||||
pub HandlerData: *const u8,
|
||||
pub HistoryTable: *const UNWIND_HISTORY_TABLE,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(dead_code)] // we only use some variants
|
||||
@ -1113,19 +1073,6 @@ extern "system" {
|
||||
pbBuffer: *mut BYTE) -> BOOL;
|
||||
pub fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
|
||||
|
||||
#[unwind]
|
||||
#[cfg(any(target_arch = "x86_64", target_env = "msvc"))]
|
||||
pub fn RaiseException(dwExceptionCode: DWORD,
|
||||
dwExceptionFlags: DWORD,
|
||||
nNumberOfArguments: DWORD,
|
||||
lpArguments: *const ULONG_PTR);
|
||||
#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
|
||||
pub fn RtlUnwindEx(TargetFrame: LPVOID,
|
||||
TargetIp: LPVOID,
|
||||
ExceptionRecord: *const EXCEPTION_RECORD,
|
||||
ReturnValue: LPVOID,
|
||||
OriginalContext: *const CONTEXT,
|
||||
HistoryTable: *const UNWIND_HISTORY_TABLE);
|
||||
pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME);
|
||||
|
||||
pub fn CreateEventW(lpEventAttributes: LPSECURITY_ATTRIBUTES,
|
||||
|
@ -163,14 +163,15 @@ use prelude::v1::*;
|
||||
|
||||
use any::Any;
|
||||
use cell::UnsafeCell;
|
||||
use ffi::{CStr, CString};
|
||||
use fmt;
|
||||
use io;
|
||||
use panic;
|
||||
use panicking;
|
||||
use str;
|
||||
use ffi::{CStr, CString};
|
||||
use sync::{Mutex, Condvar, Arc};
|
||||
use sys::thread as imp;
|
||||
use sys_common::thread_info;
|
||||
use sys_common::unwind;
|
||||
use sys_common::util;
|
||||
use sys_common::{AsInner, IntoInner};
|
||||
use time::Duration;
|
||||
@ -273,14 +274,8 @@ impl Builder {
|
||||
}
|
||||
unsafe {
|
||||
thread_info::set(imp::guard::current(), their_thread);
|
||||
let mut output = None;
|
||||
let try_result = {
|
||||
let ptr = &mut output;
|
||||
unwind::try(move || *ptr = Some(f()))
|
||||
};
|
||||
*their_packet.get() = Some(try_result.map(|()| {
|
||||
output.unwrap()
|
||||
}));
|
||||
let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f));
|
||||
*their_packet.get() = Some(try_result);
|
||||
}
|
||||
};
|
||||
|
||||
@ -337,7 +332,7 @@ pub fn yield_now() {
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn panicking() -> bool {
|
||||
unwind::panicking()
|
||||
panicking::panicking()
|
||||
}
|
||||
|
||||
/// Puts the current thread to sleep for the specified amount of time.
|
||||
|
@ -755,7 +755,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||
let expr_file_line_ptr = self.expr_addr_of(span, expr_file_line_tuple);
|
||||
self.expr_call_global(
|
||||
span,
|
||||
self.std_path(&["rt", "begin_unwind"]),
|
||||
self.std_path(&["rt", "begin_panic"]),
|
||||
vec!(
|
||||
self.expr_str(span, msg),
|
||||
expr_file_line_ptr))
|
||||
|
@ -141,6 +141,8 @@ declare_features! (
|
||||
(active, simd_ffi, "1.0.0", Some(27731)),
|
||||
(active, start, "1.0.0", Some(29633)),
|
||||
(active, structural_match, "1.8.0", Some(31434)),
|
||||
(active, panic_runtime, "1.10.0", Some(32837)),
|
||||
(active, needs_panic_runtime, "1.10.0", Some(32837)),
|
||||
|
||||
// OIBIT specific features
|
||||
(active, optin_builtin_traits, "1.0.0", Some(13231)),
|
||||
@ -435,6 +437,15 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat
|
||||
attribute is an experimental \
|
||||
feature",
|
||||
cfg_fn!(needs_allocator))),
|
||||
("panic_runtime", Whitelisted, Gated("panic_runtime",
|
||||
"the `#[panic_runtime]` attribute is \
|
||||
an experimental feature",
|
||||
cfg_fn!(panic_runtime))),
|
||||
("needs_panic_runtime", Whitelisted, Gated("needs_panic_runtime",
|
||||
"the `#[needs_panic_runtime]` \
|
||||
attribute is an experimental \
|
||||
feature",
|
||||
cfg_fn!(needs_panic_runtime))),
|
||||
("rustc_variance", Normal, Gated("rustc_attrs",
|
||||
"the `#[rustc_variance]` attribute \
|
||||
is just used for rustc unit tests \
|
||||
|
@ -41,10 +41,12 @@
|
||||
#![feature(set_stdio)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(question_mark)]
|
||||
#![feature(panic_unwind)]
|
||||
|
||||
extern crate getopts;
|
||||
extern crate term;
|
||||
extern crate libc;
|
||||
extern crate panic_unwind;
|
||||
|
||||
pub use self::TestFn::*;
|
||||
pub use self::ColorConfig::*;
|
||||
|
13
src/libunwind/Cargo.toml
Normal file
13
src/libunwind/Cargo.toml
Normal file
@ -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" }
|
39
src/libunwind/build.rs
Normal file
39
src/libunwind/build.rs
Normal file
@ -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");
|
||||
}
|
||||
}
|
30
src/libunwind/lib.rs
Normal file
30
src/libunwind/lib.rs
Normal file
@ -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::*;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// 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.
|
||||
//
|
||||
@ -8,12 +8,9 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Unwind library interface
|
||||
#![allow(bad_style)]
|
||||
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(dead_code)] // these are just bindings
|
||||
use libc;
|
||||
|
||||
#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
|
||||
pub use self::_Unwind_Action::*;
|
||||
@ -21,11 +18,9 @@ pub use self::_Unwind_Action::*;
|
||||
pub use self::_Unwind_State::*;
|
||||
pub use self::_Unwind_Reason_Code::*;
|
||||
|
||||
use libc;
|
||||
|
||||
#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum _Unwind_Action {
|
||||
_UA_SEARCH_PHASE = 1,
|
||||
_UA_CLEANUP_PHASE = 2,
|
||||
@ -36,7 +31,7 @@ pub enum _Unwind_Action {
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum _Unwind_State {
|
||||
_US_VIRTUAL_UNWIND_FRAME = 0,
|
||||
_US_UNWIND_FRAME_STARTING = 1,
|
||||
@ -47,7 +42,6 @@ pub enum _Unwind_State {
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum _Unwind_Reason_Code {
|
||||
_URC_NO_REASON = 0,
|
||||
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
||||
@ -65,6 +59,10 @@ 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;
|
||||
|
||||
@ -126,9 +124,12 @@ pub type _Unwind_Exception_Cleanup_Fn =
|
||||
link(name = "gcc_pic"))]
|
||||
#[cfg_attr(target_os = "bitrig",
|
||||
link(name = "c++abi"))]
|
||||
#[cfg_attr(all(target_os = "windows", target_env="gnu"),
|
||||
#[cfg_attr(all(target_os = "windows", target_env = "gnu"),
|
||||
link(name = "gcc_eh"))]
|
||||
extern "C" {
|
||||
#[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")))]
|
||||
@ -145,14 +146,102 @@ extern "C" {
|
||||
|
||||
#[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(always)]
|
||||
#[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
|
||||
}
|
54
src/rustc/std_shim/Cargo.lock
generated
54
src/rustc/std_shim/Cargo.lock
generated
@ -5,15 +5,6 @@ dependencies = [
|
||||
"std 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "advapi32-sys"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloc"
|
||||
version = "0.0.0"
|
||||
@ -27,7 +18,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"build_helper 0.1.0",
|
||||
"core 0.0.0",
|
||||
"gcc 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.0.0",
|
||||
]
|
||||
|
||||
@ -58,12 +49,8 @@ version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.17"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
@ -72,6 +59,24 @@ dependencies = [
|
||||
"core 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "panic_abort"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"core 0.0.0",
|
||||
"libc 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "panic_unwind"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"alloc 0.0.0",
|
||||
"core 0.0.0",
|
||||
"libc 0.0.0",
|
||||
"unwind 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.0.0"
|
||||
@ -96,19 +101,20 @@ dependencies = [
|
||||
"build_helper 0.1.0",
|
||||
"collections 0.0.0",
|
||||
"core 0.0.0",
|
||||
"gcc 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.0.0",
|
||||
"panic_abort 0.0.0",
|
||||
"panic_unwind 0.0.0",
|
||||
"rand 0.0.0",
|
||||
"rustc_unicode 0.0.0",
|
||||
"unwind 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
name = "unwind"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"core 0.0.0",
|
||||
"libc 0.0.0",
|
||||
]
|
||||
|
||||
|
31
src/test/codegen/lto-removes-invokes.rs
Normal file
31
src/test/codegen/lto-removes-invokes.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// 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.
|
||||
|
||||
// compile-flags: -C lto -C panic=abort -O
|
||||
// no-prefer-dynamic
|
||||
|
||||
fn main() {
|
||||
foo();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[inline(never)]
|
||||
fn foo() {
|
||||
let _a = Box::new(3);
|
||||
bar();
|
||||
// CHECK-LABEL: foo
|
||||
// CHECK: call {{.*}} void @bar
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[no_mangle]
|
||||
fn bar() {
|
||||
println!("hello!");
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// 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.
|
||||
|
||||
// compile-flags:-C panic=abort -C prefer-dynamic
|
||||
// ignore-musl - no dylibs here
|
||||
// error-pattern:`panic_unwind` is not compiled with this crate's panic strategy
|
||||
|
||||
// This is a test where the local crate, compiled with `panic=abort`, links to
|
||||
// the standard library **dynamically** which is already linked against
|
||||
// `panic=unwind`. We should fail because the linked panic runtime does not
|
||||
// correspond with our `-C panic` option.
|
||||
//
|
||||
// Note that this test assumes that the dynamic version of the standard library
|
||||
// is linked to `panic_unwind`, which is currently the case.
|
||||
|
||||
fn main() {
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
// 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-prefer-dynamic
|
||||
|
||||
#![feature(needs_panic_runtime)]
|
||||
#![crate_type = "rlib"]
|
||||
#![needs_panic_runtime]
|
||||
#![no_std]
|
@ -0,0 +1,27 @@
|
||||
// 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.
|
||||
|
||||
// compile-flags:-C panic=abort
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![feature(panic_runtime)]
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
#![no_std]
|
||||
#![panic_runtime]
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn __rust_maybe_catch_panic() {}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn __rust_start_panic() {}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn rust_eh_personality() {}
|
@ -0,0 +1,23 @@
|
||||
// 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-prefer-dynamic
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
#![no_std]
|
||||
#![feature(lang_items)]
|
||||
|
||||
#[lang = "panic_fmt"]
|
||||
fn panic_fmt() {}
|
||||
#[lang = "eh_personality"]
|
||||
fn eh_personality() {}
|
||||
#[lang = "eh_unwind_resume"]
|
||||
fn eh_unwind_resume() {}
|
@ -0,0 +1,27 @@
|
||||
// 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.
|
||||
|
||||
// compile-flags:-C panic=unwind
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![feature(panic_runtime)]
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
#![no_std]
|
||||
#![panic_runtime]
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn __rust_maybe_catch_panic() {}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn __rust_start_panic() {}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn rust_eh_personality() {}
|
@ -0,0 +1,27 @@
|
||||
// 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.
|
||||
|
||||
// compile-flags:-C panic=unwind
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![feature(panic_runtime)]
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
#![no_std]
|
||||
#![panic_runtime]
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn __rust_maybe_catch_panic() {}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn __rust_start_panic() {}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn rust_eh_personality() {}
|
@ -0,0 +1,18 @@
|
||||
// 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-prefer-dynamic
|
||||
|
||||
#![feature(panic_runtime)]
|
||||
#![crate_type = "rlib"]
|
||||
#![panic_runtime]
|
||||
#![no_std]
|
||||
|
||||
extern crate needs_panic_runtime;
|
@ -0,0 +1,17 @@
|
||||
// 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.
|
||||
|
||||
// compile-flags:-C panic=abort
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_runtime_abort;
|
@ -0,0 +1,16 @@
|
||||
// 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-prefer-dynamic
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_runtime_unwind;
|
14
src/test/compile-fail/panic-runtime/bad-panic-flag1.rs
Normal file
14
src/test/compile-fail/panic-runtime/bad-panic-flag1.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// 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.
|
||||
|
||||
// compile-flags:-C panic=foo
|
||||
// error-pattern:either `panic` or `abort` was expected
|
||||
|
||||
fn main() {}
|
14
src/test/compile-fail/panic-runtime/bad-panic-flag2.rs
Normal file
14
src/test/compile-fail/panic-runtime/bad-panic-flag2.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// 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.
|
||||
|
||||
// compile-flags:-C panic
|
||||
// error-pattern:requires either `panic` or `abort`
|
||||
|
||||
fn main() {}
|
20
src/test/compile-fail/panic-runtime/libtest-unwinds.rs
Normal file
20
src/test/compile-fail/panic-runtime/libtest-unwinds.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// 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.
|
||||
|
||||
// error-pattern:is not compiled with this crate's panic strategy `abort`
|
||||
// compile-flags:-C panic=abort
|
||||
|
||||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
14
src/test/compile-fail/panic-runtime/needs-gate.rs
Normal file
14
src/test/compile-fail/panic-runtime/needs-gate.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// 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.
|
||||
|
||||
#![panic_runtime] //~ ERROR: is an experimental feature
|
||||
#![needs_panic_runtime] //~ ERROR: is an experimental feature
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,15 @@
|
||||
// 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.
|
||||
|
||||
// aux-build:needs-panic-runtime.rs
|
||||
// aux-build:runtime-depending-on-panic-runtime.rs
|
||||
// error-pattern:cannot depend on a crate that needs a panic runtime
|
||||
|
||||
extern crate runtime_depending_on_panic_runtime;
|
@ -0,0 +1,24 @@
|
||||
// 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.
|
||||
|
||||
// aux-build:panic-runtime-unwind.rs
|
||||
// aux-build:panic-runtime-abort.rs
|
||||
// aux-build:wants-panic-runtime-unwind.rs
|
||||
// aux-build:wants-panic-runtime-abort.rs
|
||||
// aux-build:panic-runtime-lang-items.rs
|
||||
// error-pattern: is not compiled with this crate's panic strategy `unwind`
|
||||
|
||||
#![no_std]
|
||||
|
||||
extern crate wants_panic_runtime_unwind;
|
||||
extern crate wants_panic_runtime_abort;
|
||||
extern crate panic_runtime_lang_items;
|
||||
|
||||
fn main() {}
|
23
src/test/compile-fail/panic-runtime/two-panic-runtimes.rs
Normal file
23
src/test/compile-fail/panic-runtime/two-panic-runtimes.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// 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.
|
||||
|
||||
// error-pattern:cannot link together two panic runtimes: panic_runtime_unwind and panic_runtime_unwind2
|
||||
// ignore-tidy-linelength
|
||||
// aux-build:panic-runtime-unwind.rs
|
||||
// aux-build:panic-runtime-unwind2.rs
|
||||
// aux-build:panic-runtime-lang-items.rs
|
||||
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_runtime_unwind;
|
||||
extern crate panic_runtime_unwind2;
|
||||
extern crate panic_runtime_lang_items;
|
||||
|
||||
fn main() {}
|
17
src/test/compile-fail/panic-runtime/want-abort-got-unwind.rs
Normal file
17
src/test/compile-fail/panic-runtime/want-abort-got-unwind.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// 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.
|
||||
|
||||
// error-pattern:is not compiled with this crate's panic strategy `abort`
|
||||
// aux-build:panic-runtime-unwind.rs
|
||||
// compile-flags:-C panic=abort
|
||||
|
||||
extern crate panic_runtime_unwind;
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,18 @@
|
||||
// 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.
|
||||
|
||||
// error-pattern:is not compiled with this crate's panic strategy `abort`
|
||||
// aux-build:panic-runtime-unwind.rs
|
||||
// aux-build:wants-panic-runtime-unwind.rs
|
||||
// compile-flags:-C panic=abort
|
||||
|
||||
extern crate wants_panic_runtime_unwind;
|
||||
|
||||
fn main() {}
|
20
src/test/compile-fail/panic-runtime/want-unwind-got-abort.rs
Normal file
20
src/test/compile-fail/panic-runtime/want-unwind-got-abort.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// 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.
|
||||
|
||||
// error-pattern:is incompatible with this crate's strategy of `unwind`
|
||||
// aux-build:panic-runtime-abort.rs
|
||||
// aux-build:panic-runtime-lang-items.rs
|
||||
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_runtime_abort;
|
||||
extern crate panic_runtime_lang_items;
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,21 @@
|
||||
// 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.
|
||||
|
||||
// error-pattern:is incompatible with this crate's strategy of `unwind`
|
||||
// aux-build:panic-runtime-abort.rs
|
||||
// aux-build:wants-panic-runtime-abort.rs
|
||||
// aux-build:panic-runtime-lang-items.rs
|
||||
|
||||
#![no_std]
|
||||
|
||||
extern crate wants_panic_runtime_abort;
|
||||
extern crate panic_runtime_lang_items;
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,35 @@
|
||||
// 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.
|
||||
|
||||
// compile-flags:-C panic=abort
|
||||
// aux-build:exit-success-if-unwind.rs
|
||||
// no-prefer-dynamic
|
||||
|
||||
extern crate exit_success_if_unwind;
|
||||
|
||||
use std::process::Command;
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
let mut args = env::args_os();
|
||||
let me = args.next().unwrap();
|
||||
|
||||
if let Some(s) = args.next() {
|
||||
if &*s == "foo" {
|
||||
exit_success_if_unwind::bar(do_panic);
|
||||
}
|
||||
}
|
||||
let s = Command::new(env::args_os().next().unwrap()).arg("foo").status();
|
||||
assert!(s.unwrap().code() != Some(0));
|
||||
}
|
||||
|
||||
fn do_panic() {
|
||||
panic!("try to catch me");
|
||||
}
|
39
src/test/run-pass/panic-runtime/abort.rs
Normal file
39
src/test/run-pass/panic-runtime/abort.rs
Normal file
@ -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.
|
||||
|
||||
// compile-flags:-C panic=abort
|
||||
// no-prefer-dynamic
|
||||
|
||||
use std::process::Command;
|
||||
use std::env;
|
||||
|
||||
struct Bomb;
|
||||
|
||||
impl Drop for Bomb {
|
||||
fn drop(&mut self) {
|
||||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut args = env::args_os();
|
||||
let me = args.next().unwrap();
|
||||
|
||||
if let Some(s) = args.next() {
|
||||
if &*s == "foo" {
|
||||
|
||||
let _bomb = Bomb;
|
||||
|
||||
panic!("try to catch me");
|
||||
}
|
||||
}
|
||||
let s = Command::new(env::args_os().next().unwrap()).arg("foo").status();
|
||||
assert!(s.unwrap().code() != Some(0));
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
// 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-prefer-dynamic
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
struct Bomb;
|
||||
|
||||
impl Drop for Bomb {
|
||||
fn drop(&mut self) {
|
||||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bar(f: fn()) {
|
||||
let _bomb = Bomb;
|
||||
f();
|
||||
}
|
19
src/test/run-pass/panic-runtime/link-to-abort.rs
Normal file
19
src/test/run-pass/panic-runtime/link-to-abort.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// 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.
|
||||
|
||||
// compile-flags:-C panic=abort
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![feature(panic_abort)]
|
||||
|
||||
extern crate panic_abort;
|
||||
|
||||
fn main() {
|
||||
}
|
18
src/test/run-pass/panic-runtime/link-to-unwind.rs
Normal file
18
src/test/run-pass/panic-runtime/link-to-unwind.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// 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-prefer-dynamic
|
||||
|
||||
#![feature(panic_unwind)]
|
||||
|
||||
extern crate panic_unwind;
|
||||
|
||||
fn main() {
|
||||
}
|
39
src/test/run-pass/panic-runtime/lto-abort.rs
Normal file
39
src/test/run-pass/panic-runtime/lto-abort.rs
Normal file
@ -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.
|
||||
|
||||
// compile-flags:-C lto -C panic=abort
|
||||
// no-prefer-dynamic
|
||||
|
||||
use std::process::Command;
|
||||
use std::env;
|
||||
|
||||
struct Bomb;
|
||||
|
||||
impl Drop for Bomb {
|
||||
fn drop(&mut self) {
|
||||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut args = env::args_os();
|
||||
let me = args.next().unwrap();
|
||||
|
||||
if let Some(s) = args.next() {
|
||||
if &*s == "foo" {
|
||||
|
||||
let _bomb = Bomb;
|
||||
|
||||
panic!("try to catch me");
|
||||
}
|
||||
}
|
||||
let s = Command::new(env::args_os().next().unwrap()).arg("foo").status();
|
||||
assert!(s.unwrap().code() != Some(0));
|
||||
}
|
41
src/test/run-pass/panic-runtime/lto-unwind.rs
Normal file
41
src/test/run-pass/panic-runtime/lto-unwind.rs
Normal file
@ -0,0 +1,41 @@
|
||||
// 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.
|
||||
|
||||
// compile-flags:-C lto -C panic=unwind
|
||||
// no-prefer-dynamic
|
||||
|
||||
use std::process::Command;
|
||||
use std::env;
|
||||
|
||||
struct Bomb;
|
||||
|
||||
impl Drop for Bomb {
|
||||
fn drop(&mut self) {
|
||||
println!("hurray you ran me");
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut args = env::args_os();
|
||||
let me = args.next().unwrap();
|
||||
|
||||
if let Some(s) = args.next() {
|
||||
if &*s == "foo" {
|
||||
|
||||
let _bomb = Bomb;
|
||||
|
||||
panic!("try to catch me");
|
||||
}
|
||||
}
|
||||
let s = Command::new(env::args_os().next().unwrap()).arg("foo").output();
|
||||
let s = s.unwrap();
|
||||
assert!(!s.status.success());
|
||||
assert!(String::from_utf8_lossy(&s.stdout).contains("hurray you ran me"));
|
||||
}
|
@ -85,6 +85,9 @@ fn verify(tomlfile: &Path, libfile: &Path, bad: &mut bool) {
|
||||
if krate == "alloc_jemalloc" && toml.contains("name = \"std\"") {
|
||||
continue
|
||||
}
|
||||
if krate == "panic_abort" && toml.contains("name = \"std\"") {
|
||||
continue
|
||||
}
|
||||
|
||||
if !librs.contains(&format!("extern crate {}", krate)) {
|
||||
println!("{} doesn't have `extern crate {}`, but Cargo.toml \
|
||||
|
Loading…
Reference in New Issue
Block a user