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.
11 #![allow(private_no_mangle_fns)]
16 use sys_common
::libunwind
as uw
;
19 uwe
: uw
::_Unwind_Exception
,
20 cause
: Option
<Box
<Any
+ Send
+ '
static>>,
23 pub unsafe fn panic(data
: Box
<Any
+ Send
+ '
static>) -> ! {
24 let exception
: Box
<_
> = box Exception
{
25 uwe
: uw
::_Unwind_Exception
{
26 exception_class
: rust_exception_class(),
27 exception_cleanup
: exception_cleanup
,
28 private
: [0; uw
::unwinder_private_data_size
],
32 let exception_param
= Box
::into_raw(exception
) as *mut uw
::_Unwind_Exception
;
33 let error
= uw
::_Unwind_RaiseException(exception_param
);
34 rtabort
!("Could not unwind stack, error = {}", error
as isize);
36 extern fn exception_cleanup(_unwind_code
: uw
::_Unwind_Reason_Code
,
37 exception
: *mut uw
::_Unwind_Exception
) {
39 let _
: Box
<Exception
> = Box
::from_raw(exception
as *mut Exception
);
44 pub fn payload() -> *mut u8 {
48 pub unsafe fn cleanup(ptr
: *mut u8) -> Box
<Any
+ Send
+ '
static> {
49 let my_ep
= ptr
as *mut Exception
;
50 let cause
= (*my_ep
).cause
.take();
51 uw
::_Unwind_DeleteException(ptr
as *mut _
);
55 // Rust's exception class identifier. This is used by personality routines to
56 // determine whether the exception was thrown by their own runtime.
57 fn rust_exception_class() -> uw
::_Unwind_Exception_Class
{
58 // M O Z \0 R U S T -- vendor, language
62 // We could implement our personality routine in pure Rust, however exception
63 // info decoding is tedious. More importantly, personality routines have to
64 // handle various platform quirks, which are not fun to maintain. For this
65 // reason, we attempt to reuse personality routine of the C language:
66 // __gcc_personality_v0.
68 // Since C does not support exception catching, __gcc_personality_v0 simply
69 // always returns _URC_CONTINUE_UNWIND in search phase, and always returns
70 // _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
72 // This is pretty close to Rust's exception handling approach, except that Rust
73 // does have a single "catch-all" handler at the bottom of each thread's stack.
74 // So we have two versions of the personality routine:
75 // - rust_eh_personality, used by all cleanup landing pads, which never catches,
76 // so the behavior of __gcc_personality_v0 is perfectly adequate there, and
77 // - rust_eh_personality_catch, used only by rust_try(), which always catches.
79 // See also: rustc_trans::trans::intrinsic::trans_gnu_try
81 #[cfg(all(not(target_arch = "arm"),
82 not(all(windows
, target_arch
= "x86_64")),
85 use sys_common
::libunwind
as uw
;
89 fn __gcc_personality_v0(version
: c_int
,
90 actions
: uw
::_Unwind_Action
,
91 exception_class
: uw
::_Unwind_Exception_Class
,
92 ue_header
: *mut uw
::_Unwind_Exception
,
93 context
: *mut uw
::_Unwind_Context
)
94 -> uw
::_Unwind_Reason_Code
;
97 #[lang = "eh_personality"]
99 extern fn rust_eh_personality(
101 actions
: uw
::_Unwind_Action
,
102 exception_class
: uw
::_Unwind_Exception_Class
,
103 ue_header
: *mut uw
::_Unwind_Exception
,
104 context
: *mut uw
::_Unwind_Context
105 ) -> uw
::_Unwind_Reason_Code
108 __gcc_personality_v0(version
, actions
, exception_class
, ue_header
,
113 #[lang = "eh_personality_catch"]
115 pub extern fn rust_eh_personality_catch(
117 actions
: uw
::_Unwind_Action
,
118 exception_class
: uw
::_Unwind_Exception_Class
,
119 ue_header
: *mut uw
::_Unwind_Exception
,
120 context
: *mut uw
::_Unwind_Context
121 ) -> uw
::_Unwind_Reason_Code
124 if (actions
as c_int
& uw
::_UA_SEARCH_PHASE
as c_int
) != 0 { // search phase
125 uw
::_URC_HANDLER_FOUND
// catch!
127 else { // cleanup phase
129 __gcc_personality_v0(version
, actions
, exception_class
, ue_header
,
136 // iOS on armv7 is using SjLj exceptions and therefore requires to use
137 // a specialized personality routine: __gcc_personality_sj0
139 #[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
141 use sys_common
::libunwind
as uw
;
145 fn __gcc_personality_sj0(version
: c_int
,
146 actions
: uw
::_Unwind_Action
,
147 exception_class
: uw
::_Unwind_Exception_Class
,
148 ue_header
: *mut uw
::_Unwind_Exception
,
149 context
: *mut uw
::_Unwind_Context
)
150 -> uw
::_Unwind_Reason_Code
;
153 #[lang = "eh_personality"]
155 pub extern fn rust_eh_personality(
157 actions
: uw
::_Unwind_Action
,
158 exception_class
: uw
::_Unwind_Exception_Class
,
159 ue_header
: *mut uw
::_Unwind_Exception
,
160 context
: *mut uw
::_Unwind_Context
161 ) -> uw
::_Unwind_Reason_Code
164 __gcc_personality_sj0(version
, actions
, exception_class
, ue_header
,
169 #[lang = "eh_personality_catch"]
171 pub extern 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 sys_common
::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"]
208 extern fn rust_eh_personality(
209 state
: uw
::_Unwind_State
,
210 ue_header
: *mut uw
::_Unwind_Exception
,
211 context
: *mut uw
::_Unwind_Context
212 ) -> uw
::_Unwind_Reason_Code
215 __gcc_personality_v0(state
, ue_header
, context
)
219 #[lang = "eh_personality_catch"]
221 pub extern 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 // Backtraces on ARM will call the personality routine with
228 // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
229 // we want to continue unwinding the stack, otherwise all our backtraces
230 // would end at __rust_try.
231 if (state
as c_int
& uw
::_US_ACTION_MASK
as c_int
)
232 == uw
::_US_VIRTUAL_UNWIND_FRAME
as c_int
233 && (state
as c_int
& uw
::_US_FORCE_UNWIND
as c_int
) == 0 { // search phase
234 uw
::_URC_HANDLER_FOUND
// catch!
236 else { // cleanup phase
238 __gcc_personality_v0(state
, ue_header
, context
)
244 // See docs in the `unwind` module.
245 #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu", not(test)))]
246 #[lang = "eh_unwind_resume"]
248 unsafe extern fn rust_eh_unwind_resume(panic_ctx
: *mut u8) -> ! {
249 uw
::_Unwind_Resume(panic_ctx
as *mut uw
::_Unwind_Exception
);
252 #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
253 pub mod eh_frame_registry
{
254 // The implementation of stack unwinding is (for now) deferred to libgcc_eh, however Rust
255 // crates use these Rust-specific entry points to avoid potential clashes with GCC runtime.
256 // See also: rtbegin.rs, `unwind` module.
258 #[link(name = "gcc_eh")]
259 #[cfg(not(cargobuild))]
263 fn __register_frame_info(eh_frame_begin
: *const u8, object
: *mut u8);
264 fn __deregister_frame_info(eh_frame_begin
: *const u8, object
: *mut u8);
268 #[unstable(feature = "libstd_sys_internals", issue = "0")]
269 pub unsafe extern fn rust_eh_register_frames(eh_frame_begin
: *const u8,
271 __register_frame_info(eh_frame_begin
, object
);
275 #[unstable(feature = "libstd_sys_internals", issue = "0")]
276 pub unsafe extern fn rust_eh_unregister_frames(eh_frame_begin
: *const u8,
278 __deregister_frame_info(eh_frame_begin
, object
);