Skip to content

Commit bdd9546

Browse files
committed
---
yaml --- r: 207342 b: refs/heads/master c: f5222fb h: refs/heads/master v: v3
1 parent b708177 commit bdd9546

File tree

4 files changed

+390
-329
lines changed

4 files changed

+390
-329
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
refs/heads/master: 847c8520b14e3ae9aec26a33f70750a071d3f18d
2+
refs/heads/master: f5222fb892be00f2b3e4dd8b83c5277e94ebbbba
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: 857ef6e272e5634cb9f3e6ee50eb6bc2a2e71651
55
refs/heads/try: 7b4ef47b7805a402d756fb8157101f64880a522f

trunk/src/libstd/rt/unwind/gcc.rs

Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
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+
use prelude::v1::*;
12+
13+
use any::Any;
14+
use boxed;
15+
use libc::c_void;
16+
use rt::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 = boxed::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+
rtdebug!("exception_cleanup()");
39+
unsafe {
40+
let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
41+
}
42+
}
43+
}
44+
45+
pub unsafe fn cleanup(ptr: *mut c_void) -> Box<Any + Send + 'static> {
46+
let my_ep = ptr as *mut Exception;
47+
rtdebug!("caught {}", (*my_ep).uwe.exception_class);
48+
let cause = (*my_ep).cause.take();
49+
uw::_Unwind_DeleteException(ptr as *mut _);
50+
cause.unwrap()
51+
}
52+
53+
// Rust's exception class identifier. This is used by personality routines to
54+
// determine whether the exception was thrown by their own runtime.
55+
fn rust_exception_class() -> uw::_Unwind_Exception_Class {
56+
// M O Z \0 R U S T -- vendor, language
57+
0x4d4f5a_00_52555354
58+
}
59+
60+
// We could implement our personality routine in pure Rust, however exception
61+
// info decoding is tedious. More importantly, personality routines have to
62+
// handle various platform quirks, which are not fun to maintain. For this
63+
// reason, we attempt to reuse personality routine of the C language:
64+
// __gcc_personality_v0.
65+
//
66+
// Since C does not support exception catching, __gcc_personality_v0 simply
67+
// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
68+
// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
69+
//
70+
// This is pretty close to Rust's exception handling approach, except that Rust
71+
// does have a single "catch-all" handler at the bottom of each thread's stack.
72+
// So we have two versions of the personality routine:
73+
// - rust_eh_personality, used by all cleanup landing pads, which never catches,
74+
// so the behavior of __gcc_personality_v0 is perfectly adequate there, and
75+
// - rust_eh_personality_catch, used only by rust_try(), which always catches.
76+
//
77+
// Note, however, that for implementation simplicity, rust_eh_personality_catch
78+
// lacks code to install a landing pad, so in order to obtain exception object
79+
// pointer (which it needs to return upstream), rust_try() employs another trick:
80+
// it calls into the nested rust_try_inner(), whose landing pad does not resume
81+
// unwinds. Instead, it extracts the exception pointer and performs a "normal"
82+
// return.
83+
//
84+
// See also: rt/rust_try.ll
85+
86+
#[cfg(all(not(target_arch = "arm"),
87+
not(all(windows, target_arch = "x86_64")),
88+
not(test)))]
89+
pub mod eabi {
90+
use rt::libunwind as uw;
91+
use libc::c_int;
92+
93+
extern "C" {
94+
fn __gcc_personality_v0(version: c_int,
95+
actions: uw::_Unwind_Action,
96+
exception_class: uw::_Unwind_Exception_Class,
97+
ue_header: *mut uw::_Unwind_Exception,
98+
context: *mut uw::_Unwind_Context)
99+
-> uw::_Unwind_Reason_Code;
100+
}
101+
102+
#[lang="eh_personality"]
103+
#[no_mangle] // referenced from rust_try.ll
104+
#[allow(private_no_mangle_fns)]
105+
extern fn rust_eh_personality(
106+
version: c_int,
107+
actions: uw::_Unwind_Action,
108+
exception_class: uw::_Unwind_Exception_Class,
109+
ue_header: *mut uw::_Unwind_Exception,
110+
context: *mut uw::_Unwind_Context
111+
) -> uw::_Unwind_Reason_Code
112+
{
113+
unsafe {
114+
__gcc_personality_v0(version, actions, exception_class, ue_header,
115+
context)
116+
}
117+
}
118+
119+
#[no_mangle] // referenced from rust_try.ll
120+
pub extern "C" fn rust_eh_personality_catch(
121+
_version: c_int,
122+
actions: uw::_Unwind_Action,
123+
_exception_class: uw::_Unwind_Exception_Class,
124+
_ue_header: *mut uw::_Unwind_Exception,
125+
_context: *mut uw::_Unwind_Context
126+
) -> uw::_Unwind_Reason_Code
127+
{
128+
129+
if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
130+
uw::_URC_HANDLER_FOUND // catch!
131+
}
132+
else { // cleanup phase
133+
uw::_URC_INSTALL_CONTEXT
134+
}
135+
}
136+
}
137+
138+
// iOS on armv7 is using SjLj exceptions and therefore requires to use
139+
// a specialized personality routine: __gcc_personality_sj0
140+
141+
#[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
142+
pub mod eabi {
143+
use rt::libunwind as uw;
144+
use libc::c_int;
145+
146+
extern "C" {
147+
fn __gcc_personality_sj0(version: c_int,
148+
actions: uw::_Unwind_Action,
149+
exception_class: uw::_Unwind_Exception_Class,
150+
ue_header: *mut uw::_Unwind_Exception,
151+
context: *mut uw::_Unwind_Context)
152+
-> uw::_Unwind_Reason_Code;
153+
}
154+
155+
#[lang="eh_personality"]
156+
#[no_mangle] // referenced from rust_try.ll
157+
pub extern "C" fn rust_eh_personality(
158+
version: c_int,
159+
actions: uw::_Unwind_Action,
160+
exception_class: uw::_Unwind_Exception_Class,
161+
ue_header: *mut uw::_Unwind_Exception,
162+
context: *mut uw::_Unwind_Context
163+
) -> uw::_Unwind_Reason_Code
164+
{
165+
unsafe {
166+
__gcc_personality_sj0(version, actions, exception_class, ue_header,
167+
context)
168+
}
169+
}
170+
171+
#[no_mangle] // referenced from rust_try.ll
172+
pub extern "C" fn rust_eh_personality_catch(
173+
_version: c_int,
174+
actions: uw::_Unwind_Action,
175+
_exception_class: uw::_Unwind_Exception_Class,
176+
_ue_header: *mut uw::_Unwind_Exception,
177+
_context: *mut uw::_Unwind_Context
178+
) -> uw::_Unwind_Reason_Code
179+
{
180+
if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
181+
uw::_URC_HANDLER_FOUND // catch!
182+
}
183+
else { // cleanup phase
184+
unsafe {
185+
__gcc_personality_sj0(_version, actions, _exception_class, _ue_header,
186+
_context)
187+
}
188+
}
189+
}
190+
}
191+
192+
193+
// ARM EHABI uses a slightly different personality routine signature,
194+
// but otherwise works the same.
195+
#[cfg(all(target_arch = "arm", not(target_os = "ios"), not(test)))]
196+
pub mod eabi {
197+
use rt::libunwind as uw;
198+
use libc::c_int;
199+
200+
extern "C" {
201+
fn __gcc_personality_v0(state: uw::_Unwind_State,
202+
ue_header: *mut uw::_Unwind_Exception,
203+
context: *mut uw::_Unwind_Context)
204+
-> uw::_Unwind_Reason_Code;
205+
}
206+
207+
#[lang="eh_personality"]
208+
#[no_mangle] // referenced from rust_try.ll
209+
#[allow(private_no_mangle_fns)]
210+
extern "C" fn rust_eh_personality(
211+
state: uw::_Unwind_State,
212+
ue_header: *mut uw::_Unwind_Exception,
213+
context: *mut uw::_Unwind_Context
214+
) -> uw::_Unwind_Reason_Code
215+
{
216+
unsafe {
217+
__gcc_personality_v0(state, ue_header, context)
218+
}
219+
}
220+
221+
#[no_mangle] // referenced from rust_try.ll
222+
pub extern "C" fn rust_eh_personality_catch(
223+
state: uw::_Unwind_State,
224+
_ue_header: *mut uw::_Unwind_Exception,
225+
_context: *mut uw::_Unwind_Context
226+
) -> uw::_Unwind_Reason_Code
227+
{
228+
if (state as c_int & uw::_US_ACTION_MASK as c_int)
229+
== uw::_US_VIRTUAL_UNWIND_FRAME as c_int { // search phase
230+
uw::_URC_HANDLER_FOUND // catch!
231+
}
232+
else { // cleanup phase
233+
uw::_URC_INSTALL_CONTEXT
234+
}
235+
}
236+
}
237+
238+
// Win64 SEH (see http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx)
239+
//
240+
// This looks a bit convoluted because rather than implementing a native SEH
241+
// handler, GCC reuses the same personality routine as for the other
242+
// architectures by wrapping it with an "API translator" layer
243+
// (_GCC_specific_handler).
244+
245+
#[cfg(all(windows, target_arch = "x86_64", not(test)))]
246+
#[doc(hidden)]
247+
#[allow(non_camel_case_types, non_snake_case)]
248+
pub mod eabi {
249+
pub use self::EXCEPTION_DISPOSITION::*;
250+
use rt::libunwind as uw;
251+
use libc::{c_void, c_int};
252+
253+
#[repr(C)]
254+
pub struct EXCEPTION_RECORD;
255+
#[repr(C)]
256+
pub struct CONTEXT;
257+
#[repr(C)]
258+
pub struct DISPATCHER_CONTEXT;
259+
260+
#[repr(C)]
261+
#[derive(Copy, Clone)]
262+
pub enum EXCEPTION_DISPOSITION {
263+
ExceptionContinueExecution,
264+
ExceptionContinueSearch,
265+
ExceptionNestedException,
266+
ExceptionCollidedUnwind
267+
}
268+
269+
type _Unwind_Personality_Fn =
270+
extern "C" fn(
271+
version: c_int,
272+
actions: uw::_Unwind_Action,
273+
exception_class: uw::_Unwind_Exception_Class,
274+
ue_header: *mut uw::_Unwind_Exception,
275+
context: *mut uw::_Unwind_Context
276+
) -> uw::_Unwind_Reason_Code;
277+
278+
extern "C" {
279+
fn __gcc_personality_seh0(
280+
exceptionRecord: *mut EXCEPTION_RECORD,
281+
establisherFrame: *mut c_void,
282+
contextRecord: *mut CONTEXT,
283+
dispatcherContext: *mut DISPATCHER_CONTEXT
284+
) -> EXCEPTION_DISPOSITION;
285+
286+
fn _GCC_specific_handler(
287+
exceptionRecord: *mut EXCEPTION_RECORD,
288+
establisherFrame: *mut c_void,
289+
contextRecord: *mut CONTEXT,
290+
dispatcherContext: *mut DISPATCHER_CONTEXT,
291+
personality: _Unwind_Personality_Fn
292+
) -> EXCEPTION_DISPOSITION;
293+
}
294+
295+
#[lang="eh_personality"]
296+
#[no_mangle] // referenced from rust_try.ll
297+
#[allow(private_no_mangle_fns)]
298+
extern "C" fn rust_eh_personality(
299+
exceptionRecord: *mut EXCEPTION_RECORD,
300+
establisherFrame: *mut c_void,
301+
contextRecord: *mut CONTEXT,
302+
dispatcherContext: *mut DISPATCHER_CONTEXT
303+
) -> EXCEPTION_DISPOSITION
304+
{
305+
unsafe {
306+
__gcc_personality_seh0(exceptionRecord, establisherFrame,
307+
contextRecord, dispatcherContext)
308+
}
309+
}
310+
311+
#[no_mangle] // referenced from rust_try.ll
312+
pub extern "C" fn rust_eh_personality_catch(
313+
exceptionRecord: *mut EXCEPTION_RECORD,
314+
establisherFrame: *mut c_void,
315+
contextRecord: *mut CONTEXT,
316+
dispatcherContext: *mut DISPATCHER_CONTEXT
317+
) -> EXCEPTION_DISPOSITION
318+
{
319+
extern "C" fn inner(
320+
_version: c_int,
321+
actions: uw::_Unwind_Action,
322+
_exception_class: uw::_Unwind_Exception_Class,
323+
_ue_header: *mut uw::_Unwind_Exception,
324+
_context: *mut uw::_Unwind_Context
325+
) -> uw::_Unwind_Reason_Code
326+
{
327+
if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
328+
uw::_URC_HANDLER_FOUND // catch!
329+
}
330+
else { // cleanup phase
331+
uw::_URC_INSTALL_CONTEXT
332+
}
333+
}
334+
335+
unsafe {
336+
_GCC_specific_handler(exceptionRecord, establisherFrame,
337+
contextRecord, dispatcherContext,
338+
inner)
339+
}
340+
}
341+
}
342+

0 commit comments

Comments
 (0)