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 //! Unwinding implementation of top of native Win64 SEH,
12 //! however the unwind handler data (aka LSDA) uses GCC-compatible encoding.
15 #![allow(private_no_mangle_fns)]
17 use alloc
::boxed
::Box
;
22 use dwarf
::eh
::{EHContext, EHAction, find_eh_action}
;
25 // Define our exception codes:
26 // according to http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx,
27 // [31:30] = 3 (error), 2 (warning), 1 (info), 0 (success)
28 // [29] = 1 (user-defined)
29 // [28] = 0 (reserved)
33 const ETYPE
: c
::DWORD
= 0b1110_u32 << 28;
34 const MAGIC
: c
::DWORD
= 0x525354; // "RST"
36 const RUST_PANIC
: c
::DWORD
= ETYPE
| (1 << 24) | MAGIC
;
40 data
: Box
<Any
+ Send
>,
43 pub unsafe fn panic(data
: Box
<Any
+ Send
>) -> u32 {
44 let panic_ctx
= Box
::new(PanicData { data: data }
);
45 let params
= [Box
::into_raw(panic_ctx
) as c
::ULONG_PTR
];
46 c
::RaiseException(RUST_PANIC
,
47 c
::EXCEPTION_NONCONTINUABLE
,
48 params
.len() as c
::DWORD
,
49 ¶ms
as *const c
::ULONG_PTR
);
53 pub fn payload() -> *mut u8 {
57 pub unsafe fn cleanup(ptr
: *mut u8) -> Box
<Any
+ Send
> {
58 let panic_ctx
= Box
::from_raw(ptr
as *mut PanicData
);
59 return panic_ctx
.data
;
62 // SEH doesn't support resuming unwinds after calling a landing pad like
63 // libunwind does. For this reason, MSVC compiler outlines landing pads into
64 // separate functions that can be called directly from the personality function
65 // but are nevertheless able to find and modify stack frame of the "parent"
68 // Since this cannot be done with libdwarf-style landing pads,
69 // rust_eh_personality instead catches RUST_PANICs, runs the landing pad, then
70 // reraises the exception.
72 // Note that it makes certain assumptions about the exception:
74 // 1. That RUST_PANIC is non-continuable, so no lower stack frame may choose to
76 // 2. That the first parameter of the exception is a pointer to an extra data
78 // Since these assumptions do not generally hold true for foreign exceptions
79 // (system faults, C++ exceptions, etc), we make no attempt to invoke our
80 // landing pads (and, thus, destructors!) for anything other than RUST_PANICs.
81 // This is considered acceptable, because the behavior of throwing exceptions
82 // through a C ABI boundary is undefined.
84 // *** Delete after a new snapshot ***
86 #[lang = "eh_personality_catch"]
88 unsafe extern "C" fn rust_eh_personality_catch(exceptionRecord
: *mut c
::EXCEPTION_RECORD
,
89 establisherFrame
: c
::LPVOID
,
90 contextRecord
: *mut c
::CONTEXT
,
91 dispatcherContext
: *mut c
::DISPATCHER_CONTEXT
)
92 -> c
::EXCEPTION_DISPOSITION
{
93 rust_eh_personality(exceptionRecord
,
99 #[lang = "eh_personality"]
101 unsafe extern "C" fn rust_eh_personality(exceptionRecord
: *mut c
::EXCEPTION_RECORD
,
102 establisherFrame
: c
::LPVOID
,
103 contextRecord
: *mut c
::CONTEXT
,
104 dispatcherContext
: *mut c
::DISPATCHER_CONTEXT
)
105 -> c
::EXCEPTION_DISPOSITION
{
106 let er
= &*exceptionRecord
;
107 let dc
= &*dispatcherContext
;
109 if er
.ExceptionFlags
& c
::EXCEPTION_UNWIND
== 0 {
110 // we are in the dispatch phase
111 if er
.ExceptionCode
== RUST_PANIC
{
112 if let Some(lpad
) = find_landing_pad(dc
) {
113 c
::RtlUnwindEx(establisherFrame
,
116 er
.ExceptionInformation
[0] as c
::LPVOID
, // pointer to PanicData
122 c
::ExceptionContinueSearch
125 #[lang = "eh_unwind_resume"]
127 unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx
: c
::LPVOID
) -> ! {
128 let params
= [panic_ctx
as c
::ULONG_PTR
];
129 c
::RaiseException(RUST_PANIC
,
130 c
::EXCEPTION_NONCONTINUABLE
,
131 params
.len() as c
::DWORD
,
132 ¶ms
as *const c
::ULONG_PTR
);
136 unsafe fn find_landing_pad(dc
: &c
::DISPATCHER_CONTEXT
) -> Option
<usize> {
137 let eh_ctx
= EHContext
{
138 // The return address points 1 byte past the call instruction,
139 // which could be in the next IP range in LSDA range table.
140 ip
: dc
.ControlPc
as usize - 1,
141 func_start
: dc
.ImageBase
as usize + (*dc
.FunctionEntry
).BeginAddress
as usize,
142 get_text_start
: &|| dc
.ImageBase
as usize,
143 get_data_start
: &|| unimplemented
!(),
145 match find_eh_action(dc
.HandlerData
, &eh_ctx
) {
146 EHAction
::None
=> None
,
147 EHAction
::Cleanup(lpad
) | EHAction
::Catch(lpad
) => Some(lpad
),
148 EHAction
::Terminate
=> intrinsics
::abort(),