diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2016-04-08 16:18:40 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2016-05-09 08:22:36 -0700 |
| commit | 0ec321f7b541fcbfbf20286beb497e6d9d3352b2 (patch) | |
| tree | 30abd6498f7e3ae65fa94057e2bd46f6c769fcf2 /src/libstd | |
| parent | 32683ce1930ef1390f20e4ab72650e6804fd1c1b (diff) | |
| download | rust-0ec321f7b541fcbfbf20286beb497e6d9d3352b2.tar.gz rust-0ec321f7b541fcbfbf20286beb497e6d9d3352b2.zip | |
rustc: Implement custom panic runtimes
This commit is an implementation of [RFC 1513] which allows applications to alter the behavior of panics at compile time. A new compiler flag, `-C panic`, is added and accepts the values `unwind` or `panic`, with the default being `unwind`. This model affects how code is generated for the local crate, skipping generation of landing pads with `-C panic=abort`. [RFC 1513]: https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md Panic implementations are then provided by crates tagged with `#![panic_runtime]` and lazily required by crates with `#![needs_panic_runtime]`. The panic strategy (`-C panic` value) of the panic runtime must match the final product, and if the panic strategy is not `abort` then the entire DAG must have the same panic strategy. With the `-C panic=abort` strategy, users can expect a stable method to disable generation of landing pads, improving optimization in niche scenarios, decreasing compile time, and decreasing output binary size. With the `-C panic=unwind` strategy users can expect the existing ability to isolate failure in Rust code from the outside world. Organizationally, this commit dismantles the `sys_common::unwind` module in favor of some bits moving part of it to `libpanic_unwind` and the rest into the `panicking` module in libstd. The custom panic runtime support is pretty similar to the custom allocator support with the only major difference being how the panic runtime is injected (takes the `-C panic` flag into account).
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/Cargo.toml | 3 | ||||
| -rw-r--r-- | src/libstd/build.rs | 21 | ||||
| -rw-r--r-- | src/libstd/lib.rs | 11 | ||||
| -rw-r--r-- | src/libstd/macros.rs | 10 | ||||
| -rw-r--r-- | src/libstd/panic.rs | 9 | ||||
| -rw-r--r-- | src/libstd/panicking.rs | 216 | ||||
| -rw-r--r-- | src/libstd/rt.rs | 8 | ||||
| -rw-r--r-- | src/libstd/sys/common/dwarf/eh.rs | 159 | ||||
| -rw-r--r-- | src/libstd/sys/common/dwarf/mod.rs | 107 | ||||
| -rw-r--r-- | src/libstd/sys/common/libunwind.rs | 158 | ||||
| -rw-r--r-- | src/libstd/sys/common/mod.rs | 3 | ||||
| -rw-r--r-- | src/libstd/sys/common/unwind/gcc.rs | 280 | ||||
| -rw-r--r-- | src/libstd/sys/common/unwind/mod.rs | 241 | ||||
| -rw-r--r-- | src/libstd/sys/common/unwind/seh.rs | 153 | ||||
| -rw-r--r-- | src/libstd/sys/common/unwind/seh64_gnu.rs | 145 | ||||
| -rw-r--r-- | src/libstd/sys/unix/backtrace/tracing/gcc_s.rs | 124 | ||||
| -rw-r--r-- | src/libstd/sys/windows/c.rs | 53 | ||||
| -rw-r--r-- | src/libstd/thread/mod.rs | 17 |
18 files changed, 218 insertions, 1500 deletions
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 29bd28b6160..6d33fb311cf 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -14,11 +14,14 @@ test = false alloc = { path = "../liballoc" } alloc_jemalloc = { path = "../liballoc_jemalloc", optional = true } alloc_system = { path = "../liballoc_system" } +panic_unwind = { path = "../libpanic_unwind" } +panic_abort = { path = "../libpanic_abort" } collections = { path = "../libcollections" } core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } rand = { path = "../librand" } rustc_unicode = { path = "../librustc_unicode" } +unwind = { path = "../libunwind" } [build-dependencies] build_helper = { path = "../build_helper" } diff --git a/src/libstd/build.rs b/src/libstd/build.rs index c32bca82bd5..e879d440643 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -28,9 +28,7 @@ fn main() { } if target.contains("linux") { - if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) { - println!("cargo:rustc-link-lib=static=unwind"); - } else if target.contains("android") { + if target.contains("android") { println!("cargo:rustc-link-lib=dl"); println!("cargo:rustc-link-lib=log"); println!("cargo:rustc-link-lib=gcc"); @@ -38,27 +36,13 @@ fn main() { println!("cargo:rustc-link-lib=dl"); println!("cargo:rustc-link-lib=rt"); println!("cargo:rustc-link-lib=pthread"); - println!("cargo:rustc-link-lib=gcc_s"); } } else if target.contains("freebsd") { println!("cargo:rustc-link-lib=execinfo"); println!("cargo:rustc-link-lib=pthread"); - println!("cargo:rustc-link-lib=gcc_s"); } else if target.contains("dragonfly") || target.contains("bitrig") || target.contains("netbsd") || target.contains("openbsd") { println!("cargo:rustc-link-lib=pthread"); - - if target.contains("rumprun") { - println!("cargo:rustc-link-lib=unwind"); - } else if target.contains("netbsd") { - println!("cargo:rustc-link-lib=gcc_s"); - } else if target.contains("openbsd") { - println!("cargo:rustc-link-lib=gcc"); - } else if target.contains("bitrig") { - println!("cargo:rustc-link-lib=c++abi"); - } else if target.contains("dragonfly") { - println!("cargo:rustc-link-lib=gcc_pic"); - } } else if target.contains("apple-darwin") { println!("cargo:rustc-link-lib=System"); } else if target.contains("apple-ios") { @@ -67,9 +51,6 @@ fn main() { println!("cargo:rustc-link-lib=framework=Security"); println!("cargo:rustc-link-lib=framework=Foundation"); } else if target.contains("windows") { - if target.contains("windows-gnu") { - println!("cargo:rustc-link-lib=gcc_eh"); - } println!("cargo:rustc-link-lib=advapi32"); println!("cargo:rustc-link-lib=ws2_32"); println!("cargo:rustc-link-lib=userenv"); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d4b40b844fc..8f41bdf39e9 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -245,6 +245,7 @@ #![feature(on_unimplemented)] #![feature(oom)] #![feature(optin_builtin_traits)] +#![feature(panic_unwind)] #![feature(placement_in_syntax)] #![feature(rand)] #![feature(raw)] @@ -283,6 +284,13 @@ #![allow(unused_features)] // std may use features in a platform-specific way #![cfg_attr(not(stage0), deny(warnings))] +// FIXME(stage0): after a snapshot, move needs_panic_runtime up above and remove +// this `extern crate` declaration and feature(panic_unwind) +#![cfg_attr(not(stage0), needs_panic_runtime)] +#![cfg_attr(not(stage0), feature(needs_panic_runtime))] +#[cfg(stage0)] +extern crate panic_unwind as __please_just_link_me_dont_reference_me; + #[cfg(test)] extern crate test; // We want to reexport a few macros from core but libcore has already been @@ -301,6 +309,9 @@ extern crate alloc; extern crate rustc_unicode; extern crate libc; +// We always need an unwinder currently for backtraces +extern crate unwind; + #[cfg(stage0)] extern crate alloc_system; diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 39adda1066a..d69789cedaf 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -17,9 +17,9 @@ /// The entry point for panic of Rust threads. /// /// This macro is used to inject panic into a Rust thread, causing the thread to -/// unwind and panic entirely. Each thread's panic can be reaped as the -/// `Box<Any>` type, and the single-argument form of the `panic!` macro will be -/// the value which is transmitted. +/// panic entirely. Each thread's panic can be reaped as the `Box<Any>` type, +/// and the single-argument form of the `panic!` macro will be the value which +/// is transmitted. /// /// The multi-argument form of this macro panics with a string and has the /// `format!` syntax for building a string. @@ -41,14 +41,14 @@ macro_rules! panic { panic!("explicit panic") }); ($msg:expr) => ({ - $crate::rt::begin_unwind($msg, { + $crate::rt::begin_panic($msg, { // static requires less code at runtime, more constant data static _FILE_LINE: (&'static str, u32) = (file!(), line!()); &_FILE_LINE }) }); ($fmt:expr, $($arg:tt)+) => ({ - $crate::rt::begin_unwind_fmt(format_args!($fmt, $($arg)+), { + $crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+), { // The leading _'s are to avoid dead code warnings if this is // used inside a dead function. Just `#[allow(dead_code)]` is // insufficient, since the user may have diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index bbd89af01a7..9a195d93afd 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -16,10 +16,10 @@ use any::Any; use boxed::Box; use cell::UnsafeCell; use ops::{Deref, DerefMut}; +use panicking; use ptr::{Unique, Shared}; use rc::Rc; use sync::{Arc, Mutex, RwLock}; -use sys_common::unwind; use thread::Result; #[unstable(feature = "panic_handler", issue = "30449")] @@ -383,12 +383,9 @@ impl<R, F: FnOnce() -> R> FnOnce<()> for AssertRecoverSafe<F> { /// ``` #[stable(feature = "catch_unwind", since = "1.9.0")] pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> { - let mut result = None; unsafe { - let result = &mut result; - unwind::try(move || *result = Some(f()))? + panicking::try(f) } - Ok(result.unwrap()) } /// Deprecated, renamed to `catch_unwind` @@ -425,7 +422,7 @@ pub fn recover<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> { /// ``` #[stable(feature = "resume_unwind", since = "1.9.0")] pub fn resume_unwind(payload: Box<Any + Send>) -> ! { - unwind::rust_panic(payload) + panicking::rust_panic(payload) } /// Deprecated, use resume_unwind instead diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index fd6a15b0f69..fd74651bf77 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -8,13 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Implementation of various bits and pieces of the `panic!` macro and +//! associated runtime pieces. +//! +//! Specifically, this module contains the implementation of: +//! +//! * Panic hooks +//! * Executing a panic up to doing the actual implementation +//! * Shims around "try" + use prelude::v1::*; use io::prelude::*; use any::Any; use cell::Cell; use cell::RefCell; +use fmt; use intrinsics; +use mem; +use raw; use sync::StaticRwLock; use sync::atomic::{AtomicBool, Ordering}; use sys::stdio::Stderr; @@ -23,14 +35,33 @@ use sys_common::thread_info; use sys_common::util; use thread; -thread_local! { pub static PANIC_COUNT: Cell<usize> = Cell::new(0) } - thread_local! { pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = { RefCell::new(None) } } +thread_local! { pub static PANIC_COUNT: Cell<usize> = Cell::new(0) } + +// Binary interface to the panic runtime that the standard library depends on. +// +// The standard library is tagged with `#![needs_panic_runtime]` (introduced in +// RFC 1513) to indicate that it requires some other crate tagged with +// `#![panic_runtime]` to exist somewhere. Each panic runtime is intended to +// implement these symbols (with the same signatures) so we can get matched up +// to them. +// +// One day this may look a little less ad-hoc with the compiler helping out to +// hook up these functions, but it is not this day! +extern { + fn __rust_maybe_catch_panic(f: fn(*mut u8), + data: *mut u8, + data_ptr: *mut usize, + vtable_ptr: *mut usize) -> u32; + #[unwind] + fn __rust_start_panic(data: usize, vtable: usize) -> u32; +} + #[derive(Copy, Clone)] enum Hook { Default, @@ -57,7 +88,7 @@ static FIRST_PANIC: AtomicBool = AtomicBool::new(true); /// # Panics /// /// Panics if called from a panicking thread. -#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")] +#[unstable(feature = "panic_handler", issue = "30449")] pub fn set_hook(hook: Box<Fn(&PanicInfo) + 'static + Sync + Send>) { if thread::panicking() { panic!("cannot modify the panic hook from a panicking thread"); @@ -82,7 +113,7 @@ pub fn set_hook(hook: Box<Fn(&PanicInfo) + 'static + Sync + Send>) { /// # Panics /// /// Panics if called from a panicking thread. -#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")] +#[unstable(feature = "panic_handler", issue = "30449")] pub fn take_hook() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> { if thread::panicking() { panic!("cannot modify the panic hook from a panicking thread"); @@ -102,7 +133,7 @@ pub fn take_hook() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> { } /// A struct providing information about a panic. -#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")] +#[unstable(feature = "panic_handler", issue = "30449")] pub struct PanicInfo<'a> { payload: &'a (Any + Send), location: Location<'a>, @@ -112,7 +143,7 @@ impl<'a> PanicInfo<'a> { /// Returns the payload associated with the panic. /// /// This will commonly, but not always, be a `&'static str` or `String`. - #[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")] + #[unstable(feature = "panic_handler", issue = "30449")] pub fn payload(&self) -> &(Any + Send) { self.payload } @@ -122,14 +153,14 @@ impl<'a> PanicInfo<'a> { /// /// This method will currently always return `Some`, but this may change /// in future versions. - #[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")] + #[unstable(feature = "panic_handler", issue = "30449")] pub fn location(&self) -> Option<&Location> { Some(&self.location) } } /// A struct containing information about the location of a panic. -#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")] +#[unstable(feature = "panic_handler", issue = "30449")] pub struct Location<'a> { file: &'a str, line: u32, @@ -137,20 +168,20 @@ pub struct Location<'a> { impl<'a> Location<'a> { /// Returns the name of the source file from which the panic originated. - #[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")] + #[unstable(feature = "panic_handler", issue = "30449")] pub fn file(&self) -> &str { self.file } /// Returns the line number from which the panic originated. - #[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")] + #[unstable(feature = "panic_handler", issue = "30449")] pub fn line(&self) -> u32 { self.line } } fn default_hook(info: &PanicInfo) { - let panics = PANIC_COUNT.with(|s| s.get()); + let panics = PANIC_COUNT.with(|c| c.get()); // If this is a double panic, make sure that we print a backtrace // for this panic. Otherwise only print it if logging is enabled. @@ -195,33 +226,143 @@ fn default_hook(info: &PanicInfo) { } } -pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) { - let panics = PANIC_COUNT.with(|s| { - let count = s.get() + 1; - s.set(count); - count +/// Invoke a closure, capturing the cause of an unwinding panic if one occurs. +pub unsafe fn try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<Any + Send>> { + let mut slot = None; + let mut f = Some(f); + let ret = PANIC_COUNT.with(|s| { + let prev = s.get(); + s.set(0); + + let mut to_run = || { + slot = Some(f.take().unwrap()()); + }; + let fnptr = get_call(&mut to_run); + let dataptr = &mut to_run as *mut _ as *mut u8; + let mut any_data = 0; + let mut any_vtable = 0; + let fnptr = mem::transmute::<fn(&mut _), fn(*mut u8)>(fnptr); + let r = __rust_maybe_catch_panic(fnptr, + dataptr, + &mut any_data, + &mut any_vtable); + s.set(prev); + + if r == 0 { + Ok(()) + } else { + Err(mem::transmute(raw::TraitObject { + data: any_data as *mut _, + vtable: any_vtable as *mut _, + })) + } + }); + + 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), @@ -229,7 +370,7 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) { } } - if panics >= 2 { + if panics > 0 { // If a thread panics while it's already unwinding then we // have limited options. Currently our preference is to // just abort. In the future we may consider resuming @@ -238,4 +379,17 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) { aborting.\n")); unsafe { intrinsics::abort() } } + + rust_panic(msg) +} + +/// A private no-mangle function on which to slap yer breakpoints. +#[no_mangle] +#[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints +pub fn rust_panic(msg: Box<Any + Send>) -> ! { + let code = unsafe { + let obj = mem::transmute::<_, raw::TraitObject>(msg); + __rust_start_panic(obj.data as usize, obj.vtable as usize) + }; + rtabort!("failed to initiate panic, error {}", code) } diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 83091c72c0d..6eee4ee9bbe 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -25,12 +25,10 @@ // Reexport some of our utilities which are expected by other crates. -pub use sys_common::unwind::{begin_unwind, begin_unwind_fmt}; +pub use panicking::{begin_panic, begin_panic_fmt}; -// Rust runtime's startup objects depend on these symbols, so they must be public. -// Since sys_common isn't public, we have to re-export them here. -#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] -pub use sys_common::unwind::imp::eh_frame_registry::*; +#[cfg(stage0)] +pub use panicking::begin_panic as begin_unwind; #[cfg(not(test))] #[lang = "start"] diff --git a/src/libstd/sys/common/dwarf/eh.rs b/src/libstd/sys/common/dwarf/eh.rs deleted file mode 100644 index 319be245bde..00000000000 --- a/src/libstd/sys/common/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 <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 -} diff --git a/src/libstd/sys/common/dwarf/mod.rs b/src/libstd/sys/common/dwarf/mod.rs deleted file mode 100644 index 822826bcc83..00000000000 --- a/src/libstd/sys/common/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 <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)); - } -} diff --git a/src/libstd/sys/common/libunwind.rs b/src/libstd/sys/common/libunwind.rs deleted file mode 100644 index c1e9782852a..00000000000 --- a/src/libstd/sys/common/libunwind.rs +++ /dev/null @@ -1,158 +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 <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) -} diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index 56628a4c754..c9279883ae5 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -30,9 +30,7 @@ pub mod args; pub mod at_exit_imp; pub mod backtrace; pub mod condvar; -pub mod dwarf; pub mod io; -pub mod libunwind; pub mod mutex; pub mod net; pub mod poison; @@ -41,7 +39,6 @@ pub mod rwlock; pub mod thread; pub mod thread_info; pub mod thread_local; -pub mod unwind; pub mod util; pub mod wtf8; diff --git a/src/libstd/sys/common/unwind/gcc.rs b/src/libstd/sys/common/unwind/gcc.rs deleted file mode 100644 index da7a340af35..00000000000 --- a/src/libstd/sys/common/unwind/gcc.rs +++ /dev/null @@ -1,280 +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 <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); - } -} diff --git a/src/libstd/sys/common/unwind/mod.rs b/src/libstd/sys/common/unwind/mod.rs deleted file mode 100644 index 527c2e63030..00000000000 --- a/src/libstd/sys/common/unwind/mod.rs +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation of Rust stack unwinding -//! -//! For background on exception handling and stack unwinding please see -//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and -//! documents linked from it. -//! These are also good reads: -//! http://mentorembedded.github.io/cxx-abi/abi-eh.html -//! http://monoinfinito.wordpress.com/series/exception-handling-in-c/ -//! http://www.airs.com/blog/index.php?s=exception+frames -//! -//! ## A brief summary -//! -//! Exception handling happens in two phases: a search phase and a cleanup phase. -//! -//! In both phases the unwinder walks stack frames from top to bottom using -//! information from the stack frame unwind sections of the current process's -//! modules ("module" here refers to an OS module, i.e. an executable or a -//! dynamic library). -//! -//! For each stack frame, it invokes the associated "personality routine", whose -//! address is also stored in the unwind info section. -//! -//! In the search phase, the job of a personality routine is to examine exception -//! object being thrown, and to decide whether it should be caught at that stack -//! frame. Once the handler frame has been identified, cleanup phase begins. -//! -//! In the cleanup phase, the unwinder invokes each personality routine again. -//! This time it decides which (if any) cleanup code needs to be run for -//! the current stack frame. If so, the control is transferred to a special branch -//! in the function body, the "landing pad", which invokes destructors, frees memory, -//! etc. At the end of the landing pad, control is transferred back to the unwinder -//! and unwinding resumes. -//! -//! Once stack has been unwound down to the handler frame level, unwinding stops -//! and the last personality routine transfers control to the catch block. -//! -//! ## `eh_personality` and `eh_unwind_resume` -//! -//! These language items are used by the compiler when generating unwind info. -//! The first one is the personality routine described above. The second one -//! allows compilation target to customize the process of resuming unwind at the -//! end of the landing pads. `eh_unwind_resume` is used only if `custom_unwind_resume` -//! flag in the target options is set. -//! -//! ## Frame unwind info registration -//! -//! Each module's image contains a frame unwind info section (usually ".eh_frame"). -//! When a module is loaded/unloaded into the process, the unwinder must be informed -//! about the location of this section in memory. The methods of achieving that vary -//! by the platform. -//! On some (e.g. Linux), the unwinder can discover unwind info sections on its own -//! (by dynamically enumerating currently loaded modules via the dl_iterate_phdr() API -//! and finding their ".eh_frame" sections); -//! Others, like Windows, require modules to actively register their unwind info -//! sections via unwinder API (see `rust_eh_register_frames`/`rust_eh_unregister_frames`). - -#![allow(dead_code)] -#![allow(unused_imports)] - -use prelude::v1::*; - -use any::Any; -use boxed; -use cmp; -use panicking::{self,PANIC_COUNT}; -use fmt; -use intrinsics; -use mem; -use sync::atomic::{self, Ordering}; -use sys_common::mutex::Mutex; - -// The actual unwinding implementation is cfg'd here, and we've got two current -// implementations. One goes through SEH on Windows and the other goes through -// libgcc via the libunwind-like API. - -// *-pc-windows-msvc -#[cfg(target_env = "msvc")] -#[path = "seh.rs"] #[doc(hidden)] -pub mod imp; - -// x86_64-pc-windows-gnu -#[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] -#[path = "seh64_gnu.rs"] #[doc(hidden)] -pub mod imp; - -// i686-pc-windows-gnu and all others -#[cfg(any(unix, all(windows, target_arch = "x86", target_env = "gnu")))] -#[path = "gcc.rs"] #[doc(hidden)] -pub mod imp; - -/// Invoke a closure, capturing the cause of panic if one occurs. -/// -/// This function will return `Ok(())` if the closure did not panic, and will -/// return `Err(cause)` if the closure panics. The `cause` returned is the -/// object with which panic was originally invoked. -/// -/// This function also is unsafe for a variety of reasons: -/// -/// * This is not safe to call in a nested fashion. The unwinding -/// interface for Rust is designed to have at most one try/catch block per -/// thread, not multiple. No runtime checking is currently performed to uphold -/// this invariant, so this function is not safe. A nested try/catch block -/// may result in corruption of the outer try/catch block's state, especially -/// if this is used within a thread itself. -/// -/// * It is not sound to trigger unwinding while already unwinding. Rust threads -/// have runtime checks in place to ensure this invariant, but it is not -/// guaranteed that a rust thread is in place when invoking this function. -/// Unwinding twice can lead to resource leaks where some destructors are not -/// run. -pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> { - let mut f = Some(f); - return inner_try(try_fn::<F>, &mut f as *mut _ as *mut u8); - - fn try_fn<F: FnOnce()>(opt_closure: *mut u8) { - let opt_closure = opt_closure as *mut Option<F>; - unsafe { (*opt_closure).take().unwrap()(); } - } -} - -unsafe fn inner_try(f: fn(*mut u8), data: *mut u8) - -> Result<(), Box<Any + Send>> { - PANIC_COUNT.with(|s| { - let prev = s.get(); - s.set(0); - - // The "payload" here is a platform-specific region of memory which is - // used to transmit information about the exception being thrown from - // the point-of-throw back to this location. - // - // A pointer to this data is passed to the `try` intrinsic itself, - // allowing this function, the `try` intrinsic, imp::payload(), and - // imp::cleanup() to all work in concert to transmit this information. - // - // More information about what this pointer actually is can be found in - // each implementation as well as browsing the compiler source itself. - let mut payload = imp::payload(); - let r = intrinsics::try(f, data, &mut payload as *mut _ as *mut _); - s.set(prev); - if r == 0 { - Ok(()) - } else { - Err(imp::cleanup(payload)) - } - }) -} - -/// Determines whether the current thread is unwinding because of panic. -pub fn panicking() -> bool { - PANIC_COUNT.with(|s| s.get() != 0) -} - -// An uninlined, unmangled function upon which to slap yer breakpoints -#[inline(never)] -#[no_mangle] -#[allow(private_no_mangle_fns)] -pub fn rust_panic(cause: Box<Any + Send + 'static>) -> ! { - unsafe { - imp::panic(cause) - } -} - -#[cfg(not(test))] -/// Entry point of panic from the libcore crate. -#[lang = "panic_fmt"] -#[unwind] -pub extern fn rust_begin_unwind(msg: fmt::Arguments, - file: &'static str, line: u32) -> ! { - begin_unwind_fmt(msg, &(file, line)) -} - -/// The entry point for unwinding with a formatted message. -/// -/// This is designed to reduce the amount of code required at the call -/// site as much as possible (so that `panic!()` has as low an impact -/// on (e.g.) the inlining of other functions as possible), by moving -/// the actual formatting into this shared place. -#[unstable(feature = "libstd_sys_internals", - reason = "used by the panic! macro", - issue = "0")] -#[inline(never)] #[cold] -pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, u32)) -> ! { - use fmt::Write; - - // We do two allocations here, unfortunately. But (a) they're - // required with the current scheme, and (b) we don't handle - // panic + OOM properly anyway (see comment in begin_unwind - // below). - - let mut s = String::new(); - let _ = s.write_fmt(msg); - begin_unwind_inner(Box::new(s), file_line) -} - -/// This is the entry point of unwinding for panic!() and assert!(). -#[unstable(feature = "libstd_sys_internals", - reason = "used by the panic! macro", - issue = "0")] -#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible -pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, u32)) -> ! { - // Note that this should be the only allocation performed in this code path. - // Currently this means that panic!() on OOM will invoke this code path, - // but then again we're not really ready for panic on OOM anyway. If - // we do start doing this, then we should propagate this allocation to - // be performed in the parent of this thread instead of the thread that's - // panicking. - - // see below for why we do the `Any` coercion here. - begin_unwind_inner(Box::new(msg), file_line) -} - -/// The core of the unwinding. -/// -/// This is non-generic to avoid instantiation bloat in other crates -/// (which makes compilation of small crates noticeably slower). (Note: -/// we need the `Any` object anyway, we're not just creating it to -/// avoid being generic.) -/// -/// Doing this split took the LLVM IR line counts of `fn main() { panic!() -/// }` from ~1900/3700 (-O/no opts) to 180/590. -#[inline(never)] #[cold] // this is the slow path, please never inline this -fn begin_unwind_inner(msg: Box<Any + Send>, - file_line: &(&'static str, u32)) -> ! { - let (file, line) = *file_line; - - // First, invoke the default panic handler. - panicking::on_panic(&*msg, file, line); - - // Finally, perform the unwinding. - rust_panic(msg); -} diff --git a/src/libstd/sys/common/unwind/seh.rs b/src/libstd/sys/common/unwind/seh.rs deleted file mode 100644 index 94da42f0092..00000000000 --- a/src/libstd/sys/common/unwind/seh.rs +++ /dev/null @@ -1,153 +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 <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() } -} diff --git a/src/libstd/sys/common/unwind/seh64_gnu.rs b/src/libstd/sys/common/unwind/seh64_gnu.rs deleted file mode 100644 index 57281d67ebb..00000000000 --- a/src/libstd/sys/common/unwind/seh64_gnu.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 <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) -} diff --git a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs index 8d880917166..5f7ad6918cd 100644 --- a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs +++ b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs @@ -15,6 +15,7 @@ use mem; use sync::StaticMutex; use super::super::printing::print; +use unwind as uw; #[inline(never)] // if we know this is a function call, we can skip it when // tracing @@ -102,126 +103,3 @@ pub fn write(w: &mut Write) -> io::Result<()> { uw::_URC_NO_REASON } } - -/// Unwind library interface used for backtraces -/// -/// Note that dead code is allowed as here are just bindings -/// iOS doesn't use all of them it but adding more -/// platform-specific configs pollutes the code too much -#[allow(non_camel_case_types)] -#[allow(non_snake_case)] -mod uw { - pub use self::_Unwind_Reason_Code::*; - - use libc; - - #[repr(C)] - pub enum _Unwind_Reason_Code { - _URC_NO_REASON = 0, - _URC_FOREIGN_EXCEPTION_CAUGHT = 1, - _URC_FATAL_PHASE2_ERROR = 2, - _URC_FATAL_PHASE1_ERROR = 3, - _URC_NORMAL_STOP = 4, - _URC_END_OF_STACK = 5, - _URC_HANDLER_FOUND = 6, - _URC_INSTALL_CONTEXT = 7, - _URC_CONTINUE_UNWIND = 8, - _URC_FAILURE = 9, // used only by ARM EABI - } - - pub enum _Unwind_Context {} - - pub type _Unwind_Trace_Fn = - extern fn(ctx: *mut _Unwind_Context, - arg: *mut libc::c_void) -> _Unwind_Reason_Code; - - extern { - // No native _Unwind_Backtrace on iOS - #[cfg(not(all(target_os = "ios", target_arch = "arm")))] - pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, - trace_argument: *mut libc::c_void) - -> _Unwind_Reason_Code; - - // available since GCC 4.2.0, should be fine for our purpose - #[cfg(all(not(all(target_os = "android", target_arch = "arm")), - not(all(target_os = "linux", target_arch = "arm"))))] - pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, - ip_before_insn: *mut libc::c_int) - -> libc::uintptr_t; - - #[cfg(all(not(target_os = "android"), - not(all(target_os = "linux", target_arch = "arm"))))] - pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) - -> *mut libc::c_void; - } - - // On android, the function _Unwind_GetIP is a macro, and this is the - // expansion of the macro. This is all copy/pasted directly from the - // header file with the definition of _Unwind_GetIP. - #[cfg(any(all(target_os = "android", target_arch = "arm"), - all(target_os = "linux", target_arch = "arm")))] - pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t { - #[repr(C)] - enum _Unwind_VRS_Result { - _UVRSR_OK = 0, - _UVRSR_NOT_IMPLEMENTED = 1, - _UVRSR_FAILED = 2, - } - #[repr(C)] - enum _Unwind_VRS_RegClass { - _UVRSC_CORE = 0, - _UVRSC_VFP = 1, - _UVRSC_FPA = 2, - _UVRSC_WMMXD = 3, - _UVRSC_WMMXC = 4, - } - #[repr(C)] - enum _Unwind_VRS_DataRepresentation { - _UVRSD_UINT32 = 0, - _UVRSD_VFPX = 1, - _UVRSD_FPAX = 2, - _UVRSD_UINT64 = 3, - _UVRSD_FLOAT = 4, - _UVRSD_DOUBLE = 5, - } - - type _Unwind_Word = libc::c_uint; - extern { - fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context, - klass: _Unwind_VRS_RegClass, - word: _Unwind_Word, - repr: _Unwind_VRS_DataRepresentation, - data: *mut libc::c_void) - -> _Unwind_VRS_Result; - } - - let mut val: _Unwind_Word = 0; - let ptr = &mut val as *mut _Unwind_Word; - let _ = _Unwind_VRS_Get(ctx, _Unwind_VRS_RegClass::_UVRSC_CORE, 15, - _Unwind_VRS_DataRepresentation::_UVRSD_UINT32, - ptr as *mut libc::c_void); - (val & !1) as libc::uintptr_t - } - - // This function doesn't exist on Android or ARM/Linux, so make it same - // to _Unwind_GetIP - #[cfg(any(all(target_os = "android", target_arch = "arm"), - all(target_os = "linux", target_arch = "arm")))] - pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, - ip_before_insn: *mut libc::c_int) - -> libc::uintptr_t - { - *ip_before_insn = 0; - _Unwind_GetIP(ctx) - } - - // This function also doesn't exist on Android or ARM/Linux, so make it - // a no-op - #[cfg(any(target_os = "android", - all(target_os = "linux", target_arch = "arm")))] - pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) - -> *mut libc::c_void - { - pc - } -} diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index ab24b9e6fd6..2acf6485eb3 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -277,21 +277,6 @@ pub const CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000; pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0; pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd; pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15; -#[cfg(all(target_arch = "x86_64", target_env = "gnu"))] -pub const EXCEPTION_NONCONTINUABLE: DWORD = 0x1; // Noncontinuable exception -#[cfg(all(target_arch = "x86_64", target_env = "gnu"))] -pub const EXCEPTION_UNWINDING: DWORD = 0x2; // Unwind is in progress -#[cfg(all(target_arch = "x86_64", target_env = "gnu"))] -pub const EXCEPTION_EXIT_UNWIND: DWORD = 0x4; // Exit unwind is in progress -#[cfg(all(target_arch = "x86_64", target_env = "gnu"))] -pub const EXCEPTION_TARGET_UNWIND: DWORD = 0x20; // Target unwind in progress -#[cfg(all(target_arch = "x86_64", target_env = "gnu"))] -pub const EXCEPTION_COLLIDED_UNWIND: DWORD = 0x40; // Collided exception handler call -#[cfg(all(target_arch = "x86_64", target_env = "gnu"))] -pub const EXCEPTION_UNWIND: DWORD = EXCEPTION_UNWINDING | - EXCEPTION_EXIT_UNWIND | - EXCEPTION_TARGET_UNWIND | - EXCEPTION_COLLIDED_UNWIND; pub const PIPE_ACCESS_INBOUND: DWORD = 0x00000001; pub const FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000; @@ -813,31 +798,6 @@ pub struct in6_addr { pub s6_addr: [u8; 16], } -#[cfg(all(target_arch = "x86_64", target_env = "gnu"))] -pub enum UNWIND_HISTORY_TABLE {} - -#[repr(C)] -#[cfg(all(target_arch = "x86_64", target_env = "gnu"))] -pub struct RUNTIME_FUNCTION { - pub BeginAddress: DWORD, - pub EndAddress: DWORD, - pub UnwindData: DWORD, -} - -#[repr(C)] -#[cfg(all(target_arch = "x86_64", target_env = "gnu"))] -pub struct DISPATCHER_CONTEXT { - pub ControlPc: LPVOID, - pub ImageBase: LPVOID, - pub FunctionEntry: *const RUNTIME_FUNCTION, - pub EstablisherFrame: LPVOID, - pub TargetIp: LPVOID, - pub ContextRecord: *const CONTEXT, - pub LanguageHandler: LPVOID, - pub HandlerData: *const u8, - pub HistoryTable: *const UNWIND_HISTORY_TABLE, -} - #[repr(C)] #[derive(Copy, Clone)] #[allow(dead_code)] // we only use some variants @@ -1113,19 +1073,6 @@ extern "system" { pbBuffer: *mut BYTE) -> BOOL; pub fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL; - #[unwind] - #[cfg(any(target_arch = "x86_64", target_env = "msvc"))] - pub fn RaiseException(dwExceptionCode: DWORD, - dwExceptionFlags: DWORD, - nNumberOfArguments: DWORD, - lpArguments: *const ULONG_PTR); - #[cfg(all(target_arch = "x86_64", target_env = "gnu"))] - pub fn RtlUnwindEx(TargetFrame: LPVOID, - TargetIp: LPVOID, - ExceptionRecord: *const EXCEPTION_RECORD, - ReturnValue: LPVOID, - OriginalContext: *const CONTEXT, - HistoryTable: *const UNWIND_HISTORY_TABLE); pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME); pub fn CreateEventW(lpEventAttributes: LPSECURITY_ATTRIBUTES, diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 2f0dec759b3..99e6ba8c770 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -163,14 +163,15 @@ use prelude::v1::*; use any::Any; use cell::UnsafeCell; +use ffi::{CStr, CString}; use fmt; use io; +use panic; +use panicking; use str; -use ffi::{CStr, CString}; use sync::{Mutex, Condvar, Arc}; use sys::thread as imp; use sys_common::thread_info; -use sys_common::unwind; use sys_common::util; use sys_common::{AsInner, IntoInner}; use time::Duration; @@ -273,14 +274,8 @@ impl Builder { } unsafe { thread_info::set(imp::guard::current(), their_thread); - let mut output = None; - let try_result = { - let ptr = &mut output; - unwind::try(move || *ptr = Some(f())) - }; - *their_packet.get() = Some(try_result.map(|()| { - output.unwrap() - })); + let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f)); + *their_packet.get() = Some(try_result); } }; @@ -337,7 +332,7 @@ pub fn yield_now() { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn panicking() -> bool { - unwind::panicking() + panicking::panicking() } /// Puts the current thread to sleep for the specified amount of time. |
