about summary refs log tree commit diff
path: root/src/libstd/sys/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd/sys/common')
-rw-r--r--src/libstd/sys/common/libunwind.rs51
-rw-r--r--src/libstd/sys/common/unwind/gcc.rs33
-rw-r--r--src/libstd/sys/common/unwind/mod.rs41
-rw-r--r--src/libstd/sys/common/unwind/seh64_gnu.rs11
4 files changed, 81 insertions, 55 deletions
diff --git a/src/libstd/sys/common/libunwind.rs b/src/libstd/sys/common/libunwind.rs
index da7ebbf4ed3..75bb11216e1 100644
--- a/src/libstd/sys/common/libunwind.rs
+++ b/src/libstd/sys/common/libunwind.rs
@@ -99,35 +99,23 @@ pub type _Unwind_Exception_Cleanup_Fn =
         extern "C" fn(unwind_code: _Unwind_Reason_Code,
                       exception: *mut _Unwind_Exception);
 
-#[cfg(any(all(target_os = "linux", not(target_env = "musl")),
-          target_os = "freebsd"))]
-#[link(name = "gcc_s")]
-extern {}
-
-#[cfg(all(target_os = "linux", target_env = "musl", not(test)))]
-#[link(name = "unwind", kind = "static")]
-extern {}
-
-#[cfg(any(target_os = "android", target_os = "openbsd"))]
-#[link(name = "gcc")]
-extern {}
-
-#[cfg(all(target_os = "netbsd", not(target_vendor = "rumprun")))]
-#[link(name = "gcc")]
-extern {}
-
-#[cfg(all(target_os = "netbsd", target_vendor = "rumprun"))]
-#[link(name = "unwind")]
-extern {}
-
-#[cfg(target_os = "dragonfly")]
-#[link(name = "gcc_pic")]
-extern {}
-
-#[cfg(target_os = "bitrig")]
-#[link(name = "c++abi")]
-extern {}
-
+#[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")),
+               target_os = "freebsd"),
+           link(name = "gcc_s"))]
+#[cfg_attr(all(target_os = "linux", target_env = "musl", 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_...)
@@ -142,6 +130,11 @@ extern "C" {
                                    -> _Unwind_Reason_Code;
 
     pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
+
+    // remove cfg after new snapshot
+    #[cfg(not(all(stage0, target_os="windows", target_arch="x86_64")))]
+    #[unwind]
+    pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
 }
 
 // ... and now we just providing access to SjLj counterspart
diff --git a/src/libstd/sys/common/unwind/gcc.rs b/src/libstd/sys/common/unwind/gcc.rs
index 361cef08c11..0a598b55951 100644
--- a/src/libstd/sys/common/unwind/gcc.rs
+++ b/src/libstd/sys/common/unwind/gcc.rs
@@ -231,3 +231,36 @@ pub mod eabi {
         }
     }
 }
+
+// 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")]
+    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]
+    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]
+    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
index d87ab56d4e1..e455d163ed9 100644
--- a/src/libstd/sys/common/unwind/mod.rs
+++ b/src/libstd/sys/common/unwind/mod.rs
@@ -34,28 +34,35 @@
 //! object being thrown, and to decide whether it should be caught at that stack
 //! frame.  Once the handler frame has been identified, cleanup phase begins.
 //!
-//! In the cleanup phase, personality routines invoke cleanup code associated
-//! with their stack frames (i.e. destructors).  Once stack has been unwound down
-//! to the handler frame level, unwinding stops and the last personality routine
-//! transfers control to its catch block.
+//! 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.
 //!
-//! ## Frame unwind info registration
+//! Once stack has been unwound down to the handler frame level, unwinding stops
+//! and the last personality routine transfers control to the catch block.
 //!
-//! Each module has its own frame unwind info section (usually ".eh_frame"), and
-//! unwinder needs to know about all of them in order for unwinding to be able to
-//! cross module boundaries.
+//! ## `eh_personality` and `eh_unwind_resume`
 //!
-//! On some platforms, like Linux, this is achieved by dynamically enumerating
-//! currently loaded modules via the dl_iterate_phdr() API and finding all
-//! .eh_frame sections.
+//! 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.
 //!
-//! Others, like Windows, require modules to actively register their unwind info
-//! sections by calling __register_frame_info() API at startup.  In the latter
-//! case it is essential that there is only one copy of the unwinder runtime in
-//! the process.  This is usually achieved by linking to the dynamic version of
-//! the unwind runtime.
+//! ## Frame unwind info registration
 //!
-//! Currently Rust uses unwind runtime provided by libgcc.
+//! 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)]
diff --git a/src/libstd/sys/common/unwind/seh64_gnu.rs b/src/libstd/sys/common/unwind/seh64_gnu.rs
index 9478678fda9..92f059d68e1 100644
--- a/src/libstd/sys/common/unwind/seh64_gnu.rs
+++ b/src/libstd/sys/common/unwind/seh64_gnu.rs
@@ -190,17 +190,10 @@ unsafe extern fn rust_eh_personality(
     ExceptionContinueSearch
 }
 
-// The `resume` instruction, found at the end of the landing pads, and whose job
-// is to resume stack unwinding, is typically lowered by LLVM into a call to
-// `_Unwind_Resume` routine.  To avoid confusion with the same symbol exported
-// from libgcc, we redirect it to `rust_eh_unwind_resume`.
-// Since resolution of this symbol is done by the linker, `rust_eh_unwind_resume`
-// must be marked `pub` + `#[no_mangle]`.  (Can we make it a lang item?)
-
-#[lang = "eh_unwind_resume"]
 #[cfg(not(test))]
+#[lang = "eh_unwind_resume"]
 #[unwind]
-unsafe extern fn rust_eh_unwind_resume(panic_ctx: LPVOID) {
+unsafe extern fn rust_eh_unwind_resume(panic_ctx: LPVOID) -> ! {
     let params = [panic_ctx as ULONG_PTR];
     RaiseException(RUST_PANIC,
                    EXCEPTION_NONCONTINUABLE,