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.
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.
13 // Implementation of Rust stack unwinding
15 // For background on exception handling and stack unwinding please see
16 // "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
17 // documents linked from it.
18 // These are also good reads:
19 // http://theofilos.cs.columbia.edu/blog/2013/09/22/base_abi/
20 // http://monoinfinito.wordpress.com/series/exception-handling-in-c/
21 // http://www.airs.com/blog/index.php?s=exception+frames
23 // ~~~ A brief summary ~~~
24 // Exception handling happens in two phases: a search phase and a cleanup phase.
26 // In both phases the unwinder walks stack frames from top to bottom using
27 // information from the stack frame unwind sections of the current process's
28 // modules ("module" here refers to an OS module, i.e. an executable or a
31 // For each stack frame, it invokes the associated "personality routine", whose
32 // address is also stored in the unwind info section.
34 // In the search phase, the job of a personality routine is to examine exception
35 // object being thrown, and to decide whether it should be caught at that stack
36 // frame. Once the handler frame has been identified, cleanup phase begins.
38 // In the cleanup phase, personality routines invoke cleanup code associated
39 // with their stack frames (i.e. destructors). Once stack has been unwound down
40 // to the handler frame level, unwinding stops and the last personality routine
41 // transfers control to its' catch block.
43 // ~~~ Frame unwind info registration ~~~
44 // Each module has its' own frame unwind info section (usually ".eh_frame"), and
45 // unwinder needs to know about all of them in order for unwinding to be able to
46 // cross module boundaries.
48 // On some platforms, like Linux, this is achieved by dynamically enumerating
49 // currently loaded modules via the dl_iterate_phdr() API and finding all
50 // .eh_frame sections.
52 // Others, like Windows, require modules to actively register their unwind info
53 // sections by calling __register_frame_info() API at startup. In the latter
54 // case it is essential that there is only one copy of the unwinder runtime in
55 // the process. This is usually achieved by linking to the dynamic version of
56 // the unwind runtime.
58 // Currently Rust uses unwind runtime provided by libgcc.
60 use any::{Any, AnyRefExt};
66 use option::{Some, None, Option};
69 use result::{Err, Ok};
77 use uw = rt::libunwind;
81 cause: Option<~Any:Send>
85 pub fn new() -> Unwinder {
92 pub fn unwinding(&self) -> bool {
96 pub fn try(&mut self, f: ||) {
101 let closure: Closure = cast::transmute(f);
102 let ep = rust_try(try_fn, closure.code as *c_void,
103 closure.env as *c_void);
105 rtdebug!("caught {}", (*ep).exception_class);
106 uw::_Unwind_DeleteException(ep);
110 extern fn try_fn(code: *c_void, env: *c_void) {
112 let closure: || = cast::transmute(Closure {
122 // When f(...) returns normally, the return value is null.
123 // When f(...) throws, the return value is a pointer to the caught
125 fn rust_try(f: extern "C" fn(*c_void, *c_void),
127 data: *c_void) -> *uw::_Unwind_Exception;
131 pub fn begin_unwind(&mut self, cause: ~Any:Send) -> ! {
132 rtdebug!("begin_unwind()");
134 self.unwinding = true;
135 self.cause = Some(cause);
139 // An uninlined, unmangled function upon which to slap yer breakpoints
142 fn rust_fail() -> ! {
144 let exception = box uw::_Unwind_Exception {
145 exception_class: rust_exception_class(),
146 exception_cleanup: exception_cleanup,
147 private: [0, ..uw::unwinder_private_data_size],
149 let error = uw::_Unwind_RaiseException(cast::transmute(exception));
150 rtabort!("Could not unwind stack, error = {}", error as int)
153 extern "C" fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
154 exception: *uw::_Unwind_Exception) {
155 rtdebug!("exception_cleanup()");
157 let _: ~uw::_Unwind_Exception = cast::transmute(exception);
163 pub fn result(&mut self) -> TaskResult {
165 Err(self.cause.take().unwrap())
172 // Rust's exception class identifier. This is used by personality routines to
173 // determine whether the exception was thrown by their own runtime.
174 fn rust_exception_class() -> uw::_Unwind_Exception_Class {
175 // M O Z \0 R U S T -- vendor, language
179 // We could implement our personality routine in pure Rust, however exception
180 // info decoding is tedious. More importantly, personality routines have to
181 // handle various platform quirks, which are not fun to maintain. For this
182 // reason, we attempt to reuse personality routine of the C language:
183 // __gcc_personality_v0.
185 // Since C does not support exception catching, __gcc_personality_v0 simply
186 // always returns _URC_CONTINUE_UNWIND in search phase, and always returns
187 // _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
189 // This is pretty close to Rust's exception handling approach, except that Rust
190 // does have a single "catch-all" handler at the bottom of each task's stack.
191 // So we have two versions:
192 // - rust_eh_personality, used by all cleanup landing pads, which never catches,
193 // so the behavior of __gcc_personality_v0 is perfectly adequate there, and
194 // - rust_eh_personality_catch, used only by rust_try(), which always catches.
195 // This is achieved by overriding the return value in search phase to always
198 #[cfg(not(target_arch = "arm"), not(test))]
200 #[allow(visible_private_types)]
202 use uw = rt::libunwind;
206 fn __gcc_personality_v0(version: c_int,
207 actions: uw::_Unwind_Action,
208 exception_class: uw::_Unwind_Exception_Class,
209 ue_header: *uw::_Unwind_Exception,
210 context: *uw::_Unwind_Context)
211 -> uw::_Unwind_Reason_Code;
214 #[lang="eh_personality"]
215 #[no_mangle] // so we can reference it by name from middle/trans/base.rs
216 pub extern "C" fn rust_eh_personality(
218 actions: uw::_Unwind_Action,
219 exception_class: uw::_Unwind_Exception_Class,
220 ue_header: *uw::_Unwind_Exception,
221 context: *uw::_Unwind_Context
222 ) -> uw::_Unwind_Reason_Code
225 __gcc_personality_v0(version, actions, exception_class, ue_header,
230 #[no_mangle] // referenced from rust_try.ll
231 pub extern "C" fn rust_eh_personality_catch(
233 actions: uw::_Unwind_Action,
234 exception_class: uw::_Unwind_Exception_Class,
235 ue_header: *uw::_Unwind_Exception,
236 context: *uw::_Unwind_Context
237 ) -> uw::_Unwind_Reason_Code
239 if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
240 uw::_URC_HANDLER_FOUND // catch!
242 else { // cleanup phase
244 __gcc_personality_v0(version, actions, exception_class, ue_header,
251 // ARM EHABI uses a slightly different personality routine signature,
252 // but otherwise works the same.
253 #[cfg(target_arch = "arm", not(test))]
254 #[allow(visible_private_types)]
256 use uw = rt::libunwind;
260 fn __gcc_personality_v0(state: uw::_Unwind_State,
261 ue_header: *uw::_Unwind_Exception,
262 context: *uw::_Unwind_Context)
263 -> uw::_Unwind_Reason_Code;
266 #[lang="eh_personality"]
267 #[no_mangle] // so we can reference it by name from middle/trans/base.rs
268 pub extern "C" fn rust_eh_personality(
269 state: uw::_Unwind_State,
270 ue_header: *uw::_Unwind_Exception,
271 context: *uw::_Unwind_Context
272 ) -> uw::_Unwind_Reason_Code
275 __gcc_personality_v0(state, ue_header, context)
279 #[no_mangle] // referenced from rust_try.ll
280 pub extern "C" fn rust_eh_personality_catch(
281 state: uw::_Unwind_State,
282 ue_header: *uw::_Unwind_Exception,
283 context: *uw::_Unwind_Context
284 ) -> uw::_Unwind_Reason_Code
286 if (state as c_int & uw::_US_ACTION_MASK as c_int)
287 == uw::_US_VIRTUAL_UNWIND_FRAME as c_int { // search phase
288 uw::_URC_HANDLER_FOUND // catch!
290 else { // cleanup phase
292 __gcc_personality_v0(state, ue_header, context)
301 pub fn fail_(expr: *u8, file: *u8, line: uint) -> ! {
302 begin_unwind_raw(expr, file, line);
306 #[lang="fail_bounds_check"]
308 pub fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) -> ! {
311 let msg = format!("index out of bounds: the len is {} but the index is {}",
312 len as uint, index as uint);
313 msg.with_c_str(|buf| fail_(buf as *u8, file, line))
316 /// This is the entry point of unwinding for things like lang items and such.
317 /// The arguments are normally generated by the compiler, and need to
318 /// have static lifetimes.
319 #[inline(never)] #[cold] // this is the slow path, please never inline this
320 pub fn begin_unwind_raw(msg: *u8, file: *u8, line: uint) -> ! {
323 fn static_char_ptr(p: *u8) -> &'static str {
324 let s = unsafe { CString::new(p as *c_char, false) };
326 Some(s) => unsafe { cast::transmute::<&str, &'static str>(s) },
327 None => rtabort!("message wasn't utf8?")
331 let msg = static_char_ptr(msg);
332 let file = static_char_ptr(file);
334 begin_unwind(msg, file, line as uint)
337 /// The entry point for unwinding with a formatted message.
339 /// This is designed to reduce the amount of code required at the call
340 /// site as much as possible (so that `fail!()` has as low an impact
341 /// on (e.g.) the inlining of other functions as possible), by moving
342 /// the actual formatting into this shared place.
343 #[inline(never)] #[cold]
344 pub fn begin_unwind_fmt(msg: &fmt::Arguments, file: &'static str, line: uint) -> ! {
345 // We do two allocations here, unfortunately. But (a) they're
346 // required with the current scheme, and (b) we don't handle
347 // failure + OOM properly anyway (see comment in begin_unwind
349 begin_unwind_inner(box fmt::format(msg), file, line)
352 /// This is the entry point of unwinding for fail!() and assert!().
353 #[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
354 pub fn begin_unwind<M: Any + Send>(msg: M, file: &'static str, line: uint) -> ! {
355 // Note that this should be the only allocation performed in this code path.
356 // Currently this means that fail!() on OOM will invoke this code path,
357 // but then again we're not really ready for failing on OOM anyway. If
358 // we do start doing this, then we should propagate this allocation to
359 // be performed in the parent of this task instead of the task that's
362 // see below for why we do the `Any` coercion here.
363 begin_unwind_inner(box msg, file, line)
367 /// The core of the unwinding.
369 /// This is non-generic to avoid instantiation bloat in other crates
370 /// (which makes compilation of small crates noticably slower). (Note:
371 /// we need the `Any` object anyway, we're not just creating it to
372 /// avoid being generic.)
374 /// Do this split took the LLVM IR line counts of `fn main() { fail!()
375 /// }` from ~1900/3700 (-O/no opts) to 180/590.
376 #[inline(never)] #[cold] // this is the slow path, please never inline this
377 fn begin_unwind_inner(msg: ~Any:Send, file: &'static str, line: uint) -> ! {
380 let msg_s = match msg.as_ref::<&'static str>() {
382 None => match msg.as_ref::<~str>() {
383 Some(s) => s.as_slice(),
388 // It is assumed that all reasonable rust code will have a local task at
389 // all times. This means that this `try_take` will succeed almost all of
390 // the time. There are border cases, however, when the runtime has
391 // *almost* set up the local task, but hasn't quite gotten there yet. In
392 // order to get some better diagnostics, we print on failure and
393 // immediately abort the whole process if there is no local task
395 let opt_task: Option<~Task> = Local::try_take();
396 task = match opt_task {
399 rterrln!("failed at '{}', {}:{}", msg_s, file, line);
400 if backtrace::log_enabled() {
401 let mut err = ::rt::util::Stderr;
402 let _err = backtrace::write(&mut err);
404 rterrln!("run with `RUST_BACKTRACE=1` to see a backtrace");
406 unsafe { intrinsics::abort() }
410 // See comments in io::stdio::with_task_stdout as to why we have to be
411 // careful when using an arbitrary I/O handle from the task. We
412 // essentially need to dance to make sure when a task is in TLS when
413 // running user code.
414 let name = task.name.take();
416 let n = name.as_ref().map(|n| n.as_slice()).unwrap_or("<unnamed>");
418 match task.stderr.take() {
419 Some(mut stderr) => {
421 // FIXME: what to do when the task printing fails?
422 let _err = format_args!(|args| ::fmt::writeln(stderr, args),
423 "task '{}' failed at '{}', {}:{}",
424 n, msg_s, file, line);
425 if backtrace::log_enabled() {
426 let _err = backtrace::write(stderr);
428 task = Local::take();
430 match mem::replace(&mut task.stderr, Some(stderr)) {
434 task = Local::take();
440 rterrln!("task '{}' failed at '{}', {}:{}", n, msg_s,
442 if backtrace::log_enabled() {
443 let mut err = ::rt::util::Stderr;
444 let _err = backtrace::write(&mut err);
451 if task.unwinder.unwinding {
452 // If a task fails while it's already unwinding then we
453 // have limited options. Currently our preference is to
454 // just abort. In the future we may consider resuming
455 // unwinding or otherwise exiting the task cleanly.
456 rterrln!("task failed during unwinding (double-failure - total drag!)")
457 rterrln!("rust must abort now. so sorry.");
459 // Don't print the backtrace twice (it would have already been
460 // printed if logging was enabled).
461 if !backtrace::log_enabled() {
462 let mut err = ::rt::util::Stderr;
463 let _err = backtrace::write(&mut err);
465 unsafe { intrinsics::abort() }
469 // The unwinder won't actually use the task at all, so we put the task back
470 // into TLS right before we invoke the unwinder, but this means we need an
471 // unsafe reference back to the unwinder once it's in TLS.
474 let task: *mut Task = Local::unsafe_borrow();
475 (*task).unwinder.begin_unwind(msg);