]> git.proxmox.com Git - rustc.git/blob - src/libstd/sys/common/unwind/gcc.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / libstd / sys / common / unwind / gcc.rs
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.
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 #![allow(private_no_mangle_fns)]
12
13 use prelude::v1::*;
14
15 use any::Any;
16 use sys_common::libunwind as uw;
17
18 struct Exception {
19 uwe: uw::_Unwind_Exception,
20 cause: Option<Box<Any + Send + 'static>>,
21 }
22
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],
29 },
30 cause: Some(data),
31 };
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);
35
36 extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
37 exception: *mut uw::_Unwind_Exception) {
38 unsafe {
39 let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
40 }
41 }
42 }
43
44 pub fn payload() -> *mut u8 {
45 0 as *mut u8
46 }
47
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 _);
52 cause.unwrap()
53 }
54
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
59 0x4d4f5a_00_52555354
60 }
61
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.
67 //
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.
71 //
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.
78 //
79 // See also: rustc_trans::trans::intrinsic::trans_gnu_try
80
81 #[cfg(all(not(target_arch = "arm"),
82 not(all(windows, target_arch = "x86_64")),
83 not(test)))]
84 pub mod eabi {
85 use sys_common::libunwind as uw;
86 use libc::c_int;
87
88 extern {
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;
95 }
96
97 #[lang = "eh_personality"]
98 #[no_mangle]
99 extern fn rust_eh_personality(
100 version: c_int,
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
106 {
107 unsafe {
108 __gcc_personality_v0(version, actions, exception_class, ue_header,
109 context)
110 }
111 }
112
113 #[lang = "eh_personality_catch"]
114 #[no_mangle]
115 pub extern fn rust_eh_personality_catch(
116 version: c_int,
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
122 {
123
124 if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
125 uw::_URC_HANDLER_FOUND // catch!
126 }
127 else { // cleanup phase
128 unsafe {
129 __gcc_personality_v0(version, actions, exception_class, ue_header,
130 context)
131 }
132 }
133 }
134 }
135
136 // iOS on armv7 is using SjLj exceptions and therefore requires to use
137 // a specialized personality routine: __gcc_personality_sj0
138
139 #[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
140 pub mod eabi {
141 use sys_common::libunwind as uw;
142 use libc::c_int;
143
144 extern {
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;
151 }
152
153 #[lang = "eh_personality"]
154 #[no_mangle]
155 pub extern fn rust_eh_personality(
156 version: c_int,
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
162 {
163 unsafe {
164 __gcc_personality_sj0(version, actions, exception_class, ue_header,
165 context)
166 }
167 }
168
169 #[lang = "eh_personality_catch"]
170 #[no_mangle]
171 pub extern fn rust_eh_personality_catch(
172 version: c_int,
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
178 {
179 if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
180 uw::_URC_HANDLER_FOUND // catch!
181 }
182 else { // cleanup phase
183 unsafe {
184 __gcc_personality_sj0(version, actions, exception_class, ue_header,
185 context)
186 }
187 }
188 }
189 }
190
191
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)))]
195 pub mod eabi {
196 use sys_common::libunwind as uw;
197 use libc::c_int;
198
199 extern {
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;
204 }
205
206 #[lang = "eh_personality"]
207 #[no_mangle]
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
213 {
214 unsafe {
215 __gcc_personality_v0(state, ue_header, context)
216 }
217 }
218
219 #[lang = "eh_personality_catch"]
220 #[no_mangle]
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
226 {
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!
235 }
236 else { // cleanup phase
237 unsafe {
238 __gcc_personality_v0(state, ue_header, context)
239 }
240 }
241 }
242 }
243
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"]
247 #[unwind]
248 unsafe extern fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! {
249 uw::_Unwind_Resume(panic_ctx as *mut uw::_Unwind_Exception);
250 }
251
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.
257
258 #[link(name = "gcc_eh")]
259 #[cfg(not(cargobuild))]
260 extern {}
261
262 extern {
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);
265 }
266 #[cfg(not(test))]
267 #[no_mangle]
268 #[unstable(feature = "libstd_sys_internals", issue = "0")]
269 pub unsafe extern fn rust_eh_register_frames(eh_frame_begin: *const u8,
270 object: *mut u8) {
271 __register_frame_info(eh_frame_begin, object);
272 }
273 #[cfg(not(test))]
274 #[no_mangle]
275 #[unstable(feature = "libstd_sys_internals", issue = "0")]
276 pub unsafe extern fn rust_eh_unregister_frames(eh_frame_begin: *const u8,
277 object: *mut u8) {
278 __deregister_frame_info(eh_frame_begin, object);
279 }
280 }