]> git.proxmox.com Git - rustc.git/blame - src/libstd/sys/common/unwind/seh64_gnu.rs
Imported Upstream version 1.6.0+dfsg1
[rustc.git] / src / libstd / sys / common / unwind / seh64_gnu.rs
CommitLineData
c1a9b12d
SL
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//! Unwinding implementation of top of native Win64 SEH,
12//! however the unwind handler data (aka LSDA) uses GCC-compatible encoding.
13
14#![allow(bad_style)]
15#![allow(private_no_mangle_fns)]
16
17use prelude::v1::*;
18
19use any::Any;
e9174d1e 20use sys_common::dwarf::eh;
c1a9b12d
SL
21use core::mem;
22use core::ptr;
92a42be0 23use sys::c;
c1a9b12d
SL
24
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)
30// we define bits:
31// [24:27] = type
32// [0:23] = magic
92a42be0
SL
33const ETYPE: c::DWORD = 0b1110_u32 << 28;
34const MAGIC: c::DWORD = 0x525354; // "RST"
c1a9b12d 35
92a42be0 36const RUST_PANIC: c::DWORD = ETYPE | (1 << 24) | MAGIC;
c1a9b12d
SL
37
38#[repr(C)]
39struct PanicData {
40 data: Box<Any + Send + 'static>
41}
42
43pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
44 let panic_ctx = Box::new(PanicData { data: data });
92a42be0
SL
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 &params as *const c::ULONG_PTR);
c1a9b12d
SL
50 rtabort!("could not unwind stack");
51}
52
53pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
c1a9b12d
SL
54 let panic_ctx = Box::from_raw(ptr as *mut PanicData);
55 return panic_ctx.data;
56}
57
58// SEH doesn't support resuming unwinds after calling a landing pad like
59// libunwind does. For this reason, MSVC compiler outlines landing pads into
60// separate functions that can be called directly from the personality function
61// but are nevertheless able to find and modify stack frame of the "parent"
62// function.
63//
64// Since this cannot be done with libdwarf-style landing pads,
65// rust_eh_personality instead catches RUST_PANICs, runs the landing pad, then
66// reraises the exception.
67//
68// Note that it makes certain assumptions about the exception:
69//
70// 1. That RUST_PANIC is non-continuable, so no lower stack frame may choose to
71// resume execution.
72// 2. That the first parameter of the exception is a pointer to an extra data
73// area (PanicData).
74// Since these assumptions do not generally hold true for foreign exceptions
75// (system faults, C++ exceptions, etc), we make no attempt to invoke our
76// landing pads (and, thus, destructors!) for anything other than RUST_PANICs.
77// This is considered acceptable, because the behavior of throwing exceptions
78// through a C ABI boundary is undefined.
79
80#[lang = "eh_personality_catch"]
81#[cfg(not(test))]
82unsafe extern fn rust_eh_personality_catch(
92a42be0
SL
83 exceptionRecord: *mut c::EXCEPTION_RECORD,
84 establisherFrame: c::LPVOID,
85 contextRecord: *mut c::CONTEXT,
86 dispatcherContext: *mut c::DISPATCHER_CONTEXT
87) -> c::EXCEPTION_DISPOSITION
c1a9b12d
SL
88{
89 rust_eh_personality(exceptionRecord, establisherFrame,
90 contextRecord, dispatcherContext)
91}
92
93#[lang = "eh_personality"]
94#[cfg(not(test))]
95unsafe extern fn rust_eh_personality(
92a42be0
SL
96 exceptionRecord: *mut c::EXCEPTION_RECORD,
97 establisherFrame: c::LPVOID,
98 contextRecord: *mut c::CONTEXT,
99 dispatcherContext: *mut c::DISPATCHER_CONTEXT
100) -> c::EXCEPTION_DISPOSITION
c1a9b12d
SL
101{
102 let er = &*exceptionRecord;
103 let dc = &*dispatcherContext;
c1a9b12d 104
92a42be0 105 if er.ExceptionFlags & c::EXCEPTION_UNWIND == 0 { // we are in the dispatch phase
c1a9b12d
SL
106 if er.ExceptionCode == RUST_PANIC {
107 if let Some(lpad) = find_landing_pad(dc) {
92a42be0
SL
108 c::RtlUnwindEx(establisherFrame,
109 lpad as c::LPVOID,
110 exceptionRecord,
111 er.ExceptionInformation[0] as c::LPVOID, // pointer to PanicData
112 contextRecord,
113 dc.HistoryTable);
c1a9b12d
SL
114 rtabort!("could not unwind");
115 }
116 }
117 }
92a42be0 118 c::ExceptionContinueSearch
c1a9b12d
SL
119}
120
c1a9b12d 121#[cfg(not(test))]
92a42be0 122#[lang = "eh_unwind_resume"]
e9174d1e 123#[unwind]
92a42be0
SL
124unsafe extern fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! {
125 let params = [panic_ctx as c::ULONG_PTR];
126 c::RaiseException(RUST_PANIC,
127 c::EXCEPTION_NONCONTINUABLE,
128 params.len() as c::DWORD,
129 &params as *const c::ULONG_PTR);
c1a9b12d
SL
130 rtabort!("could not resume unwind");
131}
132
92a42be0 133unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option<usize> {
c1a9b12d
SL
134 let eh_ctx = eh::EHContext {
135 ip: dc.ControlPc as usize,
136 func_start: dc.ImageBase as usize + (*dc.FunctionEntry).BeginAddress as usize,
137 text_start: dc.ImageBase as usize,
138 data_start: 0
139 };
140 eh::find_landing_pad(dc.HandlerData, &eh_ctx)
141}