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 \
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
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
$(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
} 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
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()) {
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
#[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 {
--- /dev/null
+[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" }
--- /dev/null
+// 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() {}
--- /dev/null
+[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",
+]
+
--- /dev/null
+[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" }
--- /dev/null
+// Copyright 2015 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.
+
+//! Parsing of GCC-style Language-Specific Data Area (LSDA)
+//! For details see:
+//! http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
+//! http://mentorembedded.github.io/cxx-abi/exceptions.pdf
+//! http://www.airs.com/blog/archives/460
+//! http://www.airs.com/blog/archives/464
+//!
+//! A reference implementation may be found in the GCC source tree
+//! (<root>/libgcc/unwind-c.c as of this writing)
+
+#![allow(non_upper_case_globals)]
+#![allow(unused)]
+
+use dwarf::DwarfReader;
+use core::mem;
+
+pub const DW_EH_PE_omit : u8 = 0xFF;
+pub const DW_EH_PE_absptr : u8 = 0x00;
+
+pub const DW_EH_PE_uleb128 : u8 = 0x01;
+pub const DW_EH_PE_udata2 : u8 = 0x02;
+pub const DW_EH_PE_udata4 : u8 = 0x03;
+pub const DW_EH_PE_udata8 : u8 = 0x04;
+pub const DW_EH_PE_sleb128 : u8 = 0x09;
+pub const DW_EH_PE_sdata2 : u8 = 0x0A;
+pub const DW_EH_PE_sdata4 : u8 = 0x0B;
+pub const DW_EH_PE_sdata8 : u8 = 0x0C;
+
+pub const DW_EH_PE_pcrel : u8 = 0x10;
+pub const DW_EH_PE_textrel : u8 = 0x20;
+pub const DW_EH_PE_datarel : u8 = 0x30;
+pub const DW_EH_PE_funcrel : u8 = 0x40;
+pub const DW_EH_PE_aligned : u8 = 0x50;
+
+pub const DW_EH_PE_indirect : u8 = 0x80;
+
+#[derive(Copy, Clone)]
+pub struct EHContext {
+ pub ip: usize, // Current instruction pointer
+ pub func_start: usize, // Address of the current function
+ pub text_start: usize, // Address of the code section
+ pub data_start: usize, // Address of the data section
+}
+
+pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext)
+ -> Option<usize> {
+ if lsda.is_null() {
+ return None;
+ }
+
+ let func_start = context.func_start;
+ let mut reader = DwarfReader::new(lsda);
+
+ let start_encoding = reader.read::<u8>();
+ // base address for landing pad offsets
+ let lpad_base = if start_encoding != DW_EH_PE_omit {
+ read_encoded_pointer(&mut reader, context, start_encoding)
+ } else {
+ func_start
+ };
+
+ let ttype_encoding = reader.read::<u8>();
+ if ttype_encoding != DW_EH_PE_omit {
+ // Rust doesn't analyze exception types, so we don't care about the type table
+ reader.read_uleb128();
+ }
+
+ let call_site_encoding = reader.read::<u8>();
+ let call_site_table_length = reader.read_uleb128();
+ let action_table = reader.ptr.offset(call_site_table_length as isize);
+ // Return addresses point 1 byte past the call instruction, which could
+ // be in the next IP range.
+ let ip = context.ip-1;
+
+ while reader.ptr < action_table {
+ let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
+ let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
+ let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
+ let cs_action = reader.read_uleb128();
+ // Callsite table is sorted by cs_start, so if we've passed the ip, we
+ // may stop searching.
+ if ip < func_start + cs_start {
+ break
+ }
+ if ip < func_start + cs_start + cs_len {
+ if cs_lpad != 0 {
+ return Some(lpad_base + cs_lpad);
+ } else {
+ return None;
+ }
+ }
+ }
+ // IP range not found: gcc's C++ personality calls terminate() here,
+ // however the rest of the languages treat this the same as cs_lpad == 0.
+ // We follow this suit.
+ None
+}
+
+#[inline]
+fn round_up(unrounded: usize, align: usize) -> usize {
+ assert!(align.is_power_of_two());
+ (unrounded + align - 1) & !(align - 1)
+}
+
+unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
+ context: &EHContext,
+ encoding: u8) -> usize {
+ assert!(encoding != DW_EH_PE_omit);
+
+ // DW_EH_PE_aligned implies it's an absolute pointer value
+ if encoding == DW_EH_PE_aligned {
+ reader.ptr = round_up(reader.ptr as usize,
+ mem::size_of::<usize>()) as *const u8;
+ return reader.read::<usize>();
+ }
+
+ let mut result = match encoding & 0x0F {
+ DW_EH_PE_absptr => reader.read::<usize>(),
+ DW_EH_PE_uleb128 => reader.read_uleb128() as usize,
+ DW_EH_PE_udata2 => reader.read::<u16>() as usize,
+ DW_EH_PE_udata4 => reader.read::<u32>() as usize,
+ DW_EH_PE_udata8 => reader.read::<u64>() as usize,
+ DW_EH_PE_sleb128 => reader.read_sleb128() as usize,
+ DW_EH_PE_sdata2 => reader.read::<i16>() as usize,
+ DW_EH_PE_sdata4 => reader.read::<i32>() as usize,
+ DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
+ _ => panic!()
+ };
+
+ result += match encoding & 0x70 {
+ DW_EH_PE_absptr => 0,
+ // relative to address of the encoded value, despite the name
+ DW_EH_PE_pcrel => reader.ptr as usize,
+ DW_EH_PE_textrel => { assert!(context.text_start != 0);
+ context.text_start },
+ DW_EH_PE_datarel => { assert!(context.data_start != 0);
+ context.data_start },
+ DW_EH_PE_funcrel => { assert!(context.func_start != 0);
+ context.func_start },
+ _ => panic!()
+ };
+
+ if encoding & DW_EH_PE_indirect != 0 {
+ result = *(result as *const usize);
+ }
+
+ result
+}
--- /dev/null
+// Copyright 2015 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.
+
+//! Utilities for parsing DWARF-encoded data streams.
+//! See http://www.dwarfstd.org,
+//! DWARF-4 standard, Section 7 - "Data Representation"
+
+// This module is used only by x86_64-pc-windows-gnu for now, but we
+// are compiling it everywhere to avoid regressions.
+#![allow(unused)]
+
+pub mod eh;
+
+use core::mem;
+
+pub struct DwarfReader {
+ pub ptr : *const u8
+}
+
+#[repr(C,packed)]
+struct Unaligned<T>(T);
+
+impl DwarfReader {
+
+ pub fn new(ptr : *const u8) -> DwarfReader {
+ DwarfReader {
+ ptr : ptr
+ }
+ }
+
+ // DWARF streams are packed, so e.g. a u32 would not necessarily be aligned
+ // on a 4-byte boundary. This may cause problems on platforms with strict
+ // alignment requirements. By wrapping data in a "packed" struct, we are
+ // telling the backend to generate "misalignment-safe" code.
+ pub unsafe fn read<T:Copy>(&mut self) -> T {
+ let Unaligned(result) = *(self.ptr as *const Unaligned<T>);
+ self.ptr = self.ptr.offset(mem::size_of::<T>() as isize);
+ result
+ }
+
+ // ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable
+ // Length Data".
+ pub unsafe fn read_uleb128(&mut self) -> u64 {
+ let mut shift : usize = 0;
+ let mut result : u64 = 0;
+ let mut byte : u8;
+ loop {
+ byte = self.read::<u8>();
+ result |= ((byte & 0x7F) as u64) << shift;
+ shift += 7;
+ if byte & 0x80 == 0 {
+ break;
+ }
+ }
+ result
+ }
+
+ pub unsafe fn read_sleb128(&mut self) -> i64 {
+ let mut shift : usize = 0;
+ let mut result : u64 = 0;
+ let mut byte : u8;
+ loop {
+ byte = self.read::<u8>();
+ result |= ((byte & 0x7F) as u64) << shift;
+ shift += 7;
+ if byte & 0x80 == 0 {
+ break;
+ }
+ }
+ // sign-extend
+ if shift < 8 * mem::size_of::<u64>() && (byte & 0x40) != 0 {
+ result |= (!0 as u64) << shift;
+ }
+ result as i64
+ }
+}
+
+#[test]
+fn dwarf_reader() {
+ let encoded: &[u8] = &[1,
+ 2, 3,
+ 4, 5, 6, 7,
+ 0xE5, 0x8E, 0x26,
+ 0x9B, 0xF1, 0x59,
+ 0xFF, 0xFF];
+
+ let mut reader = DwarfReader::new(encoded.as_ptr());
+
+ unsafe {
+ assert!(reader.read::<u8>() == u8::to_be(1u8));
+ assert!(reader.read::<u16>() == u16::to_be(0x0203));
+ assert!(reader.read::<u32>() == u32::to_be(0x04050607));
+
+ assert!(reader.read_uleb128() == 624485);
+ assert!(reader.read_sleb128() == -624485);
+
+ assert!(reader.read::<i8>() == i8::to_be(-1));
+ }
+}
--- /dev/null
+// Copyright 2015 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 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 core::any::Any;
+use alloc::boxed::Box;
+
+use unwind as uw;
+
+#[repr(C)]
+struct Exception {
+ _uwe: uw::_Unwind_Exception,
+ cause: Option<Box<Any + Send>>,
+}
+
+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;
+ return uw::_Unwind_RaiseException(exception_param) as u32;
+
+ extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
+ exception: *mut uw::_Unwind_Exception) {
+ unsafe {
+ let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
+ }
+ }
+}
+
+pub fn payload() -> *mut u8 {
+ 0 as *mut u8
+}
+
+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 _);
+ cause.unwrap()
+}
+
+// Rust's exception class identifier. This is used by personality routines to
+// determine whether the exception was thrown by their own runtime.
+fn rust_exception_class() -> uw::_Unwind_Exception_Class {
+ // M O Z \0 R U S T -- vendor, language
+ 0x4d4f5a_00_52555354
+}
+
+// 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:
+// __gcc_personality_v0.
+//
+// Since C does not support exception catching, __gcc_personality_v0 simply
+// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
+// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
+//
+// This is pretty close to Rust's exception handling approach, except that Rust
+// does have a single "catch-all" handler at the bottom of each thread's stack.
+// So we have two versions of the personality routine:
+// - rust_eh_personality, used by all cleanup landing pads, which never catches,
+// so the behavior of __gcc_personality_v0 is perfectly adequate there, and
+// - rust_eh_personality_catch, used only by rust_try(), which always catches.
+//
+// See also: rustc_trans::trans::intrinsic::trans_gnu_try
+
+#[cfg(all(not(target_arch = "arm"),
+ not(all(windows, target_arch = "x86_64"))))]
+pub mod eabi {
+ use unwind as uw;
+ use libc::c_int;
+
+ extern {
+ fn __gcc_personality_v0(version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code;
+ }
+
+ #[lang = "eh_personality"]
+ #[no_mangle]
+ extern fn rust_eh_personality(
+ version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+ unsafe {
+ __gcc_personality_v0(version, actions, exception_class, ue_header,
+ context)
+ }
+ }
+
+ #[lang = "eh_personality_catch"]
+ #[no_mangle]
+ pub extern fn rust_eh_personality_catch(
+ version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+
+ if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
+ uw::_URC_HANDLER_FOUND // catch!
+ }
+ else { // cleanup phase
+ unsafe {
+ __gcc_personality_v0(version, actions, exception_class, ue_header,
+ context)
+ }
+ }
+ }
+}
+
+// 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"))]
+pub mod eabi {
+ use unwind as uw;
+ use libc::c_int;
+
+ extern {
+ fn __gcc_personality_sj0(version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code;
+ }
+
+ #[lang = "eh_personality"]
+ #[no_mangle]
+ pub extern fn rust_eh_personality(
+ version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+ unsafe {
+ __gcc_personality_sj0(version, actions, exception_class, ue_header,
+ context)
+ }
+ }
+
+ #[lang = "eh_personality_catch"]
+ #[no_mangle]
+ pub extern fn rust_eh_personality_catch(
+ version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+ if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
+ uw::_URC_HANDLER_FOUND // catch!
+ }
+ else { // cleanup phase
+ unsafe {
+ __gcc_personality_sj0(version, actions, exception_class, ue_header,
+ context)
+ }
+ }
+ }
+}
+
+
+// ARM EHABI uses a slightly different personality routine signature,
+// but otherwise works the same.
+#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
+pub mod eabi {
+ use unwind as uw;
+ use libc::c_int;
+
+ extern {
+ fn __gcc_personality_v0(state: uw::_Unwind_State,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code;
+ }
+
+ #[lang = "eh_personality"]
+ #[no_mangle]
+ extern fn rust_eh_personality(
+ state: uw::_Unwind_State,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+ unsafe {
+ __gcc_personality_v0(state, ue_header, context)
+ }
+ }
+
+ #[lang = "eh_personality_catch"]
+ #[no_mangle]
+ pub extern fn rust_eh_personality_catch(
+ state: uw::_Unwind_State,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+ // Backtraces on ARM will call the personality routine with
+ // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
+ // we want to continue unwinding the stack, otherwise all our backtraces
+ // would end at __rust_try.
+ if (state as c_int & uw::_US_ACTION_MASK as c_int)
+ == uw::_US_VIRTUAL_UNWIND_FRAME as c_int
+ && (state as c_int & uw::_US_FORCE_UNWIND as c_int) == 0 { // search phase
+ uw::_URC_HANDLER_FOUND // catch!
+ }
+ else { // cleanup phase
+ unsafe {
+ __gcc_personality_v0(state, ue_header, context)
+ }
+ }
+ }
+}
+
+// See docs in the `unwind` module.
+#[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 {
+ #[link(name = "gcc_eh")]
+ #[cfg(not(cargobuild))]
+ extern {}
+
+ extern {
+ fn __register_frame_info(eh_frame_begin: *const u8, object: *mut u8);
+ fn __deregister_frame_info(eh_frame_begin: *const u8, object: *mut u8);
+ }
+
+ #[no_mangle]
+ pub unsafe extern fn rust_eh_register_frames(eh_frame_begin: *const u8,
+ object: *mut u8) {
+ __register_frame_info(eh_frame_begin, object);
+ }
+
+ #[no_mangle]
+ pub unsafe extern fn rust_eh_unregister_frames(eh_frame_begin: *const u8,
+ object: *mut u8) {
+ __deregister_frame_info(eh_frame_begin, object);
+ }
+}
--- /dev/null
+// 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 (),
+ }))
+}
--- /dev/null
+// Copyright 2015 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.
+
+//! Windows SEH
+//!
+//! On Windows (currently only on MSVC), the default exception handling
+//! mechanism is Structured Exception Handling (SEH). This is quite different
+//! than Dwarf-based exception handling (e.g. what other unix platforms use) in
+//! terms of compiler internals, so LLVM is required to have a good deal of
+//! extra support for SEH.
+//!
+//! In a nutshell, what happens here is:
+//!
+//! 1. The `panic` function calls the standard Windows function `RaiseException`
+//! with a Rust-specific code, triggering the unwinding process.
+//! 2. All landing pads generated by the compiler use the personality function
+//! `__C_specific_handler` on 64-bit and `__except_handler3` on 32-bit,
+//! functions in the CRT, and the unwinding code in Windows will use this
+//! personality function to execute all cleanup code on the stack.
+//! 3. All compiler-generated calls to `invoke` have a landing pad set as a
+//! `cleanuppad` LLVM instruction, which indicates the start of the cleanup
+//! routine. The personality (in step 2, defined in the CRT) is responsible
+//! for running the cleanup routines.
+//! 4. Eventually the "catch" code in the `try` intrinsic (generated by the
+//! compiler) is executed, which will ensure that the exception being caught
+//! is indeed a Rust exception, indicating that control should come back to
+//! Rust. This is done via a `catchswitch` plus a `catchpad` instruction in
+//! LLVM IR terms, finally returning normal control to the program with a
+//! `catchret` instruction. The `try` intrinsic uses a filter function to
+//! detect what kind of exception is being thrown, and this detection is
+//! implemented as the msvc_try_filter language item below.
+//!
+//! Some specific differences from the gcc-based exception handling are:
+//!
+//! * Rust has no custom personality function, it is instead *always*
+//! __C_specific_handler or __except_handler3, so the filtering is done in a
+//! C++-like manner instead of in the personality function itself. Note that
+//! 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>`. 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
+//! that the pointers are passed directly to `RaiseException` which are then
+//! recovered in the filter function to be written to the stack frame of the
+//! `try` intrinsic.
+//!
+//! [win64]: http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx
+//! [llvm]: http://llvm.org/docs/ExceptionHandling.html#background-on-windows-exceptions
+
+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 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`.
+ //
+ // 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
+// it's never actually called by the compiler because __C_specific_handler
+// or _except_handler3 is the personality function that is always used.
+// Hence this is just an aborting stub.
+#[lang = "eh_personality"]
+#[cfg(not(test))]
+fn rust_eh_personality() {
+ unsafe { intrinsics::abort() }
+}
--- /dev/null
+// Copyright 2015 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.
+
+//! Unwinding implementation of top of native Win64 SEH,
+//! however the unwind handler data (aka LSDA) uses GCC-compatible encoding.
+
+#![allow(bad_style)]
+#![allow(private_no_mangle_fns)]
+
+use alloc::boxed::Box;
+
+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,
+// [31:30] = 3 (error), 2 (warning), 1 (info), 0 (success)
+// [29] = 1 (user-defined)
+// [28] = 0 (reserved)
+// we define bits:
+// [24:27] = type
+// [0:23] = magic
+const ETYPE: c::DWORD = 0b1110_u32 << 28;
+const MAGIC: c::DWORD = 0x525354; // "RST"
+
+const RUST_PANIC: c::DWORD = ETYPE | (1 << 24) | MAGIC;
+
+#[repr(C)]
+struct PanicData {
+ data: Box<Any + Send>
+}
+
+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);
+ u32::max_value()
+}
+
+pub fn payload() -> *mut u8 {
+ 0 as *mut u8
+}
+
+pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
+ let panic_ctx = Box::from_raw(ptr as *mut PanicData);
+ return panic_ctx.data;
+}
+
+// SEH doesn't support resuming unwinds after calling a landing pad like
+// libunwind does. For this reason, MSVC compiler outlines landing pads into
+// separate functions that can be called directly from the personality function
+// but are nevertheless able to find and modify stack frame of the "parent"
+// function.
+//
+// Since this cannot be done with libdwarf-style landing pads,
+// rust_eh_personality instead catches RUST_PANICs, runs the landing pad, then
+// reraises the exception.
+//
+// Note that it makes certain assumptions about the exception:
+//
+// 1. That RUST_PANIC is non-continuable, so no lower stack frame may choose to
+// resume execution.
+// 2. That the first parameter of the exception is a pointer to an extra data
+// area (PanicData).
+// Since these assumptions do not generally hold true for foreign exceptions
+// (system faults, C++ exceptions, etc), we make no attempt to invoke our
+// landing pads (and, thus, destructors!) for anything other than RUST_PANICs.
+// This is considered acceptable, because the behavior of throwing exceptions
+// through a C ABI boundary is undefined.
+
+#[lang = "eh_personality_catch"]
+#[cfg(not(test))]
+unsafe extern fn rust_eh_personality_catch(
+ exceptionRecord: *mut c::EXCEPTION_RECORD,
+ establisherFrame: c::LPVOID,
+ contextRecord: *mut c::CONTEXT,
+ dispatcherContext: *mut c::DISPATCHER_CONTEXT
+) -> c::EXCEPTION_DISPOSITION
+{
+ rust_eh_personality(exceptionRecord, establisherFrame,
+ contextRecord, dispatcherContext)
+}
+
+#[lang = "eh_personality"]
+#[cfg(not(test))]
+unsafe extern fn rust_eh_personality(
+ exceptionRecord: *mut c::EXCEPTION_RECORD,
+ establisherFrame: c::LPVOID,
+ contextRecord: *mut c::CONTEXT,
+ dispatcherContext: *mut c::DISPATCHER_CONTEXT
+) -> c::EXCEPTION_DISPOSITION
+{
+ let er = &*exceptionRecord;
+ let dc = &*dispatcherContext;
+
+ if er.ExceptionFlags & c::EXCEPTION_UNWIND == 0 { // we are in the dispatch phase
+ if er.ExceptionCode == RUST_PANIC {
+ if let Some(lpad) = find_landing_pad(dc) {
+ c::RtlUnwindEx(establisherFrame,
+ lpad as c::LPVOID,
+ exceptionRecord,
+ er.ExceptionInformation[0] as c::LPVOID, // pointer to PanicData
+ contextRecord,
+ dc.HistoryTable);
+ }
+ }
+ }
+ c::ExceptionContinueSearch
+}
+
+#[lang = "eh_unwind_resume"]
+#[unwind]
+unsafe extern fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! {
+ let params = [panic_ctx as c::ULONG_PTR];
+ c::RaiseException(RUST_PANIC,
+ c::EXCEPTION_NONCONTINUABLE,
+ params.len() as c::DWORD,
+ ¶ms as *const c::ULONG_PTR);
+ intrinsics::abort();
+}
+
+unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option<usize> {
+ let eh_ctx = eh::EHContext {
+ ip: dc.ControlPc as usize,
+ func_start: dc.ImageBase as usize + (*dc.FunctionEntry).BeginAddress as usize,
+ text_start: dc.ImageBase as usize,
+ data_start: 0
+ };
+ eh::find_landing_pad(dc.HandlerData, &eh_ctx)
+}
--- /dev/null
+// 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);
+}
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;
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
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") }
use syntax::ast;
use session;
-use session::config;
+use session::config::{self, PanicStrategy};
use middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic};
use util::nodemap::FnvHashMap;
}
// 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
}
}).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;
}
}
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);
}
}
//! Validity checking for weak lang items
-use session::config;
+use session::config::{self, PanicStrategy};
use session::Session;
use middle::lang_items;
config::CrateTypeRlib => false,
}
});
- if !needs_check { return }
+ if !needs_check {
+ return
+ }
let mut missing = HashSet::new();
for cnum in sess.cstore.crates() {
}
}
+ // 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)));
}
}
+#[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
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 {
}
}
}
+
+ 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
+ }
}
) }
"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"),
}
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;
/// 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
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
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()),
};
option_env!("CFG_VERSION").unwrap_or("unknown version")
)
}
+
+pub const tag_panic_strategy: usize = 0x114;
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;
}
}
+ 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!
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();
}
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) {
+ 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
+ }
+
// 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);
-
- // 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.
+ // 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);
}
}
}
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);
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;
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())
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};
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 {
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};
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),
+ }
+}
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;
}
}
+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 ];
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);
}
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);
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" }
}
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");
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") {
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");
#![feature(on_unimplemented)]
#![feature(oom)]
#![feature(optin_builtin_traits)]
+#![feature(panic_unwind)]
#![feature(placement_in_syntax)]
#![feature(rand)]
#![feature(raw)]
#![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
extern crate rustc_unicode;
extern crate libc;
+// We always need an unwinder currently for backtraces
+extern crate unwind;
+
#[cfg(stage0)]
extern crate alloc_system;
/// 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.
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
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")]
/// ```
#[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`
/// ```
#[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
// 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;
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,
/// # 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");
/// # 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");
}
/// 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>,
/// 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
}
///
/// 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,
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.
}
}
-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 _,
+ }))
+ }
+ });
+
+ return ret.map(|()| {
+ slot.take().unwrap()
});
- // 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 {
+ 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),
}
}
- 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
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)
}
// 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"]
+++ /dev/null
-// Copyright 2015 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.
-
-//! Parsing of GCC-style Language-Specific Data Area (LSDA)
-//! For details see:
-//! http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
-//! http://mentorembedded.github.io/cxx-abi/exceptions.pdf
-//! http://www.airs.com/blog/archives/460
-//! http://www.airs.com/blog/archives/464
-//!
-//! A reference implementation may be found in the GCC source tree
-//! (<root>/libgcc/unwind-c.c as of this writing)
-
-#![allow(non_upper_case_globals)]
-#![allow(unused)]
-
-use prelude::v1::*;
-use sys_common::dwarf::DwarfReader;
-use core::mem;
-
-pub const DW_EH_PE_omit : u8 = 0xFF;
-pub const DW_EH_PE_absptr : u8 = 0x00;
-
-pub const DW_EH_PE_uleb128 : u8 = 0x01;
-pub const DW_EH_PE_udata2 : u8 = 0x02;
-pub const DW_EH_PE_udata4 : u8 = 0x03;
-pub const DW_EH_PE_udata8 : u8 = 0x04;
-pub const DW_EH_PE_sleb128 : u8 = 0x09;
-pub const DW_EH_PE_sdata2 : u8 = 0x0A;
-pub const DW_EH_PE_sdata4 : u8 = 0x0B;
-pub const DW_EH_PE_sdata8 : u8 = 0x0C;
-
-pub const DW_EH_PE_pcrel : u8 = 0x10;
-pub const DW_EH_PE_textrel : u8 = 0x20;
-pub const DW_EH_PE_datarel : u8 = 0x30;
-pub const DW_EH_PE_funcrel : u8 = 0x40;
-pub const DW_EH_PE_aligned : u8 = 0x50;
-
-pub const DW_EH_PE_indirect : u8 = 0x80;
-
-#[derive(Copy, Clone)]
-pub struct EHContext {
- pub ip: usize, // Current instruction pointer
- pub func_start: usize, // Address of the current function
- pub text_start: usize, // Address of the code section
- pub data_start: usize, // Address of the data section
-}
-
-pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext)
- -> Option<usize> {
- if lsda.is_null() {
- return None;
- }
-
- let func_start = context.func_start;
- let mut reader = DwarfReader::new(lsda);
-
- let start_encoding = reader.read::<u8>();
- // base address for landing pad offsets
- let lpad_base = if start_encoding != DW_EH_PE_omit {
- read_encoded_pointer(&mut reader, context, start_encoding)
- } else {
- func_start
- };
-
- let ttype_encoding = reader.read::<u8>();
- if ttype_encoding != DW_EH_PE_omit {
- // Rust doesn't analyze exception types, so we don't care about the type table
- reader.read_uleb128();
- }
-
- let call_site_encoding = reader.read::<u8>();
- let call_site_table_length = reader.read_uleb128();
- let action_table = reader.ptr.offset(call_site_table_length as isize);
- // Return addresses point 1 byte past the call instruction, which could
- // be in the next IP range.
- let ip = context.ip-1;
-
- while reader.ptr < action_table {
- let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
- let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
- let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
- let cs_action = reader.read_uleb128();
- // Callsite table is sorted by cs_start, so if we've passed the ip, we
- // may stop searching.
- if ip < func_start + cs_start {
- break
- }
- if ip < func_start + cs_start + cs_len {
- if cs_lpad != 0 {
- return Some(lpad_base + cs_lpad);
- } else {
- return None;
- }
- }
- }
- // IP range not found: gcc's C++ personality calls terminate() here,
- // however the rest of the languages treat this the same as cs_lpad == 0.
- // We follow this suit.
- None
-}
-
-#[inline]
-fn round_up(unrounded: usize, align: usize) -> usize {
- assert!(align.is_power_of_two());
- (unrounded + align - 1) & !(align - 1)
-}
-
-unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
- context: &EHContext,
- encoding: u8) -> usize {
- assert!(encoding != DW_EH_PE_omit);
-
- // DW_EH_PE_aligned implies it's an absolute pointer value
- if encoding == DW_EH_PE_aligned {
- reader.ptr = round_up(reader.ptr as usize,
- mem::size_of::<usize>()) as *const u8;
- return reader.read::<usize>();
- }
-
- let mut result = match encoding & 0x0F {
- DW_EH_PE_absptr => reader.read::<usize>(),
- DW_EH_PE_uleb128 => reader.read_uleb128() as usize,
- DW_EH_PE_udata2 => reader.read::<u16>() as usize,
- DW_EH_PE_udata4 => reader.read::<u32>() as usize,
- DW_EH_PE_udata8 => reader.read::<u64>() as usize,
- DW_EH_PE_sleb128 => reader.read_sleb128() as usize,
- DW_EH_PE_sdata2 => reader.read::<i16>() as usize,
- DW_EH_PE_sdata4 => reader.read::<i32>() as usize,
- DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
- _ => panic!()
- };
-
- result += match encoding & 0x70 {
- DW_EH_PE_absptr => 0,
- // relative to address of the encoded value, despite the name
- DW_EH_PE_pcrel => reader.ptr as usize,
- DW_EH_PE_textrel => { assert!(context.text_start != 0);
- context.text_start },
- DW_EH_PE_datarel => { assert!(context.data_start != 0);
- context.data_start },
- DW_EH_PE_funcrel => { assert!(context.func_start != 0);
- context.func_start },
- _ => panic!()
- };
-
- if encoding & DW_EH_PE_indirect != 0 {
- result = *(result as *const usize);
- }
-
- result
-}
+++ /dev/null
-// Copyright 2015 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.
-
-//! Utilities for parsing DWARF-encoded data streams.
-//! See http://www.dwarfstd.org,
-//! DWARF-4 standard, Section 7 - "Data Representation"
-
-// This module is used only by x86_64-pc-windows-gnu for now, but we
-// are compiling it everywhere to avoid regressions.
-#![allow(unused)]
-
-pub mod eh;
-
-use prelude::v1::*;
-use core::mem;
-
-pub struct DwarfReader {
- pub ptr : *const u8
-}
-
-#[repr(C,packed)]
-struct Unaligned<T>(T);
-
-impl DwarfReader {
-
- pub fn new(ptr : *const u8) -> DwarfReader {
- DwarfReader {
- ptr : ptr
- }
- }
-
- // DWARF streams are packed, so e.g. a u32 would not necessarily be aligned
- // on a 4-byte boundary. This may cause problems on platforms with strict
- // alignment requirements. By wrapping data in a "packed" struct, we are
- // telling the backend to generate "misalignment-safe" code.
- pub unsafe fn read<T:Copy>(&mut self) -> T {
- let Unaligned(result) = *(self.ptr as *const Unaligned<T>);
- self.ptr = self.ptr.offset(mem::size_of::<T>() as isize);
- result
- }
-
- // ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable
- // Length Data".
- pub unsafe fn read_uleb128(&mut self) -> u64 {
- let mut shift : usize = 0;
- let mut result : u64 = 0;
- let mut byte : u8;
- loop {
- byte = self.read::<u8>();
- result |= ((byte & 0x7F) as u64) << shift;
- shift += 7;
- if byte & 0x80 == 0 {
- break;
- }
- }
- result
- }
-
- pub unsafe fn read_sleb128(&mut self) -> i64 {
- let mut shift : usize = 0;
- let mut result : u64 = 0;
- let mut byte : u8;
- loop {
- byte = self.read::<u8>();
- result |= ((byte & 0x7F) as u64) << shift;
- shift += 7;
- if byte & 0x80 == 0 {
- break;
- }
- }
- // sign-extend
- if shift < 8 * mem::size_of::<u64>() && (byte & 0x40) != 0 {
- result |= (!0 as u64) << shift;
- }
- result as i64
- }
-}
-
-#[test]
-fn dwarf_reader() {
- let encoded: &[u8] = &[1,
- 2, 3,
- 4, 5, 6, 7,
- 0xE5, 0x8E, 0x26,
- 0x9B, 0xF1, 0x59,
- 0xFF, 0xFF];
-
- let mut reader = DwarfReader::new(encoded.as_ptr());
-
- unsafe {
- assert!(reader.read::<u8>() == u8::to_be(1u8));
- assert!(reader.read::<u16>() == u16::to_be(0x0203));
- assert!(reader.read::<u32>() == u32::to_be(0x04050607));
-
- assert!(reader.read_uleb128() == 624485);
- assert!(reader.read_sleb128() == -624485);
-
- assert!(reader.read::<i8>() == i8::to_be(-1));
- }
-}
+++ /dev/null
-// Copyright 2014-2015 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.
-
-//! Unwind library interface
-
-#![allow(non_upper_case_globals)]
-#![allow(non_camel_case_types)]
-#![allow(non_snake_case)]
-#![allow(dead_code)] // these are just bindings
-
-#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
-pub use self::_Unwind_Action::*;
-#[cfg(target_arch = "arm")]
-pub use self::_Unwind_State::*;
-pub use self::_Unwind_Reason_Code::*;
-
-use libc;
-
-#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub enum _Unwind_Action {
- _UA_SEARCH_PHASE = 1,
- _UA_CLEANUP_PHASE = 2,
- _UA_HANDLER_FRAME = 4,
- _UA_FORCE_UNWIND = 8,
- _UA_END_OF_STACK = 16,
-}
-
-#[cfg(target_arch = "arm")]
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub enum _Unwind_State {
- _US_VIRTUAL_UNWIND_FRAME = 0,
- _US_UNWIND_FRAME_STARTING = 1,
- _US_UNWIND_FRAME_RESUME = 2,
- _US_ACTION_MASK = 3,
- _US_FORCE_UNWIND = 8,
- _US_END_OF_STACK = 16
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub enum _Unwind_Reason_Code {
- _URC_NO_REASON = 0,
- _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
- _URC_FATAL_PHASE2_ERROR = 2,
- _URC_FATAL_PHASE1_ERROR = 3,
- _URC_NORMAL_STOP = 4,
- _URC_END_OF_STACK = 5,
- _URC_HANDLER_FOUND = 6,
- _URC_INSTALL_CONTEXT = 7,
- _URC_CONTINUE_UNWIND = 8,
- _URC_FAILURE = 9, // used only by ARM EABI
-}
-
-pub type _Unwind_Exception_Class = u64;
-
-pub type _Unwind_Word = libc::uintptr_t;
-
-#[cfg(target_arch = "x86")]
-pub const unwinder_private_data_size: usize = 5;
-
-#[cfg(target_arch = "x86_64")]
-pub const unwinder_private_data_size: usize = 6;
-
-#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
-pub const unwinder_private_data_size: usize = 20;
-
-#[cfg(all(target_arch = "arm", target_os = "ios"))]
-pub const unwinder_private_data_size: usize = 5;
-
-#[cfg(target_arch = "aarch64")]
-pub const unwinder_private_data_size: usize = 2;
-
-#[cfg(target_arch = "mips")]
-pub const unwinder_private_data_size: usize = 2;
-
-#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
-pub const unwinder_private_data_size: usize = 2;
-
-#[cfg(target_arch = "asmjs")]
-// FIXME: Copied from arm. Need to confirm.
-pub const unwinder_private_data_size: usize = 20;
-
-#[repr(C)]
-pub struct _Unwind_Exception {
- pub exception_class: _Unwind_Exception_Class,
- pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
- pub private: [_Unwind_Word; unwinder_private_data_size],
-}
-
-pub enum _Unwind_Context {}
-
-pub type _Unwind_Exception_Cleanup_Fn =
- extern "C" fn(unwind_code: _Unwind_Reason_Code,
- exception: *mut _Unwind_Exception);
-
-#[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")),
- target_os = "freebsd",
- target_os = "solaris",
- all(target_os = "linux",
- target_env = "musl",
- not(target_arch = "x86"),
- not(target_arch = "x86_64"))),
- link(name = "gcc_s"))]
-#[cfg_attr(all(target_os = "linux",
- target_env = "musl",
- any(target_arch = "x86", target_arch = "x86_64"),
- not(test)),
- link(name = "unwind", kind = "static"))]
-#[cfg_attr(any(target_os = "android", target_os = "openbsd"),
- link(name = "gcc"))]
-#[cfg_attr(all(target_os = "netbsd", not(target_vendor = "rumprun")),
- link(name = "gcc"))]
-#[cfg_attr(all(target_os = "netbsd", target_vendor = "rumprun"),
- link(name = "unwind"))]
-#[cfg_attr(target_os = "dragonfly",
- link(name = "gcc_pic"))]
-#[cfg_attr(target_os = "bitrig",
- link(name = "c++abi"))]
-#[cfg_attr(all(target_os = "windows", target_env="gnu"),
- link(name = "gcc_eh"))]
-extern "C" {
- // iOS on armv7 uses SjLj exceptions and requires to link
- // against corresponding routine (..._SjLj_...)
- #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
- #[unwind]
- pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception)
- -> _Unwind_Reason_Code;
-
- #[cfg(all(target_os = "ios", target_arch = "arm"))]
- #[unwind]
- fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception)
- -> _Unwind_Reason_Code;
-
- pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
-
- #[unwind]
- pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
-}
-
-// ... 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)]
-pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception)
- -> _Unwind_Reason_Code {
- _Unwind_SjLj_RaiseException(exc)
-}
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;
pub mod thread;
pub mod thread_info;
pub mod thread_local;
-pub mod unwind;
pub mod util;
pub mod wtf8;
+++ /dev/null
-// Copyright 2015 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(private_no_mangle_fns)]
-
-use prelude::v1::*;
-
-use any::Any;
-use sys_common::libunwind as uw;
-
-struct Exception {
- uwe: uw::_Unwind_Exception,
- cause: Option<Box<Any + Send + 'static>>,
-}
-
-pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
- let exception: Box<_> = box 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);
-
- extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
- exception: *mut uw::_Unwind_Exception) {
- unsafe {
- let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
- }
- }
-}
-
-pub fn payload() -> *mut u8 {
- 0 as *mut u8
-}
-
-pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
- let my_ep = ptr as *mut Exception;
- let cause = (*my_ep).cause.take();
- uw::_Unwind_DeleteException(ptr as *mut _);
- cause.unwrap()
-}
-
-// Rust's exception class identifier. This is used by personality routines to
-// determine whether the exception was thrown by their own runtime.
-fn rust_exception_class() -> uw::_Unwind_Exception_Class {
- // M O Z \0 R U S T -- vendor, language
- 0x4d4f5a_00_52555354
-}
-
-// We could implement our personality routine in pure 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:
-// __gcc_personality_v0.
-//
-// Since C does not support exception catching, __gcc_personality_v0 simply
-// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
-// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
-//
-// This is pretty close to Rust's exception handling approach, except that Rust
-// does have a single "catch-all" handler at the bottom of each thread's stack.
-// So we have two versions of the personality routine:
-// - rust_eh_personality, used by all cleanup landing pads, which never catches,
-// so the behavior of __gcc_personality_v0 is perfectly adequate there, and
-// - rust_eh_personality_catch, used only by rust_try(), which always catches.
-//
-// See also: rustc_trans::trans::intrinsic::trans_gnu_try
-
-#[cfg(all(not(target_arch = "arm"),
- not(all(windows, target_arch = "x86_64")),
- not(test)))]
-pub mod eabi {
- use sys_common::libunwind as uw;
- use libc::c_int;
-
- extern {
- fn __gcc_personality_v0(version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code;
- }
-
- #[lang = "eh_personality"]
- #[no_mangle]
- extern fn rust_eh_personality(
- version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
- unsafe {
- __gcc_personality_v0(version, actions, exception_class, ue_header,
- context)
- }
- }
-
- #[lang = "eh_personality_catch"]
- #[no_mangle]
- pub extern fn rust_eh_personality_catch(
- version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
-
- if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
- uw::_URC_HANDLER_FOUND // catch!
- }
- else { // cleanup phase
- unsafe {
- __gcc_personality_v0(version, actions, exception_class, ue_header,
- context)
- }
- }
- }
-}
-
-// 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)))]
-pub mod eabi {
- use sys_common::libunwind as uw;
- use libc::c_int;
-
- extern {
- fn __gcc_personality_sj0(version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code;
- }
-
- #[lang = "eh_personality"]
- #[no_mangle]
- pub extern fn rust_eh_personality(
- version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
- unsafe {
- __gcc_personality_sj0(version, actions, exception_class, ue_header,
- context)
- }
- }
-
- #[lang = "eh_personality_catch"]
- #[no_mangle]
- pub extern fn rust_eh_personality_catch(
- version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
- if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
- uw::_URC_HANDLER_FOUND // catch!
- }
- else { // cleanup phase
- unsafe {
- __gcc_personality_sj0(version, actions, exception_class, ue_header,
- context)
- }
- }
- }
-}
-
-
-// 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)))]
-pub mod eabi {
- use sys_common::libunwind as uw;
- use libc::c_int;
-
- extern {
- fn __gcc_personality_v0(state: uw::_Unwind_State,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code;
- }
-
- #[lang = "eh_personality"]
- #[no_mangle]
- extern fn rust_eh_personality(
- state: uw::_Unwind_State,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
- unsafe {
- __gcc_personality_v0(state, ue_header, context)
- }
- }
-
- #[lang = "eh_personality_catch"]
- #[no_mangle]
- pub extern fn rust_eh_personality_catch(
- state: uw::_Unwind_State,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
- // Backtraces on ARM will call the personality routine with
- // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
- // we want to continue unwinding the stack, otherwise all our backtraces
- // would end at __rust_try.
- if (state as c_int & uw::_US_ACTION_MASK as c_int)
- == uw::_US_VIRTUAL_UNWIND_FRAME as c_int
- && (state as c_int & uw::_US_FORCE_UNWIND as c_int) == 0 { // search phase
- uw::_URC_HANDLER_FOUND // catch!
- }
- else { // cleanup phase
- unsafe {
- __gcc_personality_v0(state, ue_header, context)
- }
- }
- }
-}
-
-// See docs in the `unwind` module.
-#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu", not(test)))]
-#[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);
-}
-
-#[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 {}
-
- extern {
- 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);
- }
-}
+++ /dev/null
-// 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);
-}
+++ /dev/null
-// Copyright 2015 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.
-
-//! Windows SEH
-//!
-//! On Windows (currently only on MSVC), the default exception handling
-//! mechanism is Structured Exception Handling (SEH). This is quite different
-//! than Dwarf-based exception handling (e.g. what other unix platforms use) in
-//! terms of compiler internals, so LLVM is required to have a good deal of
-//! extra support for SEH.
-//!
-//! In a nutshell, what happens here is:
-//!
-//! 1. The `panic` function calls the standard Windows function `RaiseException`
-//! with a Rust-specific code, triggering the unwinding process.
-//! 2. All landing pads generated by the compiler use the personality function
-//! `__C_specific_handler` on 64-bit and `__except_handler3` on 32-bit,
-//! functions in the CRT, and the unwinding code in Windows will use this
-//! personality function to execute all cleanup code on the stack.
-//! 3. All compiler-generated calls to `invoke` have a landing pad set as a
-//! `cleanuppad` LLVM instruction, which indicates the start of the cleanup
-//! routine. The personality (in step 2, defined in the CRT) is responsible
-//! for running the cleanup routines.
-//! 4. Eventually the "catch" code in the `try` intrinsic (generated by the
-//! compiler) is executed, which will ensure that the exception being caught
-//! is indeed a Rust exception, indicating that control should come back to
-//! Rust. This is done via a `catchswitch` plus a `catchpad` instruction in
-//! LLVM IR terms, finally returning normal control to the program with a
-//! `catchret` instruction. The `try` intrinsic uses a filter function to
-//! detect what kind of exception is being thrown, and this detection is
-//! implemented as the msvc_try_filter language item below.
-//!
-//! Some specific differences from the gcc-based exception handling are:
-//!
-//! * Rust has no custom personality function, it is instead *always*
-//! __C_specific_handler or __except_handler3, so the filtering is done in a
-//! C++-like manner instead of in the personality function itself. Note that
-//! 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
-//! 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
-//! that the pointers are passed directly to `RaiseException` which are then
-//! recovered in the filter function to be written to the stack frame of the
-//! `try` intrinsic.
-//!
-//! [win64]: http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx
-//! [llvm]: http://llvm.org/docs/ExceptionHandling.html#background-on-windows-exceptions
-
-use sys::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:
- //
- // * 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
-// it's never actually called by the compiler because __C_specific_handler
-// or _except_handler3 is the personality function that is always used.
-// Hence this is just an aborting stub.
-#[lang = "eh_personality"]
-#[cfg(not(test))]
-fn rust_eh_personality() {
- unsafe { ::intrinsics::abort() }
-}
+++ /dev/null
-// Copyright 2015 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.
-
-//! Unwinding implementation of top of native Win64 SEH,
-//! however the unwind handler data (aka LSDA) uses GCC-compatible encoding.
-
-#![allow(bad_style)]
-#![allow(private_no_mangle_fns)]
-
-use prelude::v1::*;
-
-use any::Any;
-use sys_common::dwarf::eh;
-use core::mem;
-use core::ptr;
-use sys::c;
-
-// Define our exception codes:
-// according to http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx,
-// [31:30] = 3 (error), 2 (warning), 1 (info), 0 (success)
-// [29] = 1 (user-defined)
-// [28] = 0 (reserved)
-// we define bits:
-// [24:27] = type
-// [0:23] = magic
-const ETYPE: c::DWORD = 0b1110_u32 << 28;
-const MAGIC: c::DWORD = 0x525354; // "RST"
-
-const RUST_PANIC: c::DWORD = ETYPE | (1 << 24) | MAGIC;
-
-#[repr(C)]
-struct PanicData {
- data: Box<Any + Send + 'static>
-}
-
-pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
- 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");
-}
-
-pub fn payload() -> *mut u8 {
- 0 as *mut u8
-}
-
-pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
- let panic_ctx = Box::from_raw(ptr as *mut PanicData);
- return panic_ctx.data;
-}
-
-// SEH doesn't support resuming unwinds after calling a landing pad like
-// libunwind does. For this reason, MSVC compiler outlines landing pads into
-// separate functions that can be called directly from the personality function
-// but are nevertheless able to find and modify stack frame of the "parent"
-// function.
-//
-// Since this cannot be done with libdwarf-style landing pads,
-// rust_eh_personality instead catches RUST_PANICs, runs the landing pad, then
-// reraises the exception.
-//
-// Note that it makes certain assumptions about the exception:
-//
-// 1. That RUST_PANIC is non-continuable, so no lower stack frame may choose to
-// resume execution.
-// 2. That the first parameter of the exception is a pointer to an extra data
-// area (PanicData).
-// Since these assumptions do not generally hold true for foreign exceptions
-// (system faults, C++ exceptions, etc), we make no attempt to invoke our
-// landing pads (and, thus, destructors!) for anything other than RUST_PANICs.
-// This is considered acceptable, because the behavior of throwing exceptions
-// through a C ABI boundary is undefined.
-
-#[lang = "eh_personality_catch"]
-#[cfg(not(test))]
-unsafe extern fn rust_eh_personality_catch(
- exceptionRecord: *mut c::EXCEPTION_RECORD,
- establisherFrame: c::LPVOID,
- contextRecord: *mut c::CONTEXT,
- dispatcherContext: *mut c::DISPATCHER_CONTEXT
-) -> c::EXCEPTION_DISPOSITION
-{
- rust_eh_personality(exceptionRecord, establisherFrame,
- contextRecord, dispatcherContext)
-}
-
-#[lang = "eh_personality"]
-#[cfg(not(test))]
-unsafe extern fn rust_eh_personality(
- exceptionRecord: *mut c::EXCEPTION_RECORD,
- establisherFrame: c::LPVOID,
- contextRecord: *mut c::CONTEXT,
- dispatcherContext: *mut c::DISPATCHER_CONTEXT
-) -> c::EXCEPTION_DISPOSITION
-{
- let er = &*exceptionRecord;
- let dc = &*dispatcherContext;
-
- if er.ExceptionFlags & c::EXCEPTION_UNWIND == 0 { // we are in the dispatch phase
- if er.ExceptionCode == RUST_PANIC {
- if let Some(lpad) = find_landing_pad(dc) {
- c::RtlUnwindEx(establisherFrame,
- lpad as c::LPVOID,
- exceptionRecord,
- 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) -> ! {
- let params = [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 resume unwind");
-}
-
-unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option<usize> {
- let eh_ctx = eh::EHContext {
- ip: dc.ControlPc as usize,
- func_start: dc.ImageBase as usize + (*dc.FunctionEntry).BeginAddress as usize,
- text_start: dc.ImageBase as usize,
- data_start: 0
- };
- eh::find_landing_pad(dc.HandlerData, &eh_ctx)
-}
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
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
- }
-}
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;
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
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,
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;
}
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);
}
};
#[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.
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))
(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)),
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 \
#![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::*;
--- /dev/null
+[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" }
--- /dev/null
+// 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");
+ }
+}
--- /dev/null
+// 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::*;
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(bad_style)]
+
+use libc;
+
+#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
+pub use self::_Unwind_Action::*;
+#[cfg(target_arch = "arm")]
+pub use self::_Unwind_State::*;
+pub use self::_Unwind_Reason_Code::*;
+
+#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub enum _Unwind_Action {
+ _UA_SEARCH_PHASE = 1,
+ _UA_CLEANUP_PHASE = 2,
+ _UA_HANDLER_FRAME = 4,
+ _UA_FORCE_UNWIND = 8,
+ _UA_END_OF_STACK = 16,
+}
+
+#[cfg(target_arch = "arm")]
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub enum _Unwind_State {
+ _US_VIRTUAL_UNWIND_FRAME = 0,
+ _US_UNWIND_FRAME_STARTING = 1,
+ _US_UNWIND_FRAME_RESUME = 2,
+ _US_ACTION_MASK = 3,
+ _US_FORCE_UNWIND = 8,
+ _US_END_OF_STACK = 16
+}
+
+#[repr(C)]
+pub enum _Unwind_Reason_Code {
+ _URC_NO_REASON = 0,
+ _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+ _URC_FATAL_PHASE2_ERROR = 2,
+ _URC_FATAL_PHASE1_ERROR = 3,
+ _URC_NORMAL_STOP = 4,
+ _URC_END_OF_STACK = 5,
+ _URC_HANDLER_FOUND = 6,
+ _URC_INSTALL_CONTEXT = 7,
+ _URC_CONTINUE_UNWIND = 8,
+ _URC_FAILURE = 9, // used only by ARM EABI
+}
+
+pub type _Unwind_Exception_Class = u64;
+
+pub type _Unwind_Word = libc::uintptr_t;
+
+pub type _Unwind_Trace_Fn =
+ extern fn(ctx: *mut _Unwind_Context,
+ arg: *mut libc::c_void) -> _Unwind_Reason_Code;
+
+#[cfg(target_arch = "x86")]
+pub const unwinder_private_data_size: usize = 5;
+
+#[cfg(target_arch = "x86_64")]
+pub const unwinder_private_data_size: usize = 6;
+
+#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
+pub const unwinder_private_data_size: usize = 20;
+
+#[cfg(all(target_arch = "arm", target_os = "ios"))]
+pub const unwinder_private_data_size: usize = 5;
+
+#[cfg(target_arch = "aarch64")]
+pub const unwinder_private_data_size: usize = 2;
+
+#[cfg(target_arch = "mips")]
+pub const unwinder_private_data_size: usize = 2;
+
+#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
+pub const unwinder_private_data_size: usize = 2;
+
+#[cfg(target_arch = "asmjs")]
+// FIXME: Copied from arm. Need to confirm.
+pub const unwinder_private_data_size: usize = 20;
+
+#[repr(C)]
+pub struct _Unwind_Exception {
+ pub exception_class: _Unwind_Exception_Class,
+ pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
+ pub private: [_Unwind_Word; unwinder_private_data_size],
+}
+
+pub enum _Unwind_Context {}
+
+pub type _Unwind_Exception_Cleanup_Fn =
+ extern "C" fn(unwind_code: _Unwind_Reason_Code,
+ exception: *mut _Unwind_Exception);
+
+#[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")),
+ target_os = "freebsd",
+ target_os = "solaris",
+ all(target_os = "linux",
+ target_env = "musl",
+ not(target_arch = "x86"),
+ not(target_arch = "x86_64"))),
+ link(name = "gcc_s"))]
+#[cfg_attr(all(target_os = "linux",
+ target_env = "musl",
+ any(target_arch = "x86", target_arch = "x86_64"),
+ not(test)),
+ link(name = "unwind", kind = "static"))]
+#[cfg_attr(any(target_os = "android", target_os = "openbsd"),
+ link(name = "gcc"))]
+#[cfg_attr(all(target_os = "netbsd", not(target_vendor = "rumprun")),
+ link(name = "gcc"))]
+#[cfg_attr(all(target_os = "netbsd", target_vendor = "rumprun"),
+ link(name = "unwind"))]
+#[cfg_attr(target_os = "dragonfly",
+ link(name = "gcc_pic"))]
+#[cfg_attr(target_os = "bitrig",
+ link(name = "c++abi"))]
+#[cfg_attr(all(target_os = "windows", target_env = "gnu"),
+ link(name = "gcc_eh"))]
+#[cfg(not(cargobuild))]
+extern {}
+
+extern {
+ // iOS on armv7 uses SjLj exceptions and requires to link
+ // against corresponding routine (..._SjLj_...)
+ #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
+ #[unwind]
+ pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception)
+ -> _Unwind_Reason_Code;
+
+ #[cfg(all(target_os = "ios", target_arch = "arm"))]
+ #[unwind]
+ fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception)
+ -> _Unwind_Reason_Code;
+
+ pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
+
+ #[unwind]
+ pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
+
+ // No native _Unwind_Backtrace on iOS
+ #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
+ pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
+ trace_argument: *mut libc::c_void)
+ -> _Unwind_Reason_Code;
+
+ // available since GCC 4.2.0, should be fine for our purpose
+ #[cfg(all(not(all(target_os = "android", target_arch = "arm")),
+ not(all(target_os = "linux", target_arch = "arm"))))]
+ pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
+ ip_before_insn: *mut libc::c_int)
+ -> libc::uintptr_t;
+
+ #[cfg(all(not(target_os = "android"),
+ not(all(target_os = "linux", target_arch = "arm"))))]
+ pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void)
+ -> *mut libc::c_void;
+}
+
+// ... and now we just providing access to SjLj counterspart
+// through a standard name to hide those details from others
+// (see also comment above regarding _Unwind_RaiseException)
+#[cfg(all(target_os = "ios", target_arch = "arm"))]
+#[inline]
+pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception)
+ -> _Unwind_Reason_Code {
+ _Unwind_SjLj_RaiseException(exc)
+}
+
+// On android, the function _Unwind_GetIP is a macro, and this is the
+// expansion of the macro. This is all copy/pasted directly from the
+// header file with the definition of _Unwind_GetIP.
+#[cfg(any(all(target_os = "android", target_arch = "arm"),
+ all(target_os = "linux", target_arch = "arm")))]
+pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
+ #[repr(C)]
+ enum _Unwind_VRS_Result {
+ _UVRSR_OK = 0,
+ _UVRSR_NOT_IMPLEMENTED = 1,
+ _UVRSR_FAILED = 2,
+ }
+ #[repr(C)]
+ enum _Unwind_VRS_RegClass {
+ _UVRSC_CORE = 0,
+ _UVRSC_VFP = 1,
+ _UVRSC_FPA = 2,
+ _UVRSC_WMMXD = 3,
+ _UVRSC_WMMXC = 4,
+ }
+ #[repr(C)]
+ enum _Unwind_VRS_DataRepresentation {
+ _UVRSD_UINT32 = 0,
+ _UVRSD_VFPX = 1,
+ _UVRSD_FPAX = 2,
+ _UVRSD_UINT64 = 3,
+ _UVRSD_FLOAT = 4,
+ _UVRSD_DOUBLE = 5,
+ }
+
+ type _Unwind_Word = libc::c_uint;
+ extern {
+ fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
+ klass: _Unwind_VRS_RegClass,
+ word: _Unwind_Word,
+ repr: _Unwind_VRS_DataRepresentation,
+ data: *mut libc::c_void)
+ -> _Unwind_VRS_Result;
+ }
+
+ let mut val: _Unwind_Word = 0;
+ let ptr = &mut val as *mut _Unwind_Word;
+ let _ = _Unwind_VRS_Get(ctx, _Unwind_VRS_RegClass::_UVRSC_CORE, 15,
+ _Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
+ ptr as *mut libc::c_void);
+ (val & !1) as libc::uintptr_t
+}
+
+// This function doesn't exist on Android or ARM/Linux, so make it same
+// to _Unwind_GetIP
+#[cfg(any(all(target_os = "android", target_arch = "arm"),
+ all(target_os = "linux", target_arch = "arm")))]
+pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
+ ip_before_insn: *mut libc::c_int)
+ -> libc::uintptr_t
+{
+ *ip_before_insn = 0;
+ _Unwind_GetIP(ctx)
+}
+
+// This function also doesn't exist on Android or ARM/Linux, so make it
+// a no-op
+#[cfg(any(target_os = "android",
+ all(target_os = "linux", target_arch = "arm")))]
+pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void)
+ -> *mut libc::c_void
+{
+ pc
+}
"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"
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",
]
[[package]]
name = "gcc"
-version = "0.3.17"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "libc"
+version = "0.0.0"
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)",
+ "core 0.0.0",
]
[[package]]
-name = "libc"
+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]]
"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",
+]
--- /dev/null
+// 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!");
+}
--- /dev/null
+// 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() {
+}
--- /dev/null
+// 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]
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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;
--- /dev/null
+// 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;
--- /dev/null
+// 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;
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {
+}
+
--- /dev/null
+// 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() {}
--- /dev/null
+// 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;
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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");
+}
--- /dev/null
+// 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));
+}
--- /dev/null
+// 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();
+}
--- /dev/null
+// 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() {
+}
--- /dev/null
+// 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() {
+}
--- /dev/null
+// 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));
+}
--- /dev/null
+// 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"));
+}
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 \