From f4be2026dfb507e5db919cc5df8fd934e05fa0b8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 8 Sep 2015 15:53:46 -0700 Subject: std: Internalize almost all of `std::rt` This commit does some refactoring to make almost all of the `std::rt` private. Specifically, the following items are no longer part of its API: * DEFAULT_ERROR_CODE * backtrace * unwind * args * at_exit * cleanup * heap (this is just alloc::heap) * min_stack * util The module is now tagged as `#[doc(hidden)]` as the only purpose it's serve is an entry point for the `panic!` macro via the `begin_unwind` and `begin_unwind_fmt` reexports. --- src/libstd/rt/args.rs | 160 ------------------- src/libstd/rt/at_exit_imp.rs | 82 ---------- src/libstd/rt/backtrace.rs | 76 --------- src/libstd/rt/dwarf/eh.rs | 159 ------------------- src/libstd/rt/dwarf/mod.rs | 107 ------------- src/libstd/rt/libunwind.rs | 145 ----------------- src/libstd/rt/macros.rs | 51 ------ src/libstd/rt/mod.rs | 135 ---------------- src/libstd/rt/unwind/gcc.rs | 235 --------------------------- src/libstd/rt/unwind/mod.rs | 325 -------------------------------------- src/libstd/rt/unwind/seh.rs | 145 ----------------- src/libstd/rt/unwind/seh64_gnu.rs | 226 -------------------------- src/libstd/rt/util.rs | 53 ------- 13 files changed, 1899 deletions(-) delete mode 100644 src/libstd/rt/args.rs delete mode 100644 src/libstd/rt/at_exit_imp.rs delete mode 100644 src/libstd/rt/backtrace.rs delete mode 100644 src/libstd/rt/dwarf/eh.rs delete mode 100644 src/libstd/rt/dwarf/mod.rs delete mode 100644 src/libstd/rt/libunwind.rs delete mode 100644 src/libstd/rt/macros.rs delete mode 100644 src/libstd/rt/mod.rs delete mode 100644 src/libstd/rt/unwind/gcc.rs delete mode 100644 src/libstd/rt/unwind/mod.rs delete mode 100644 src/libstd/rt/unwind/seh.rs delete mode 100644 src/libstd/rt/unwind/seh64_gnu.rs delete mode 100644 src/libstd/rt/util.rs (limited to 'src/libstd/rt') diff --git a/src/libstd/rt/args.rs b/src/libstd/rt/args.rs deleted file mode 100644 index 8de713aeac8..00000000000 --- a/src/libstd/rt/args.rs +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2012-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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Global storage for command line arguments -//! -//! The current incarnation of the Rust runtime expects for -//! the processes `argc` and `argv` arguments to be stored -//! in a globally-accessible location for use by the `os` module. -//! -//! Only valid to call on Linux. Mac and Windows use syscalls to -//! discover the command line arguments. -//! -//! FIXME #7756: Would be nice for this to not exist. - -use vec::Vec; - -/// One-time global initialization. -pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) } - -/// One-time global cleanup. -pub unsafe fn cleanup() { imp::cleanup() } - -/// Take the global arguments from global storage. -pub fn take() -> Option>> { imp::take() } - -/// Give the global arguments to global storage. -/// -/// It is an error if the arguments already exist. -pub fn put(args: Vec>) { imp::put(args) } - -/// Make a clone of the global arguments. -pub fn clone() -> Option>> { imp::clone() } - -#[cfg(any(target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "netbsd", - target_os = "openbsd"))] -mod imp { - use prelude::v1::*; - - use libc; - use mem; - use ffi::CStr; - - use sync::StaticMutex; - - static mut GLOBAL_ARGS_PTR: usize = 0; - static LOCK: StaticMutex = StaticMutex::new(); - - pub unsafe fn init(argc: isize, argv: *const *const u8) { - let args = load_argc_and_argv(argc, argv); - put(args); - } - - pub unsafe fn cleanup() { - take(); - } - - pub fn take() -> Option>> { - let _guard = LOCK.lock(); - unsafe { - let ptr = get_global_ptr(); - let val = mem::replace(&mut *ptr, None); - val.as_ref().map(|s: &Box>>| (**s).clone()) - } - } - - pub fn put(args: Vec>) { - let _guard = LOCK.lock(); - unsafe { - let ptr = get_global_ptr(); - rtassert!((*ptr).is_none()); - (*ptr) = Some(box args.clone()); - } - } - - pub fn clone() -> Option>> { - let _guard = LOCK.lock(); - unsafe { - let ptr = get_global_ptr(); - (*ptr).as_ref().map(|s: &Box>>| (**s).clone()) - } - } - - fn get_global_ptr() -> *mut Option>>> { - unsafe { mem::transmute(&GLOBAL_ARGS_PTR) } - } - - unsafe fn load_argc_and_argv(argc: isize, - argv: *const *const u8) -> Vec> { - let argv = argv as *const *const libc::c_char; - (0..argc).map(|i| { - CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec() - }).collect() - } - - #[cfg(test)] - mod tests { - use prelude::v1::*; - - use super::*; - - #[test] - fn smoke_test() { - // Preserve the actual global state. - let saved_value = take(); - - let expected = vec![ - b"happy".to_vec(), - b"today?".to_vec(), - ]; - - put(expected.clone()); - assert!(clone() == Some(expected.clone())); - assert!(take() == Some(expected.clone())); - assert!(take() == None); - - // Restore the actual global state. - match saved_value { - Some(ref args) => put(args.clone()), - None => () - } - } - } -} - -#[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "windows"))] -mod imp { - use vec::Vec; - - pub unsafe fn init(_argc: isize, _argv: *const *const u8) { - } - - pub fn cleanup() { - } - - pub fn take() -> Option>> { - panic!() - } - - pub fn put(_args: Vec>) { - panic!() - } - - pub fn clone() -> Option>> { - panic!() - } -} diff --git a/src/libstd/rt/at_exit_imp.rs b/src/libstd/rt/at_exit_imp.rs deleted file mode 100644 index 7a1215bf382..00000000000 --- a/src/libstd/rt/at_exit_imp.rs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation of running at_exit routines -//! -//! Documentation can be found on the `rt::at_exit` function. - -use alloc::boxed::FnBox; -use boxed::Box; -use ptr; -use sys_common::mutex::Mutex; -use vec::Vec; - -type Queue = Vec>; - -// NB these are specifically not types from `std::sync` as they currently rely -// on poisoning and this module needs to operate at a lower level than requiring -// the thread infrastructure to be in place (useful on the borders of -// initialization/destruction). -static LOCK: Mutex = Mutex::new(); -static mut QUEUE: *mut Queue = ptr::null_mut(); - -// The maximum number of times the cleanup routines will be run. While running -// the at_exit closures new ones may be registered, and this count is the number -// of times the new closures will be allowed to register successfully. After -// this number of iterations all new registrations will return `false`. -const ITERS: usize = 10; - -unsafe fn init() -> bool { - if QUEUE.is_null() { - let state: Box = box Vec::new(); - QUEUE = Box::into_raw(state); - } else if QUEUE as usize == 1 { - // can't re-init after a cleanup - return false - } - - true -} - -pub fn cleanup() { - for i in 0..ITERS { - unsafe { - LOCK.lock(); - let queue = QUEUE; - QUEUE = if i == ITERS - 1 {1} else {0} as *mut _; - LOCK.unlock(); - - // make sure we're not recursively cleaning up - rtassert!(queue as usize != 1); - - // If we never called init, not need to cleanup! - if queue as usize != 0 { - let queue: Box = Box::from_raw(queue); - for to_run in *queue { - to_run(); - } - } - } - } -} - -pub fn push(f: Box) -> bool { - let mut ret = true; - unsafe { - LOCK.lock(); - if init() { - (*QUEUE).push(f); - } else { - ret = false; - } - LOCK.unlock(); - } - ret -} diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs deleted file mode 100644 index 9e7ed89bae1..00000000000 --- a/src/libstd/rt/backtrace.rs +++ /dev/null @@ -1,76 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Simple backtrace functionality (to print on panic) - -#![allow(non_camel_case_types)] - -use env; -use sync::atomic::{self, Ordering}; - -pub use sys::backtrace::write; - -// For now logging is turned off by default, and this function checks to see -// whether the magical environment variable is present to see if it's turned on. -pub fn log_enabled() -> bool { - static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0); - match ENABLED.load(Ordering::SeqCst) { - 1 => return false, - 2 => return true, - _ => {} - } - - let val = match env::var_os("RUST_BACKTRACE") { - Some(..) => 2, - None => 1, - }; - ENABLED.store(val, Ordering::SeqCst); - val == 2 -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - use sys_common; - macro_rules! t { ($a:expr, $b:expr) => ({ - let mut m = Vec::new(); - sys_common::backtrace::demangle(&mut m, $a).unwrap(); - assert_eq!(String::from_utf8(m).unwrap(), $b); - }) } - - #[test] - fn demangle() { - t!("test", "test"); - t!("_ZN4testE", "test"); - t!("_ZN4test", "_ZN4test"); - t!("_ZN4test1a2bcE", "test::a::bc"); - } - - #[test] - fn demangle_dollars() { - t!("_ZN4$RP$E", ")"); - t!("_ZN8$RF$testE", "&test"); - t!("_ZN8$BP$test4foobE", "*test::foob"); - t!("_ZN9$u20$test4foobE", " test::foob"); - } - - #[test] - fn demangle_many_dollars() { - t!("_ZN13test$u20$test4foobE", "test test::foob"); - t!("_ZN12test$BP$test4foobE", "test*test::foob"); - } - - #[test] - fn demangle_windows() { - t!("ZN4testE", "test"); - t!("ZN13test$u20$test4foobE", "test test::foob"); - t!("ZN12test$RF$test4foobE", "test&test::foob"); - } -} diff --git a/src/libstd/rt/dwarf/eh.rs b/src/libstd/rt/dwarf/eh.rs deleted file mode 100644 index f4799703d99..00000000000 --- a/src/libstd/rt/dwarf/eh.rs +++ /dev/null @@ -1,159 +0,0 @@ -// 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 or the MIT license -// , 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 -//! (/libgcc/unwind-c.c as of this writing) - -#![allow(non_upper_case_globals)] -#![allow(unused)] - -use prelude::v1::*; -use rt::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 { - if lsda.is_null() { - return None; - } - - let func_start = context.func_start; - let mut reader = DwarfReader::new(lsda); - - let start_encoding = reader.read::(); - // 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::(); - 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::(); - 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::()) as *const u8; - return reader.read::(); - } - - let mut result = match encoding & 0x0F { - DW_EH_PE_absptr => reader.read::(), - DW_EH_PE_uleb128 => reader.read_uleb128() as usize, - DW_EH_PE_udata2 => reader.read::() as usize, - DW_EH_PE_udata4 => reader.read::() as usize, - DW_EH_PE_udata8 => reader.read::() as usize, - DW_EH_PE_sleb128 => reader.read_sleb128() as usize, - DW_EH_PE_sdata2 => reader.read::() as usize, - DW_EH_PE_sdata4 => reader.read::() as usize, - DW_EH_PE_sdata8 => reader.read::() 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 -} diff --git a/src/libstd/rt/dwarf/mod.rs b/src/libstd/rt/dwarf/mod.rs deleted file mode 100644 index 822826bcc83..00000000000 --- a/src/libstd/rt/dwarf/mod.rs +++ /dev/null @@ -1,107 +0,0 @@ -// 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 or the MIT license -// , 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); - -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(&mut self) -> T { - let Unaligned(result) = *(self.ptr as *const Unaligned); - self.ptr = self.ptr.offset(mem::size_of::() 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::(); - 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::(); - result |= ((byte & 0x7F) as u64) << shift; - shift += 7; - if byte & 0x80 == 0 { - break; - } - } - // sign-extend - if shift < 8 * mem::size_of::() && (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::to_be(1u8)); - assert!(reader.read::() == u16::to_be(0x0203)); - assert!(reader.read::() == u32::to_be(0x04050607)); - - assert!(reader.read_uleb128() == 624485); - assert!(reader.read_sleb128() == -624485); - - assert!(reader.read::() == i8::to_be(-1)); - } -} diff --git a/src/libstd/rt/libunwind.rs b/src/libstd/rt/libunwind.rs deleted file mode 100644 index fde612014e9..00000000000 --- a/src/libstd/rt/libunwind.rs +++ /dev/null @@ -1,145 +0,0 @@ -// 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 or the MIT license -// , 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(any(target_arch = "mips", target_arch = "mipsel"))] -pub const unwinder_private_data_size: usize = 2; - -#[cfg(target_arch = "powerpc")] -pub const unwinder_private_data_size: usize = 2; - -#[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(any(all(target_os = "linux", not(target_env = "musl")), - target_os = "freebsd"))] -#[link(name = "gcc_s")] -extern {} - -#[cfg(all(target_os = "linux", target_env = "musl", not(test)))] -#[link(name = "unwind", kind = "static")] -extern {} - -#[cfg(any(target_os = "android", target_os = "netbsd", target_os = "openbsd"))] -#[link(name = "gcc")] -extern {} - -#[cfg(target_os = "dragonfly")] -#[link(name = "gcc_pic")] -extern {} - -#[cfg(target_os = "bitrig")] -#[link(name = "c++abi")] -extern {} - -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")))] - pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) - -> _Unwind_Reason_Code; - - #[cfg(all(target_os = "ios", target_arch = "arm"))] - fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) - -> _Unwind_Reason_Code; - - pub fn _Unwind_DeleteException(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) -} diff --git a/src/libstd/rt/macros.rs b/src/libstd/rt/macros.rs deleted file mode 100644 index 414ccc911af..00000000000 --- a/src/libstd/rt/macros.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Macros used by the runtime. -//! -//! These macros call functions which are only accessible in the `rt` module, so -//! they aren't defined anywhere outside of the `rt` module. - -macro_rules! rterrln { - ($fmt:expr) => ( { - ::rt::util::dumb_print(format_args!(concat!($fmt, "\n"))) - } ); - ($fmt:expr, $($arg:expr),*) => ( { - ::rt::util::dumb_print(format_args!(concat!($fmt, "\n"), $($arg),*)) - } ) -} - -// Some basic logging. Enabled by passing `--cfg rtdebug` to the libstd build. -macro_rules! rtdebug { - ($arg:expr) => ( { - if cfg!(rtdebug) { - rterrln!($arg) - } - } ); - ($str:expr, $($arg:expr),*) => ( { - if cfg!(rtdebug) { - rterrln!($str, $($arg),*) - } - }) -} - -macro_rules! rtassert { - ( $arg:expr ) => ( { - if ::rt::util::ENFORCE_SANITY { - if !$arg { - rtabort!(" assertion failed: {}", stringify!($arg)); - } - } - } ) -} - -macro_rules! rtabort { - ($($arg:tt)*) => (::rt::util::abort(format_args!($($arg)*))) -} diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs deleted file mode 100644 index 95cba132201..00000000000 --- a/src/libstd/rt/mod.rs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Runtime services -//! -//! The `rt` module provides a narrow set of runtime services, -//! including the global heap (exported in `heap`) and unwinding and -//! backtrace support. The APIs in this module are highly unstable, -//! and should be considered as private implementation details for the -//! time being. - -#![unstable(feature = "rt", - reason = "this public module should not exist and is highly likely \ - to disappear", - issue = "0")] -#![allow(missing_docs)] - -use prelude::v1::*; -use sync::Once; -use sys; -use thread; - -// Reexport some of our utilities which are expected by other crates. -pub use self::util::min_stack; -pub use self::unwind::{begin_unwind, begin_unwind_fmt}; - -// Reexport some functionality from liballoc. -pub use alloc::heap; - -// Simple backtrace functionality (to print on panic) -pub mod backtrace; - -// Internals -#[macro_use] -mod macros; - -// These should be refactored/moved/made private over time -pub mod util; -pub mod unwind; -pub mod args; - -mod at_exit_imp; -mod libunwind; - -mod dwarf; - -/// The default error code of the rust runtime if the main thread panics instead -/// of exiting cleanly. -pub const DEFAULT_ERROR_CODE: isize = 101; - -#[cfg(not(test))] -#[lang = "start"] -fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { - use prelude::v1::*; - - use mem; - use rt; - use sys_common::thread_info::{self, NewThread}; - use thread::Thread; - - let failed = unsafe { - let main_guard = sys::thread::guard::init(); - sys::stack_overflow::init(); - - // Next, set up the current Thread with the guard information we just - // created. Note that this isn't necessary in general for new threads, - // but we just do this to name the main thread and to give it correct - // info about the stack bounds. - let thread: Thread = NewThread::new(Some("
".to_owned())); - thread_info::set(main_guard, thread); - - // By default, some platforms will send a *signal* when a EPIPE error - // would otherwise be delivered. This runtime doesn't install a SIGPIPE - // handler, causing it to kill the program, which isn't exactly what we - // want! - // - // Hence, we set SIGPIPE to ignore when the program starts up in order - // to prevent this problem. - #[cfg(windows)] fn ignore_sigpipe() {} - #[cfg(unix)] fn ignore_sigpipe() { - use libc; - use libc::funcs::posix01::signal::signal; - unsafe { - assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0); - } - } - ignore_sigpipe(); - - // Store our args if necessary in a squirreled away location - args::init(argc, argv); - - // And finally, let's run some code! - let res = thread::catch_panic(mem::transmute::<_, fn()>(main)); - cleanup(); - res.is_err() - }; - - // If the exit code wasn't set, then the try block must have panicked. - if failed { - rt::DEFAULT_ERROR_CODE - } else { - 0 - } -} - -/// Enqueues a procedure to run when the main thread exits. -/// -/// Currently these closures are only run once the main *Rust* thread exits. -/// Once the `at_exit` handlers begin running, more may be enqueued, but not -/// infinitely so. Eventually a handler registration will be forced to fail. -/// -/// Returns `Ok` if the handler was successfully registered, meaning that the -/// closure will be run once the main thread exits. Returns `Err` to indicate -/// that the closure could not be registered, meaning that it is not scheduled -/// to be run. -pub fn at_exit(f: F) -> Result<(), ()> { - if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())} -} - -/// One-time runtime cleanup. -pub fn cleanup() { - static CLEANUP: Once = Once::new(); - CLEANUP.call_once(|| unsafe { - args::cleanup(); - sys::stack_overflow::cleanup(); - at_exit_imp::cleanup(); - }); -} diff --git a/src/libstd/rt/unwind/gcc.rs b/src/libstd/rt/unwind/gcc.rs deleted file mode 100644 index 55deb048b7e..00000000000 --- a/src/libstd/rt/unwind/gcc.rs +++ /dev/null @@ -1,235 +0,0 @@ -// 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 or the MIT license -// , 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 rt::libunwind as uw; - -struct Exception { - uwe: uw::_Unwind_Exception, - cause: Option>, -} - -pub unsafe fn panic(data: Box) -> ! { - 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) { - rtdebug!("exception_cleanup()"); - unsafe { - let _: Box = Box::from_raw(exception as *mut Exception); - } - } -} - -pub unsafe fn cleanup(ptr: *mut u8) -> Box { - let my_ep = ptr as *mut Exception; - rtdebug!("caught {}", (*my_ep).uwe.exception_class); - 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 rt::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 rt::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 rt::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 - { - if (state as c_int & uw::_US_ACTION_MASK as c_int) - == uw::_US_VIRTUAL_UNWIND_FRAME as c_int { // search phase - uw::_URC_HANDLER_FOUND // catch! - } - else { // cleanup phase - unsafe { - __gcc_personality_v0(state, ue_header, context) - } - } - } -} diff --git a/src/libstd/rt/unwind/mod.rs b/src/libstd/rt/unwind/mod.rs deleted file mode 100644 index 4feb2d49a98..00000000000 --- a/src/libstd/rt/unwind/mod.rs +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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, personality routines invoke cleanup code associated -//! with their stack frames (i.e. destructors). Once stack has been unwound down -//! to the handler frame level, unwinding stops and the last personality routine -//! transfers control to its catch block. -//! -//! ## Frame unwind info registration -//! -//! Each module has its own frame unwind info section (usually ".eh_frame"), and -//! unwinder needs to know about all of them in order for unwinding to be able to -//! cross module boundaries. -//! -//! On some platforms, like Linux, this is achieved by dynamically enumerating -//! currently loaded modules via the dl_iterate_phdr() API and finding all -//! .eh_frame sections. -//! -//! Others, like Windows, require modules to actively register their unwind info -//! sections by calling __register_frame_info() API at startup. In the latter -//! case it is essential that there is only one copy of the unwinder runtime in -//! the process. This is usually achieved by linking to the dynamic version of -//! the unwind runtime. -//! -//! Currently Rust uses unwind runtime provided by libgcc. - -#![allow(dead_code)] -#![allow(unused_imports)] - -use prelude::v1::*; - -use any::Any; -use boxed; -use cell::Cell; -use cmp; -use panicking; -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. - -// i686-pc-windows-msvc -#[cfg(all(windows, target_arch = "x86", target_env = "msvc"))] -#[path = "seh.rs"] #[doc(hidden)] -pub mod imp; - -// x86_64-pc-windows-* -#[cfg(all(windows, target_arch = "x86_64"))] -#[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; - -pub type Callback = fn(msg: &(Any + Send), file: &'static str, line: u32); - -// Variables used for invoking callbacks when a thread starts to unwind. -// -// For more information, see below. -const MAX_CALLBACKS: usize = 16; -static CALLBACKS: [atomic::AtomicUsize; MAX_CALLBACKS] = - [atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0), - atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0), - atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0), - atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0), - atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0), - atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0), - atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0), - atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0)]; -static CALLBACK_CNT: atomic::AtomicUsize = atomic::AtomicUsize::new(0); - -thread_local! { static PANICKING: Cell = Cell::new(false) } - -/// 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: F) -> Result<(), Box> { - let mut f = Some(f); - return inner_try(try_fn::, &mut f as *mut _ as *mut u8); - - // If an inner function were not used here, then this generic function `try` - // uses the native symbol `rust_try`, for which the code is statically - // linked into the standard library. This means that the DLL for the - // standard library must have `rust_try` as an exposed symbol that - // downstream crates can link against (because monomorphizations of `try` in - // downstream crates will have a reference to the `rust_try` symbol). - // - // On MSVC this requires the symbol `rust_try` to be tagged with - // `dllexport`, but it's easier to not have conditional `src/rt/rust_try.ll` - // files and instead just have this non-generic shim the compiler can take - // care of exposing correctly. - unsafe fn inner_try(f: fn(*mut u8), data: *mut u8) - -> Result<(), Box> { - let prev = PANICKING.with(|s| s.get()); - PANICKING.with(|s| s.set(false)); - let ep = intrinsics::try(f, data); - PANICKING.with(|s| s.set(prev)); - if ep.is_null() { - Ok(()) - } else { - Err(imp::cleanup(ep)) - } - } - - fn try_fn(opt_closure: *mut u8) { - let opt_closure = opt_closure as *mut Option; - unsafe { (*opt_closure).take().unwrap()(); } - } - - extern { - // Rust's try-catch - // When f(...) returns normally, the return value is null. - // When f(...) throws, the return value is a pointer to the caught - // exception object. - fn rust_try(f: extern fn(*mut u8), - data: *mut u8) -> *mut u8; - } -} - -/// Determines whether the current thread is unwinding because of panic. -pub fn panicking() -> bool { - PANICKING.with(|s| s.get()) -} - -// An uninlined, unmangled function upon which to slap yer breakpoints -#[inline(never)] -#[no_mangle] -#[allow(private_no_mangle_fns)] -fn rust_panic(cause: Box) -> ! { - rtdebug!("begin_unwind()"); - unsafe { - imp::panic(cause) - } -} - -#[cfg(not(test))] -/// Entry point of panic from the libcore crate. -#[lang = "panic_fmt"] -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. -#[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!(). -#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible -pub fn begin_unwind(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, - file_line: &(&'static str, u32)) -> ! { - // Make sure the default failure handler is registered before we look at the - // callbacks. We also use a raw sys-based mutex here instead of a - // `std::sync` one as accessing TLS can cause weird recursive problems (and - // we don't need poison checking). - unsafe { - static LOCK: Mutex = Mutex::new(); - static mut INIT: bool = false; - LOCK.lock(); - if !INIT { - register(panicking::on_panic); - INIT = true; - } - LOCK.unlock(); - } - - // First, invoke call the user-defined callbacks triggered on thread panic. - // - // By the time that we see a callback has been registered (by reading - // MAX_CALLBACKS), the actual callback itself may have not been stored yet, - // so we just chalk it up to a race condition and move on to the next - // callback. Additionally, CALLBACK_CNT may briefly be higher than - // MAX_CALLBACKS, so we're sure to clamp it as necessary. - let callbacks = { - let amt = CALLBACK_CNT.load(Ordering::SeqCst); - &CALLBACKS[..cmp::min(amt, MAX_CALLBACKS)] - }; - for cb in callbacks { - match cb.load(Ordering::SeqCst) { - 0 => {} - n => { - let f: Callback = unsafe { mem::transmute(n) }; - let (file, line) = *file_line; - f(&*msg, file, line); - } - } - }; - - // Now that we've run all the necessary unwind callbacks, we actually - // perform the unwinding. - if panicking() { - // 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 - // unwinding or otherwise exiting the thread cleanly. - rterrln!("thread panicked while panicking. aborting."); - unsafe { intrinsics::abort() } - } - PANICKING.with(|s| s.set(true)); - rust_panic(msg); -} - -/// Register a callback to be invoked when a thread unwinds. -/// -/// This is an unsafe and experimental API which allows for an arbitrary -/// callback to be invoked when a thread panics. This callback is invoked on both -/// the initial unwinding and a double unwinding if one occurs. Additionally, -/// the local `Thread` will be in place for the duration of the callback, and -/// the callback must ensure that it remains in place once the callback returns. -/// -/// Only a limited number of callbacks can be registered, and this function -/// returns whether the callback was successfully registered or not. It is not -/// currently possible to unregister a callback once it has been registered. -pub unsafe fn register(f: Callback) -> bool { - match CALLBACK_CNT.fetch_add(1, Ordering::SeqCst) { - // The invocation code has knowledge of this window where the count has - // been incremented, but the callback has not been stored. We're - // guaranteed that the slot we're storing into is 0. - n if n < MAX_CALLBACKS => { - let prev = CALLBACKS[n].swap(mem::transmute(f), Ordering::SeqCst); - rtassert!(prev == 0); - true - } - // If we accidentally bumped the count too high, pull it back. - _ => { - CALLBACK_CNT.store(MAX_CALLBACKS, Ordering::SeqCst); - false - } - } -} diff --git a/src/libstd/rt/unwind/seh.rs b/src/libstd/rt/unwind/seh.rs deleted file mode 100644 index 8c793758166..00000000000 --- a/src/libstd/rt/unwind/seh.rs +++ /dev/null @@ -1,145 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Win64 SEH (see http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx) -//! -//! 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. Currently this support is somewhat lacking, so what's -//! here is the bare bones of SEH support. -//! -//! 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 (just "cleanup" landing pads) -//! use the personality function `__C_specific_handler`, a function in the -//! CRT, and the unwinding code in Windows will use this personality function -//! to execute all cleanup code on the stack. -//! 3. Eventually the "catch" code in `rust_try` (located in -//! src/rt/rust_try_msvc_64.ll) is executed, which will ensure that the -//! exception being caught is indeed a Rust exception, returning control back -//! into Rust. -//! -//! Some specific differences from the gcc-based exception handling are: -//! -//! * Rust has no custom personality function, it is instead *always* -//! __C_specific_handler, so the filtering is done in a C++-like manner -//! instead of in the personality function itself. Note that the specific -//! syntax for this (found in the rust_try_msvc_64.ll) is taken from an LLVM -//! test case for SEH. -//! * We've got some data to transmit across the unwinding boundary, -//! specifically a `Box`. In Dwarf-based unwinding this -//! data is part of the payload of the exception, but I have not currently -//! figured out how to do this with LLVM's bindings. Judging by some comments -//! in the LLVM test cases this may not even be possible currently with LLVM, -//! so this is just abandoned entirely. Instead the data is stored in a -//! thread-local in `panic` and retrieved during `cleanup`. -//! -//! So given all that, the bindings here are pretty small, - -#![allow(bad_style)] - -use prelude::v1::*; - -use any::Any; -use libc::{c_ulong, DWORD, c_void}; -use ptr; -use sys_common::thread_local::StaticKey; - -// 0x R U S T -const RUST_PANIC: DWORD = 0x52555354; -static PANIC_DATA: StaticKey = StaticKey::new(None); - -// This function is provided by kernel32.dll -extern "system" { - fn RaiseException(dwExceptionCode: DWORD, - dwExceptionFlags: DWORD, - nNumberOfArguments: DWORD, - lpArguments: *const c_ulong); -} - -#[repr(C)] -pub struct EXCEPTION_POINTERS { - ExceptionRecord: *mut EXCEPTION_RECORD, - ContextRecord: *mut CONTEXT, -} - -enum CONTEXT {} - -#[repr(C)] -struct EXCEPTION_RECORD { - ExceptionCode: DWORD, - ExceptionFlags: DWORD, - ExceptionRecord: *mut _EXCEPTION_RECORD, - ExceptionAddress: *mut c_void, - NumberParameters: DWORD, - ExceptionInformation: [*mut c_ulong; EXCEPTION_MAXIMUM_PARAMETERS], -} - -enum _EXCEPTION_RECORD {} - -const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15; - -pub unsafe fn panic(data: Box) -> ! { - // See module docs above for an explanation of why `data` is stored in a - // thread local instead of being passed as an argument to the - // `RaiseException` function (which can in theory carry along arbitrary - // data). - let exception = Box::new(data); - rtassert!(PANIC_DATA.get().is_null()); - PANIC_DATA.set(Box::into_raw(exception) as *mut u8); - - RaiseException(RUST_PANIC, 0, 0, ptr::null()); - rtabort!("could not unwind stack"); -} - -pub unsafe fn cleanup(ptr: *mut u8) -> Box { - // The `ptr` here actually corresponds to the code of the exception, and our - // real data is stored in our thread local. - rtassert!(ptr as DWORD == RUST_PANIC); - - let data = PANIC_DATA.get() as *mut Box; - PANIC_DATA.set(ptr::null_mut()); - rtassert!(!data.is_null()); - - *Box::from_raw(data) -} - -// 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 is the -// personality function that is always used. Hence this is just an aborting -// stub. -#[lang = "eh_personality"] -fn rust_eh_personality() { - unsafe { ::intrinsics::abort() } -} - -// This is a function referenced from `rust_try_msvc_64.ll` which is used to -// filter the exceptions being caught by that function. -// -// In theory local variables can be accessed through the `rbp` parameter of this -// function, but a comment in an LLVM test case indicates that this is not -// implemented in LLVM, so this is just an idempotent function which doesn't -// ferry along any other information. -// -// This function just takes a look at the current EXCEPTION_RECORD being thrown -// to ensure that it's code is RUST_PANIC, which was set by the call to -// `RaiseException` above in the `panic` function. -#[no_mangle] -#[lang = "msvc_try_filter"] -pub extern fn __rust_try_filter(eh_ptrs: *mut EXCEPTION_POINTERS, - _rbp: *mut u8) -> i32 { - unsafe { - ((*(*eh_ptrs).ExceptionRecord).ExceptionCode == RUST_PANIC) as i32 - } -} diff --git a/src/libstd/rt/unwind/seh64_gnu.rs b/src/libstd/rt/unwind/seh64_gnu.rs deleted file mode 100644 index 78f969bfbeb..00000000000 --- a/src/libstd/rt/unwind/seh64_gnu.rs +++ /dev/null @@ -1,226 +0,0 @@ -// 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 or the MIT license -// , 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 self::EXCEPTION_DISPOSITION::*; -use rt::dwarf::eh; -use core::mem; -use core::ptr; -use libc::{c_void, c_ulonglong, DWORD, LPVOID}; -type ULONG_PTR = c_ulonglong; - -// 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: DWORD = 0b1110_u32 << 28; -const MAGIC: DWORD = 0x525354; // "RST" - -const RUST_PANIC: DWORD = ETYPE | (1 << 24) | MAGIC; - -const EXCEPTION_NONCONTINUABLE: DWORD = 0x1; // Noncontinuable exception -const EXCEPTION_UNWINDING: DWORD = 0x2; // Unwind is in progress -const EXCEPTION_EXIT_UNWIND: DWORD = 0x4; // Exit unwind is in progress -const EXCEPTION_STACK_INVALID: DWORD = 0x8; // Stack out of limits or unaligned -const EXCEPTION_NESTED_CALL: DWORD = 0x10; // Nested exception handler call -const EXCEPTION_TARGET_UNWIND: DWORD = 0x20; // Target unwind in progress -const EXCEPTION_COLLIDED_UNWIND: DWORD = 0x40; // Collided exception handler call -const EXCEPTION_UNWIND: DWORD = EXCEPTION_UNWINDING | - EXCEPTION_EXIT_UNWIND | - EXCEPTION_TARGET_UNWIND | - EXCEPTION_COLLIDED_UNWIND; - -#[repr(C)] -pub struct EXCEPTION_RECORD { - ExceptionCode: DWORD, - ExceptionFlags: DWORD, - ExceptionRecord: *const EXCEPTION_RECORD, - ExceptionAddress: LPVOID, - NumberParameters: DWORD, - ExceptionInformation: [ULONG_PTR; 15], -} - -pub enum CONTEXT {} -pub enum UNWIND_HISTORY_TABLE {} - -#[repr(C)] -pub struct RUNTIME_FUNCTION { - BeginAddress: DWORD, - EndAddress: DWORD, - UnwindData: DWORD, -} - -#[repr(C)] -pub struct DISPATCHER_CONTEXT { - ControlPc: LPVOID, - ImageBase: LPVOID, - FunctionEntry: *const RUNTIME_FUNCTION, - EstablisherFrame: LPVOID, - TargetIp: LPVOID, - ContextRecord: *const CONTEXT, - LanguageHandler: LPVOID, - HandlerData: *const u8, - HistoryTable: *const UNWIND_HISTORY_TABLE, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum EXCEPTION_DISPOSITION { - ExceptionContinueExecution, - ExceptionContinueSearch, - ExceptionNestedException, - ExceptionCollidedUnwind -} - -// From kernel32.dll -extern "system" { - fn RaiseException(dwExceptionCode: DWORD, - dwExceptionFlags: DWORD, - nNumberOfArguments: DWORD, - lpArguments: *const ULONG_PTR); - - fn RtlUnwindEx(TargetFrame: LPVOID, - TargetIp: LPVOID, - ExceptionRecord: *const EXCEPTION_RECORD, - ReturnValue: LPVOID, - OriginalContext: *const CONTEXT, - HistoryTable: *const UNWIND_HISTORY_TABLE); -} - -#[repr(C)] -struct PanicData { - data: Box -} - -pub unsafe fn panic(data: Box) -> ! { - let panic_ctx = Box::new(PanicData { data: data }); - let params = [Box::into_raw(panic_ctx) as ULONG_PTR]; - rtdebug!("panic: ctx={:X}", params[0]); - RaiseException(RUST_PANIC, - EXCEPTION_NONCONTINUABLE, - params.len() as DWORD, - ¶ms as *const ULONG_PTR); - rtabort!("could not unwind stack"); -} - -pub unsafe fn cleanup(ptr: *mut u8) -> Box { - rtdebug!("cleanup: ctx={:X}", ptr as usize); - 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 EXCEPTION_RECORD, - establisherFrame: LPVOID, - contextRecord: *mut CONTEXT, - dispatcherContext: *mut DISPATCHER_CONTEXT -) -> EXCEPTION_DISPOSITION -{ - rust_eh_personality(exceptionRecord, establisherFrame, - contextRecord, dispatcherContext) -} - -#[lang = "eh_personality"] -#[cfg(not(test))] -unsafe extern fn rust_eh_personality( - exceptionRecord: *mut EXCEPTION_RECORD, - establisherFrame: LPVOID, - contextRecord: *mut CONTEXT, - dispatcherContext: *mut DISPATCHER_CONTEXT -) -> EXCEPTION_DISPOSITION -{ - let er = &*exceptionRecord; - let dc = &*dispatcherContext; - rtdebug!("rust_eh_personality: code={:X}, flags={:X}, frame={:X}, ip={:X}", - er.ExceptionCode, er.ExceptionFlags, - establisherFrame as usize, dc.ControlPc as usize); - - if er.ExceptionFlags & EXCEPTION_UNWIND == 0 { // we are in the dispatch phase - if er.ExceptionCode == RUST_PANIC { - if let Some(lpad) = find_landing_pad(dc) { - rtdebug!("unwinding to landing pad {:X}", lpad); - - RtlUnwindEx(establisherFrame, - lpad as LPVOID, - exceptionRecord, - er.ExceptionInformation[0] as LPVOID, // pointer to PanicData - contextRecord, - dc.HistoryTable); - rtabort!("could not unwind"); - } - } - } - ExceptionContinueSearch -} - -// The `resume` instruction, found at the end of the landing pads, and whose job -// is to resume stack unwinding, is typically lowered by LLVM into a call to -// `_Unwind_Resume` routine. To avoid confusion with the same symbol exported -// from libgcc, we redirect it to `rust_eh_unwind_resume`. -// Since resolution of this symbol is done by the linker, `rust_eh_unwind_resume` -// must be marked `pub` + `#[no_mangle]`. (Can we make it a lang item?) - -#[lang = "eh_unwind_resume"] -#[cfg(not(test))] -unsafe extern fn rust_eh_unwind_resume(panic_ctx: LPVOID) { - rtdebug!("rust_eh_unwind_resume: ctx={:X}", panic_ctx as usize); - let params = [panic_ctx as ULONG_PTR]; - RaiseException(RUST_PANIC, - EXCEPTION_NONCONTINUABLE, - params.len() as DWORD, - ¶ms as *const ULONG_PTR); - rtabort!("could not resume unwind"); -} - -unsafe fn find_landing_pad(dc: &DISPATCHER_CONTEXT) -> Option { - 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) -} diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs deleted file mode 100644 index 23a3c3e38c4..00000000000 --- a/src/libstd/rt/util.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io::prelude::*; - -use env; -use fmt; -use intrinsics; -use sync::atomic::{self, Ordering}; -use sys::stdio::Stderr; - -pub fn min_stack() -> usize { - static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0); - match MIN.load(Ordering::SeqCst) { - 0 => {} - n => return n - 1, - } - let amt = env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok()); - let amt = amt.unwrap_or(2 * 1024 * 1024); - // 0 is our sentinel value, so ensure that we'll never see 0 after - // initialization has run - MIN.store(amt + 1, Ordering::SeqCst); - amt -} - -// Indicates whether we should perform expensive sanity checks, including rtassert! -// -// FIXME: Once the runtime matures remove the `true` below to turn off rtassert, -// etc. -pub const ENFORCE_SANITY: bool = true || !cfg!(rtopt) || cfg!(rtdebug) || - cfg!(rtassert); - -pub fn dumb_print(args: fmt::Arguments) { - let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args)); -} - -pub fn abort(args: fmt::Arguments) -> ! { - rterrln!("fatal runtime error: {}", args); - unsafe { intrinsics::abort(); } -} - -pub unsafe fn report_overflow() { - use thread; - rterrln!("\nthread '{}' has overflowed its stack", - thread::current().name().unwrap_or("")); -} -- cgit 1.4.1-3-g733a5