about summary refs log tree commit diff
path: root/src/libstd/rt
diff options
context:
space:
mode:
authorMathieu David <mathieudavid@mathieudavid.org>2015-07-27 20:46:01 +0200
committerMathieu David <mathieudavid@mathieudavid.org>2015-07-27 20:46:01 +0200
commitf6e9240a99e86d2c799dc29f179dd2870e51f71d (patch)
treea7e5ba20745b16949a45a4612b2708e262693a7b /src/libstd/rt
parent003c3eaa62981b791f9eb7bcad015baa1e00d98c (diff)
parent3351afeecffcc9ebaeb1188a5cde976da8e4a5aa (diff)
downloadrust-f6e9240a99e86d2c799dc29f179dd2870e51f71d.tar.gz
rust-f6e9240a99e86d2c799dc29f179dd2870e51f71d.zip
Fix the relative path issue by including the files using include_bytes!
Diffstat (limited to 'src/libstd/rt')
-rw-r--r--src/libstd/rt/args.rs1
-rw-r--r--src/libstd/rt/libunwind.rs2
-rw-r--r--src/libstd/rt/mod.rs4
-rw-r--r--src/libstd/rt/unwind/gcc.rs73
-rw-r--r--src/libstd/rt/unwind/mod.rs19
-rw-r--r--src/libstd/rt/unwind/seh.rs132
-rw-r--r--src/libstd/rt/util.rs15
7 files changed, 187 insertions, 59 deletions
diff --git a/src/libstd/rt/args.rs b/src/libstd/rt/args.rs
index d23a124a6ec..52697f00264 100644
--- a/src/libstd/rt/args.rs
+++ b/src/libstd/rt/args.rs
@@ -44,6 +44,7 @@ pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
           target_os = "freebsd",
           target_os = "dragonfly",
           target_os = "bitrig",
+          target_os = "netbsd",
           target_os = "openbsd"))]
 mod imp {
     use prelude::v1::*;
diff --git a/src/libstd/rt/libunwind.rs b/src/libstd/rt/libunwind.rs
index 8f75ae5ef5c..d99b31c9f2b 100644
--- a/src/libstd/rt/libunwind.rs
+++ b/src/libstd/rt/libunwind.rs
@@ -106,7 +106,7 @@ extern {}
 #[link(name = "unwind", kind = "static")]
 extern {}
 
-#[cfg(any(target_os = "android", target_os = "openbsd"))]
+#[cfg(any(target_os = "android", target_os = "netbsd", target_os = "openbsd"))]
 #[link(name = "gcc")]
 extern {}
 
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs
index 1729d20da20..0ac0d03e19d 100644
--- a/src/libstd/rt/mod.rs
+++ b/src/libstd/rt/mod.rs
@@ -96,7 +96,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
         // own fault handlers if we hit it.
         sys_common::stack::record_os_managed_stack_bounds(my_stack_bottom,
                                                           my_stack_top);
-        sys::thread::guard::init();
+        let main_guard = sys::thread::guard::init();
         sys::stack_overflow::init();
 
         // Next, set up the current Thread with the guard information we just
@@ -104,7 +104,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
         // but we just do this to name the main thread and to give it correct
         // info about the stack bounds.
         let thread: Thread = NewThread::new(Some("<main>".to_string()));
-        thread_info::set(sys::thread::guard::main(), thread);
+        thread_info::set(main_guard, thread);
 
         // By default, some platforms will send a *signal* when a EPIPE error
         // would otherwise be delivered. This runtime doesn't install a SIGPIPE
diff --git a/src/libstd/rt/unwind/gcc.rs b/src/libstd/rt/unwind/gcc.rs
index 84c6d6864a9..59fc8df6107 100644
--- a/src/libstd/rt/unwind/gcc.rs
+++ b/src/libstd/rt/unwind/gcc.rs
@@ -8,10 +8,11 @@
 // 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 libc::c_void;
 use rt::libunwind as uw;
 
 struct Exception {
@@ -41,7 +42,7 @@ pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
     }
 }
 
-pub unsafe fn cleanup(ptr: *mut c_void) -> Box<Any + Send + 'static> {
+pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
     let my_ep = ptr as *mut Exception;
     rtdebug!("caught {}", (*my_ep).uwe.exception_class);
     let cause = (*my_ep).cause.take();
@@ -89,7 +90,7 @@ pub mod eabi {
     use rt::libunwind as uw;
     use libc::c_int;
 
-    extern "C" {
+    extern {
         fn __gcc_personality_v0(version: c_int,
                                 actions: uw::_Unwind_Action,
                                 exception_class: uw::_Unwind_Exception_Class,
@@ -98,9 +99,8 @@ pub mod eabi {
             -> uw::_Unwind_Reason_Code;
     }
 
-    #[lang="eh_personality"]
-    #[no_mangle] // referenced from rust_try.ll
-    #[allow(private_no_mangle_fns)]
+    #[lang = "eh_personality"]
+    #[no_mangle]
     extern fn rust_eh_personality(
         version: c_int,
         actions: uw::_Unwind_Action,
@@ -115,8 +115,9 @@ pub mod eabi {
         }
     }
 
-    #[no_mangle] // referenced from rust_try.ll
-    pub extern "C" fn rust_eh_personality_catch(
+    #[cfg_attr(not(stage0), 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,
@@ -142,7 +143,7 @@ pub mod eabi {
     use rt::libunwind as uw;
     use libc::c_int;
 
-    extern "C" {
+    extern {
         fn __gcc_personality_sj0(version: c_int,
                                 actions: uw::_Unwind_Action,
                                 exception_class: uw::_Unwind_Exception_Class,
@@ -151,9 +152,9 @@ pub mod eabi {
             -> uw::_Unwind_Reason_Code;
     }
 
-    #[lang="eh_personality"]
-    #[no_mangle] // referenced from rust_try.ll
-    pub extern "C" fn rust_eh_personality(
+    #[lang = "eh_personality"]
+    #[no_mangle]
+    pub extern fn rust_eh_personality(
         version: c_int,
         actions: uw::_Unwind_Action,
         exception_class: uw::_Unwind_Exception_Class,
@@ -167,8 +168,9 @@ pub mod eabi {
         }
     }
 
-    #[no_mangle] // referenced from rust_try.ll
-    pub extern "C" fn rust_eh_personality_catch(
+    #[cfg_attr(not(stage0), 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,
@@ -196,17 +198,16 @@ pub mod eabi {
     use rt::libunwind as uw;
     use libc::c_int;
 
-    extern "C" {
+    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] // referenced from rust_try.ll
-    #[allow(private_no_mangle_fns)]
-    extern "C" fn rust_eh_personality(
+    #[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
@@ -217,8 +218,9 @@ pub mod eabi {
         }
     }
 
-    #[no_mangle] // referenced from rust_try.ll
-    pub extern "C" fn rust_eh_personality_catch(
+    #[cfg_attr(not(stage0), 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
@@ -249,12 +251,11 @@ pub mod eabi {
     use rt::libunwind as uw;
     use libc::{c_void, c_int};
 
-    #[repr(C)]
-    pub struct EXCEPTION_RECORD;
-    #[repr(C)]
-    pub struct CONTEXT;
-    #[repr(C)]
-    pub struct DISPATCHER_CONTEXT;
+    // Fake definitions; these are actually complicated structs,
+    // but we don't use the contents here.
+    pub type EXCEPTION_RECORD = c_void;
+    pub type CONTEXT = c_void;
+    pub type DISPATCHER_CONTEXT = c_void;
 
     #[repr(C)]
     #[derive(Copy, Clone)]
@@ -266,7 +267,7 @@ pub mod eabi {
     }
 
     type _Unwind_Personality_Fn =
-        extern "C" fn(
+        extern fn(
             version: c_int,
             actions: uw::_Unwind_Action,
             exception_class: uw::_Unwind_Exception_Class,
@@ -274,7 +275,7 @@ pub mod eabi {
             context: *mut uw::_Unwind_Context
         ) -> uw::_Unwind_Reason_Code;
 
-    extern "C" {
+    extern {
         fn __gcc_personality_seh0(
             exceptionRecord: *mut EXCEPTION_RECORD,
             establisherFrame: *mut c_void,
@@ -291,10 +292,9 @@ pub mod eabi {
         ) -> EXCEPTION_DISPOSITION;
     }
 
-    #[lang="eh_personality"]
-    #[no_mangle] // referenced from rust_try.ll
-    #[allow(private_no_mangle_fns)]
-    extern "C" fn rust_eh_personality(
+    #[lang = "eh_personality"]
+    #[no_mangle]
+    extern fn rust_eh_personality(
         exceptionRecord: *mut EXCEPTION_RECORD,
         establisherFrame: *mut c_void,
         contextRecord: *mut CONTEXT,
@@ -307,15 +307,16 @@ pub mod eabi {
         }
     }
 
-    #[no_mangle] // referenced from rust_try.ll
-    pub extern "C" fn rust_eh_personality_catch(
+    #[cfg_attr(not(stage0), lang = "eh_personality_catch")]
+    #[no_mangle]
+    pub extern fn rust_eh_personality_catch(
         exceptionRecord: *mut EXCEPTION_RECORD,
         establisherFrame: *mut c_void,
         contextRecord: *mut CONTEXT,
         dispatcherContext: *mut DISPATCHER_CONTEXT
     ) -> EXCEPTION_DISPOSITION
     {
-        extern "C" fn inner(
+        extern fn inner(
                 _version: c_int,
                 actions: uw::_Unwind_Action,
                 _exception_class: uw::_Unwind_Exception_Class,
diff --git a/src/libstd/rt/unwind/mod.rs b/src/libstd/rt/unwind/mod.rs
index c403976745a..db2310ba361 100644
--- a/src/libstd/rt/unwind/mod.rs
+++ b/src/libstd/rt/unwind/mod.rs
@@ -69,7 +69,6 @@ use cmp;
 use panicking;
 use fmt;
 use intrinsics;
-use libc::c_void;
 use mem;
 use sync::atomic::{self, Ordering};
 use sys_common::mutex::Mutex;
@@ -127,7 +126,7 @@ extern {}
 ///   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 c_void);
+    return inner_try(try_fn::<F>, &mut f as *mut _ as *mut u8);
 
     // If an inner function were not used here, then this generic function `try`
     // uses the native symbol `rust_try`, for which the code is statically
@@ -140,11 +139,12 @@ pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
     // `dllexport`, but it's easier to not have conditional `src/rt/rust_try.ll`
     // files and instead just have this non-generic shim the compiler can take
     // care of exposing correctly.
-    unsafe fn inner_try(f: extern fn(*mut c_void), data: *mut c_void)
+    #[cfg(not(stage0))]
+    unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
                         -> Result<(), Box<Any + Send>> {
         let prev = PANICKING.with(|s| s.get());
         PANICKING.with(|s| s.set(false));
-        let ep = rust_try(f, data);
+        let ep = intrinsics::try(f, data);
         PANICKING.with(|s| s.set(prev));
         if ep.is_null() {
             Ok(())
@@ -152,8 +152,13 @@ pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
             Err(imp::cleanup(ep))
         }
     }
+    #[cfg(stage0)]
+    unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
+                        -> Result<(), Box<Any + Send>> {
+        Ok(f(data))
+    }
 
-    extern fn try_fn<F: FnOnce()>(opt_closure: *mut c_void) {
+    fn try_fn<F: FnOnce()>(opt_closure: *mut u8) {
         let opt_closure = opt_closure as *mut Option<F>;
         unsafe { (*opt_closure).take().unwrap()(); }
     }
@@ -163,8 +168,8 @@ pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
         // When f(...) returns normally, the return value is null.
         // When f(...) throws, the return value is a pointer to the caught
         // exception object.
-        fn rust_try(f: extern fn(*mut c_void),
-                    data: *mut c_void) -> *mut c_void;
+        fn rust_try(f: extern fn(*mut u8),
+                    data: *mut u8) -> *mut u8;
     }
 }
 
diff --git a/src/libstd/rt/unwind/seh.rs b/src/libstd/rt/unwind/seh.rs
index a72c1debe14..ed44f9a8bda 100644
--- a/src/libstd/rt/unwind/seh.rs
+++ b/src/libstd/rt/unwind/seh.rs
@@ -8,23 +8,137 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! Win64 SEH (see http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx)
+//!
+//! On Windows (currently only on MSVC), the default exception handling
+//! mechanism is Structured Exception Handling (SEH). This is quite different
+//! than Dwarf-based exception handling (e.g. what other unix platforms use) in
+//! terms of compiler internals, so LLVM is required to have a good deal of
+//! extra support for SEH. Currently this support is somewhat lacking, so what's
+//! here is the bare bones of SEH support.
+//!
+//! In a nutshell, what happens here is:
+//!
+//! 1. The `panic` function calls the standard Windows function `RaiseException`
+//!    with a Rust-specific code, triggering the unwinding process.
+//! 2. All landing pads generated by the compiler (just "cleanup" landing pads)
+//!    use the personality function `__C_specific_handler`, a function in the
+//!    CRT, and the unwinding code in Windows will use this personality function
+//!    to execute all cleanup code on the stack.
+//! 3. Eventually the "catch" code in `rust_try` (located in
+//!    src/rt/rust_try_msvc_64.ll) is executed, which will ensure that the
+//!    exception being caught is indeed a Rust exception, returning control back
+//!    into Rust.
+//!
+//! Some specific differences from the gcc-based exception handling are:
+//!
+//! * Rust has no custom personality function, it is instead *always*
+//!   __C_specific_handler, so the filtering is done in a C++-like manner
+//!   instead of in the personality function itself. Note that the specific
+//!   syntax for this (found in the rust_try_msvc_64.ll) is taken from an LLVM
+//!   test case for SEH.
+//! * We've got some data to transmit across the unwinding boundary,
+//!   specifically a `Box<Any + Send + 'static>`. In Dwarf-based unwinding this
+//!   data is part of the payload of the exception, but I have not currently
+//!   figured out how to do this with LLVM's bindings. Judging by some comments
+//!   in the LLVM test cases this may not even be possible currently with LLVM,
+//!   so this is just abandoned entirely. Instead the data is stored in a
+//!   thread-local in `panic` and retrieved during `cleanup`.
+//!
+//! So given all that, the bindings here are pretty small,
+
+#![allow(bad_style)]
+
 use prelude::v1::*;
 
 use any::Any;
-use intrinsics;
-use libc::c_void;
+use libc::{c_ulong, DWORD, c_void};
+use sys_common::thread_local::StaticKey;
+
+//                        0x R U S T
+const RUST_PANIC: DWORD = 0x52555354;
+static PANIC_DATA: StaticKey = StaticKey::new(None);
+
+// This function is provided by kernel32.dll
+extern "system" {
+    fn RaiseException(dwExceptionCode: DWORD,
+                      dwExceptionFlags: DWORD,
+                      nNumberOfArguments: DWORD,
+                      lpArguments: *const c_ulong);
+}
+
+#[repr(C)]
+pub struct EXCEPTION_POINTERS {
+    ExceptionRecord: *mut EXCEPTION_RECORD,
+    ContextRecord: *mut CONTEXT,
+}
+
+enum CONTEXT {}
+
+#[repr(C)]
+struct EXCEPTION_RECORD {
+    ExceptionCode: DWORD,
+    ExceptionFlags: DWORD,
+    ExceptionRecord: *mut _EXCEPTION_RECORD,
+    ExceptionAddress: *mut c_void,
+    NumberParameters: DWORD,
+    ExceptionInformation: [*mut c_ulong; EXCEPTION_MAXIMUM_PARAMETERS],
+}
 
-pub unsafe fn panic(_data: Box<Any + Send + 'static>) -> ! {
-    intrinsics::abort();
+enum _EXCEPTION_RECORD {}
+
+const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
+
+pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
+    // See module docs above for an explanation of why `data` is stored in a
+    // thread local instead of being passed as an argument to the
+    // `RaiseException` function (which can in theory carry along arbitrary
+    // data).
+    let exception = Box::new(data);
+    rtassert!(PANIC_DATA.get().is_null());
+    PANIC_DATA.set(Box::into_raw(exception) as *mut u8);
+
+    RaiseException(RUST_PANIC, 0, 0, 0 as *const _);
+    rtabort!("could not unwind stack");
 }
 
-pub unsafe fn cleanup(_ptr: *mut c_void) -> Box<Any + Send + 'static> {
-    intrinsics::abort();
+pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
+    // The `ptr` here actually corresponds to the code of the exception, and our
+    // real data is stored in our thread local.
+    rtassert!(ptr as DWORD == RUST_PANIC);
+
+    let data = PANIC_DATA.get() as *mut Box<Any + Send + 'static>;
+    PANIC_DATA.set(0 as *mut u8);
+    rtassert!(!data.is_null());
+
+    *Box::from_raw(data)
 }
 
+// This is required by the compiler to exist (e.g. it's a lang item), but it's
+// never actually called by the compiler because __C_specific_handler is the
+// personality function that is always used. Hence this is just an aborting
+// stub.
 #[lang = "eh_personality"]
-#[no_mangle]
-pub extern fn rust_eh_personality() {}
+fn rust_eh_personality() {
+    unsafe { ::intrinsics::abort() }
+}
 
+// This is a function referenced from `rust_try_msvc_64.ll` which is used to
+// filter the exceptions being caught by that function.
+//
+// In theory local variables can be accessed through the `rbp` parameter of this
+// function, but a comment in an LLVM test case indicates that this is not
+// implemented in LLVM, so this is just an idempotent function which doesn't
+// ferry along any other information.
+//
+// This function just takes a look at the current EXCEPTION_RECORD being thrown
+// to ensure that it's code is RUST_PANIC, which was set by the call to
+// `RaiseException` above in the `panic` function.
 #[no_mangle]
-pub extern fn rust_eh_personality_catch() {}
+#[lang = "msvc_try_filter"]
+pub extern fn __rust_try_filter(eh_ptrs: *mut EXCEPTION_POINTERS,
+                                _rbp: *mut u8) -> i32 {
+    unsafe {
+        ((*(*eh_ptrs).ExceptionRecord).ExceptionCode == RUST_PANIC) as i32
+    }
+}
diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs
index 04f36d99c8e..031fda089c8 100644
--- a/src/libstd/rt/util.rs
+++ b/src/libstd/rt/util.rs
@@ -13,7 +13,6 @@ use io::prelude::*;
 use env;
 use fmt;
 use intrinsics;
-use libc::uintptr_t;
 use sync::atomic::{self, Ordering};
 use sys::stdio::Stderr;
 
@@ -22,10 +21,18 @@ use sys::stdio::Stderr;
 /// can't run correctly un-altered. Valgrind is there to help
 /// you notice weirdness in normal, un-doctored code paths!
 pub fn running_on_valgrind() -> bool {
-    extern {
-        fn rust_running_on_valgrind() -> uintptr_t;
+    return on_valgrind();
+    #[cfg(windows)]
+    fn on_valgrind() -> bool { false }
+
+    #[cfg(unix)]
+    fn on_valgrind() -> bool {
+        use libc::uintptr_t;
+        extern {
+            fn rust_running_on_valgrind() -> uintptr_t;
+        }
+        unsafe { rust_running_on_valgrind() != 0 }
     }
-    unsafe { rust_running_on_valgrind() != 0 }
 }
 
 /// Valgrind has a fixed-sized array (size around 2000) of segment descriptors