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/sys/common | |
| 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/sys/common')
| -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 |
8 files changed, 0 insertions, 1246 deletions
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) -} |
