1 // Copyright 2015 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.
15 use rt
::libunwind
as uw
;
18 uwe
: uw
::_Unwind_Exception
,
19 cause
: Option
<Box
<Any
+ Send
+ '
static>>,
22 pub unsafe fn panic(data
: Box
<Any
+ Send
+ '
static>) -> ! {
23 let exception
: Box
<_
> = box Exception
{
24 uwe
: uw
::_Unwind_Exception
{
25 exception_class
: rust_exception_class(),
26 exception_cleanup
: exception_cleanup
,
27 private
: [0; uw
::unwinder_private_data_size
],
31 let exception_param
= Box
::into_raw(exception
) as *mut uw
::_Unwind_Exception
;
32 let error
= uw
::_Unwind_RaiseException(exception_param
);
33 rtabort
!("Could not unwind stack, error = {}", error
as isize);
35 extern fn exception_cleanup(_unwind_code
: uw
::_Unwind_Reason_Code
,
36 exception
: *mut uw
::_Unwind_Exception
) {
37 rtdebug
!("exception_cleanup()");
39 let _
: Box
<Exception
> = Box
::from_raw(exception
as *mut Exception
);
44 pub unsafe fn cleanup(ptr
: *mut c_void
) -> Box
<Any
+ Send
+ '
static> {
45 let my_ep
= ptr
as *mut Exception
;
46 rtdebug
!("caught {}", (*my_ep
).uwe
.exception_class
);
47 let cause
= (*my_ep
).cause
.take();
48 uw
::_Unwind_DeleteException(ptr
as *mut _
);
52 // Rust's exception class identifier. This is used by personality routines to
53 // determine whether the exception was thrown by their own runtime.
54 fn rust_exception_class() -> uw
::_Unwind_Exception_Class
{
55 // M O Z \0 R U S T -- vendor, language
59 // We could implement our personality routine in pure Rust, however exception
60 // info decoding is tedious. More importantly, personality routines have to
61 // handle various platform quirks, which are not fun to maintain. For this
62 // reason, we attempt to reuse personality routine of the C language:
63 // __gcc_personality_v0.
65 // Since C does not support exception catching, __gcc_personality_v0 simply
66 // always returns _URC_CONTINUE_UNWIND in search phase, and always returns
67 // _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
69 // This is pretty close to Rust's exception handling approach, except that Rust
70 // does have a single "catch-all" handler at the bottom of each thread's stack.
71 // So we have two versions of the personality routine:
72 // - rust_eh_personality, used by all cleanup landing pads, which never catches,
73 // so the behavior of __gcc_personality_v0 is perfectly adequate there, and
74 // - rust_eh_personality_catch, used only by rust_try(), which always catches.
76 // Note, however, that for implementation simplicity, rust_eh_personality_catch
77 // lacks code to install a landing pad, so in order to obtain exception object
78 // pointer (which it needs to return upstream), rust_try() employs another trick:
79 // it calls into the nested rust_try_inner(), whose landing pad does not resume
80 // unwinds. Instead, it extracts the exception pointer and performs a "normal"
83 // See also: rt/rust_try.ll
85 #[cfg(all(not(target_arch = "arm"),
86 not(all(windows
, target_arch
= "x86_64")),
89 use rt
::libunwind
as uw
;
93 fn __gcc_personality_v0(version
: c_int
,
94 actions
: uw
::_Unwind_Action
,
95 exception_class
: uw
::_Unwind_Exception_Class
,
96 ue_header
: *mut uw
::_Unwind_Exception
,
97 context
: *mut uw
::_Unwind_Context
)
98 -> uw
::_Unwind_Reason_Code
;
101 #[lang="eh_personality"]
102 #[no_mangle] // referenced from rust_try.ll
103 #[allow(private_no_mangle_fns)]
104 extern fn rust_eh_personality(
106 actions
: uw
::_Unwind_Action
,
107 exception_class
: uw
::_Unwind_Exception_Class
,
108 ue_header
: *mut uw
::_Unwind_Exception
,
109 context
: *mut uw
::_Unwind_Context
110 ) -> uw
::_Unwind_Reason_Code
113 __gcc_personality_v0(version
, actions
, exception_class
, ue_header
,
118 #[no_mangle] // referenced from rust_try.ll
119 pub extern "C" fn rust_eh_personality_catch(
121 actions
: uw
::_Unwind_Action
,
122 _exception_class
: uw
::_Unwind_Exception_Class
,
123 _ue_header
: *mut uw
::_Unwind_Exception
,
124 _context
: *mut uw
::_Unwind_Context
125 ) -> uw
::_Unwind_Reason_Code
128 if (actions
as c_int
& uw
::_UA_SEARCH_PHASE
as c_int
) != 0 { // search phase
129 uw
::_URC_HANDLER_FOUND
// catch!
131 else { // cleanup phase
132 uw
::_URC_INSTALL_CONTEXT
137 // iOS on armv7 is using SjLj exceptions and therefore requires to use
138 // a specialized personality routine: __gcc_personality_sj0
140 #[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
142 use rt
::libunwind
as uw
;
146 fn __gcc_personality_sj0(version
: c_int
,
147 actions
: uw
::_Unwind_Action
,
148 exception_class
: uw
::_Unwind_Exception_Class
,
149 ue_header
: *mut uw
::_Unwind_Exception
,
150 context
: *mut uw
::_Unwind_Context
)
151 -> uw
::_Unwind_Reason_Code
;
154 #[lang="eh_personality"]
155 #[no_mangle] // referenced from rust_try.ll
156 pub extern "C" fn rust_eh_personality(
158 actions
: uw
::_Unwind_Action
,
159 exception_class
: uw
::_Unwind_Exception_Class
,
160 ue_header
: *mut uw
::_Unwind_Exception
,
161 context
: *mut uw
::_Unwind_Context
162 ) -> uw
::_Unwind_Reason_Code
165 __gcc_personality_sj0(version
, actions
, exception_class
, ue_header
,
170 #[no_mangle] // referenced from rust_try.ll
171 pub extern "C" fn rust_eh_personality_catch(
173 actions
: uw
::_Unwind_Action
,
174 _exception_class
: uw
::_Unwind_Exception_Class
,
175 _ue_header
: *mut uw
::_Unwind_Exception
,
176 _context
: *mut uw
::_Unwind_Context
177 ) -> uw
::_Unwind_Reason_Code
179 if (actions
as c_int
& uw
::_UA_SEARCH_PHASE
as c_int
) != 0 { // search phase
180 uw
::_URC_HANDLER_FOUND
// catch!
182 else { // cleanup phase
184 __gcc_personality_sj0(_version
, actions
, _exception_class
, _ue_header
,
192 // ARM EHABI uses a slightly different personality routine signature,
193 // but otherwise works the same.
194 #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(test)))]
196 use rt
::libunwind
as uw
;
200 fn __gcc_personality_v0(state
: uw
::_Unwind_State
,
201 ue_header
: *mut uw
::_Unwind_Exception
,
202 context
: *mut uw
::_Unwind_Context
)
203 -> uw
::_Unwind_Reason_Code
;
206 #[lang="eh_personality"]
207 #[no_mangle] // referenced from rust_try.ll
208 #[allow(private_no_mangle_fns)]
209 extern "C" fn rust_eh_personality(
210 state
: uw
::_Unwind_State
,
211 ue_header
: *mut uw
::_Unwind_Exception
,
212 context
: *mut uw
::_Unwind_Context
213 ) -> uw
::_Unwind_Reason_Code
216 __gcc_personality_v0(state
, ue_header
, context
)
220 #[no_mangle] // referenced from rust_try.ll
221 pub extern "C" fn rust_eh_personality_catch(
222 state
: uw
::_Unwind_State
,
223 _ue_header
: *mut uw
::_Unwind_Exception
,
224 _context
: *mut uw
::_Unwind_Context
225 ) -> uw
::_Unwind_Reason_Code
227 if (state
as c_int
& uw
::_US_ACTION_MASK
as c_int
)
228 == uw
::_US_VIRTUAL_UNWIND_FRAME
as c_int
{ // search phase
229 uw
::_URC_HANDLER_FOUND
// catch!
231 else { // cleanup phase
232 uw
::_URC_INSTALL_CONTEXT
237 // Win64 SEH (see http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx)
239 // This looks a bit convoluted because rather than implementing a native SEH
240 // handler, GCC reuses the same personality routine as for the other
241 // architectures by wrapping it with an "API translator" layer
242 // (_GCC_specific_handler).
244 #[cfg(all(windows, target_arch = "x86_64", not(test)))]
246 #[allow(non_camel_case_types, non_snake_case)]
248 pub use self::EXCEPTION_DISPOSITION
::*;
249 use rt
::libunwind
as uw
;
250 use libc
::{c_void, c_int}
;
253 pub struct EXCEPTION_RECORD
;
257 pub struct DISPATCHER_CONTEXT
;
260 #[derive(Copy, Clone)]
261 pub enum EXCEPTION_DISPOSITION
{
262 ExceptionContinueExecution
,
263 ExceptionContinueSearch
,
264 ExceptionNestedException
,
265 ExceptionCollidedUnwind
268 type _Unwind_Personality_Fn
=
271 actions
: uw
::_Unwind_Action
,
272 exception_class
: uw
::_Unwind_Exception_Class
,
273 ue_header
: *mut uw
::_Unwind_Exception
,
274 context
: *mut uw
::_Unwind_Context
275 ) -> uw
::_Unwind_Reason_Code
;
278 fn __gcc_personality_seh0(
279 exceptionRecord
: *mut EXCEPTION_RECORD
,
280 establisherFrame
: *mut c_void
,
281 contextRecord
: *mut CONTEXT
,
282 dispatcherContext
: *mut DISPATCHER_CONTEXT
283 ) -> EXCEPTION_DISPOSITION
;
285 fn _GCC_specific_handler(
286 exceptionRecord
: *mut EXCEPTION_RECORD
,
287 establisherFrame
: *mut c_void
,
288 contextRecord
: *mut CONTEXT
,
289 dispatcherContext
: *mut DISPATCHER_CONTEXT
,
290 personality
: _Unwind_Personality_Fn
291 ) -> EXCEPTION_DISPOSITION
;
294 #[lang="eh_personality"]
295 #[no_mangle] // referenced from rust_try.ll
296 #[allow(private_no_mangle_fns)]
297 extern "C" fn rust_eh_personality(
298 exceptionRecord
: *mut EXCEPTION_RECORD
,
299 establisherFrame
: *mut c_void
,
300 contextRecord
: *mut CONTEXT
,
301 dispatcherContext
: *mut DISPATCHER_CONTEXT
302 ) -> EXCEPTION_DISPOSITION
305 __gcc_personality_seh0(exceptionRecord
, establisherFrame
,
306 contextRecord
, dispatcherContext
)
310 #[no_mangle] // referenced from rust_try.ll
311 pub extern "C" fn rust_eh_personality_catch(
312 exceptionRecord
: *mut EXCEPTION_RECORD
,
313 establisherFrame
: *mut c_void
,
314 contextRecord
: *mut CONTEXT
,
315 dispatcherContext
: *mut DISPATCHER_CONTEXT
316 ) -> EXCEPTION_DISPOSITION
320 actions
: uw
::_Unwind_Action
,
321 _exception_class
: uw
::_Unwind_Exception_Class
,
322 _ue_header
: *mut uw
::_Unwind_Exception
,
323 _context
: *mut uw
::_Unwind_Context
324 ) -> uw
::_Unwind_Reason_Code
326 if (actions
as c_int
& uw
::_UA_SEARCH_PHASE
as c_int
) != 0 { // search phase
327 uw
::_URC_HANDLER_FOUND
// catch!
329 else { // cleanup phase
330 uw
::_URC_INSTALL_CONTEXT
335 _GCC_specific_handler(exceptionRecord
, establisherFrame
,
336 contextRecord
, dispatcherContext
,