]> git.proxmox.com Git - rustc.git/blame - src/libstd/sys/common/unwind/mod.rs
Imported Upstream version 1.6.0+dfsg1
[rustc.git] / src / libstd / sys / common / unwind / mod.rs
CommitLineData
62682a34
SL
1// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! Implementation of Rust stack unwinding
12//!
13//! For background on exception handling and stack unwinding please see
14//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
15//! documents linked from it.
16//! These are also good reads:
c1a9b12d 17//! http://mentorembedded.github.io/cxx-abi/abi-eh.html
62682a34
SL
18//! http://monoinfinito.wordpress.com/series/exception-handling-in-c/
19//! http://www.airs.com/blog/index.php?s=exception+frames
20//!
21//! ## A brief summary
22//!
23//! Exception handling happens in two phases: a search phase and a cleanup phase.
24//!
25//! In both phases the unwinder walks stack frames from top to bottom using
26//! information from the stack frame unwind sections of the current process's
27//! modules ("module" here refers to an OS module, i.e. an executable or a
28//! dynamic library).
29//!
30//! For each stack frame, it invokes the associated "personality routine", whose
31//! address is also stored in the unwind info section.
32//!
33//! In the search phase, the job of a personality routine is to examine exception
34//! object being thrown, and to decide whether it should be caught at that stack
35//! frame. Once the handler frame has been identified, cleanup phase begins.
36//!
92a42be0
SL
37//! In the cleanup phase, the unwinder invokes each personality routine again.
38//! This time it decides which (if any) cleanup code needs to be run for
39//! the current stack frame. If so, the control is transferred to a special branch
40//! in the function body, the "landing pad", which invokes destructors, frees memory,
41//! etc. At the end of the landing pad, control is transferred back to the unwinder
42//! and unwinding resumes.
62682a34 43//!
92a42be0
SL
44//! Once stack has been unwound down to the handler frame level, unwinding stops
45//! and the last personality routine transfers control to the catch block.
62682a34 46//!
92a42be0 47//! ## `eh_personality` and `eh_unwind_resume`
62682a34 48//!
92a42be0
SL
49//! These language items are used by the compiler when generating unwind info.
50//! The first one is the personality routine described above. The second one
51//! allows compilation target to customize the process of resuming unwind at the
52//! end of the landing pads. `eh_unwind_resume` is used only if `custom_unwind_resume`
53//! flag in the target options is set.
62682a34 54//!
92a42be0 55//! ## Frame unwind info registration
62682a34 56//!
92a42be0
SL
57//! Each module's image contains a frame unwind info section (usually ".eh_frame").
58//! When a module is loaded/unloaded into the process, the unwinder must be informed
59//! about the location of this section in memory. The methods of achieving that vary
60//! by the platform.
61//! On some (e.g. Linux), the unwinder can discover unwind info sections on its own
62//! (by dynamically enumerating currently loaded modules via the dl_iterate_phdr() API
63//! and finding their ".eh_frame" sections);
64//! Others, like Windows, require modules to actively register their unwind info
65//! sections via unwinder API (see `rust_eh_register_frames`/`rust_eh_unregister_frames`).
62682a34
SL
66
67#![allow(dead_code)]
68#![allow(unused_imports)]
69
70use prelude::v1::*;
71
72use any::Any;
73use boxed;
62682a34 74use cmp;
b039eaaf 75use panicking::{self,PANIC_COUNT};
62682a34
SL
76use fmt;
77use intrinsics;
62682a34
SL
78use mem;
79use sync::atomic::{self, Ordering};
80use sys_common::mutex::Mutex;
81
82// The actual unwinding implementation is cfg'd here, and we've got two current
83// implementations. One goes through SEH on Windows and the other goes through
84// libgcc via the libunwind-like API.
c1a9b12d 85
e9174d1e
SL
86// i686-pc-windows-msvc
87#[cfg(all(windows, target_arch = "x86", target_env = "msvc"))]
c1a9b12d
SL
88#[path = "seh.rs"] #[doc(hidden)]
89pub mod imp;
90
b039eaaf
SL
91// stage0: i686-pc-windows-gnu
92#[cfg(all(stage0, windows, target_arch = "x86_64", target_env = "gnu"))]
93#[path = "seh64_gnu.rs"] #[doc(hidden)]
94pub mod imp;
95
96// stage0: x86_64-pc-windows-msvc
97#[cfg(all(stage0, windows, target_arch = "x86_64", target_env = "msvc"))]
98#[path = "seh.rs"] #[doc(hidden)]
99pub mod imp;
100
e9174d1e 101// x86_64-pc-windows-*
b039eaaf 102#[cfg(all(not(stage0), windows, target_arch = "x86_64"))]
c1a9b12d 103#[path = "seh64_gnu.rs"] #[doc(hidden)]
62682a34 104pub mod imp;
c1a9b12d
SL
105
106// i686-pc-windows-gnu and all others
e9174d1e 107#[cfg(any(unix, all(windows, target_arch = "x86", target_env = "gnu")))]
c1a9b12d 108#[path = "gcc.rs"] #[doc(hidden)]
62682a34
SL
109pub mod imp;
110
62682a34
SL
111/// Invoke a closure, capturing the cause of panic if one occurs.
112///
113/// This function will return `Ok(())` if the closure did not panic, and will
114/// return `Err(cause)` if the closure panics. The `cause` returned is the
115/// object with which panic was originally invoked.
116///
117/// This function also is unsafe for a variety of reasons:
118///
119/// * This is not safe to call in a nested fashion. The unwinding
120/// interface for Rust is designed to have at most one try/catch block per
121/// thread, not multiple. No runtime checking is currently performed to uphold
122/// this invariant, so this function is not safe. A nested try/catch block
123/// may result in corruption of the outer try/catch block's state, especially
124/// if this is used within a thread itself.
125///
126/// * It is not sound to trigger unwinding while already unwinding. Rust threads
127/// have runtime checks in place to ensure this invariant, but it is not
128/// guaranteed that a rust thread is in place when invoking this function.
129/// Unwinding twice can lead to resource leaks where some destructors are not
130/// run.
131pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
132 let mut f = Some(f);
c1a9b12d 133 return inner_try(try_fn::<F>, &mut f as *mut _ as *mut u8);
62682a34
SL
134
135 // If an inner function were not used here, then this generic function `try`
136 // uses the native symbol `rust_try`, for which the code is statically
137 // linked into the standard library. This means that the DLL for the
138 // standard library must have `rust_try` as an exposed symbol that
139 // downstream crates can link against (because monomorphizations of `try` in
140 // downstream crates will have a reference to the `rust_try` symbol).
141 //
142 // On MSVC this requires the symbol `rust_try` to be tagged with
143 // `dllexport`, but it's easier to not have conditional `src/rt/rust_try.ll`
144 // files and instead just have this non-generic shim the compiler can take
145 // care of exposing correctly.
c1a9b12d 146 unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
62682a34 147 -> Result<(), Box<Any + Send>> {
b039eaaf
SL
148 PANIC_COUNT.with(|s| {
149 let prev = s.get();
150 s.set(0);
151 let ep = intrinsics::try(f, data);
152 s.set(prev);
153 if ep.is_null() {
154 Ok(())
155 } else {
156 Err(imp::cleanup(ep))
157 }
158 })
62682a34
SL
159 }
160
c1a9b12d 161 fn try_fn<F: FnOnce()>(opt_closure: *mut u8) {
62682a34
SL
162 let opt_closure = opt_closure as *mut Option<F>;
163 unsafe { (*opt_closure).take().unwrap()(); }
164 }
165
166 extern {
167 // Rust's try-catch
168 // When f(...) returns normally, the return value is null.
169 // When f(...) throws, the return value is a pointer to the caught
170 // exception object.
c1a9b12d
SL
171 fn rust_try(f: extern fn(*mut u8),
172 data: *mut u8) -> *mut u8;
62682a34
SL
173 }
174}
175
176/// Determines whether the current thread is unwinding because of panic.
177pub fn panicking() -> bool {
b039eaaf 178 PANIC_COUNT.with(|s| s.get() != 0)
62682a34
SL
179}
180
181// An uninlined, unmangled function upon which to slap yer breakpoints
182#[inline(never)]
183#[no_mangle]
184#[allow(private_no_mangle_fns)]
185fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
62682a34
SL
186 unsafe {
187 imp::panic(cause)
188 }
189}
190
191#[cfg(not(test))]
192/// Entry point of panic from the libcore crate.
193#[lang = "panic_fmt"]
e9174d1e 194#[unwind]
62682a34
SL
195pub extern fn rust_begin_unwind(msg: fmt::Arguments,
196 file: &'static str, line: u32) -> ! {
197 begin_unwind_fmt(msg, &(file, line))
198}
199
200/// The entry point for unwinding with a formatted message.
201///
202/// This is designed to reduce the amount of code required at the call
203/// site as much as possible (so that `panic!()` has as low an impact
204/// on (e.g.) the inlining of other functions as possible), by moving
205/// the actual formatting into this shared place.
92a42be0
SL
206#[unstable(feature = "libstd_sys_internals",
207 reason = "used by the panic! macro",
208 issue = "0")]
62682a34
SL
209#[inline(never)] #[cold]
210pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, u32)) -> ! {
211 use fmt::Write;
212
213 // We do two allocations here, unfortunately. But (a) they're
214 // required with the current scheme, and (b) we don't handle
215 // panic + OOM properly anyway (see comment in begin_unwind
216 // below).
217
218 let mut s = String::new();
219 let _ = s.write_fmt(msg);
220 begin_unwind_inner(Box::new(s), file_line)
221}
222
223/// This is the entry point of unwinding for panic!() and assert!().
92a42be0
SL
224#[unstable(feature = "libstd_sys_internals",
225 reason = "used by the panic! macro",
226 issue = "0")]
62682a34
SL
227#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
228pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, u32)) -> ! {
229 // Note that this should be the only allocation performed in this code path.
230 // Currently this means that panic!() on OOM will invoke this code path,
231 // but then again we're not really ready for panic on OOM anyway. If
232 // we do start doing this, then we should propagate this allocation to
233 // be performed in the parent of this thread instead of the thread that's
234 // panicking.
235
236 // see below for why we do the `Any` coercion here.
237 begin_unwind_inner(Box::new(msg), file_line)
238}
239
240/// The core of the unwinding.
241///
242/// This is non-generic to avoid instantiation bloat in other crates
243/// (which makes compilation of small crates noticeably slower). (Note:
244/// we need the `Any` object anyway, we're not just creating it to
245/// avoid being generic.)
246///
247/// Doing this split took the LLVM IR line counts of `fn main() { panic!()
248/// }` from ~1900/3700 (-O/no opts) to 180/590.
249#[inline(never)] #[cold] // this is the slow path, please never inline this
250fn begin_unwind_inner(msg: Box<Any + Send>,
251 file_line: &(&'static str, u32)) -> ! {
b039eaaf 252 let (file, line) = *file_line;
62682a34 253
b039eaaf
SL
254 // First, invoke the default panic handler.
255 panicking::on_panic(&*msg, file, line);
62682a34 256
b039eaaf 257 // Finally, perform the unwinding.
62682a34
SL
258 rust_panic(msg);
259}