2015-07-13 20:11:44 -05:00
|
|
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
//! Unwinding implementation of top of native Win64 SEH,
|
|
|
|
//! however the unwind handler data (aka LSDA) uses GCC-compatible encoding.
|
|
|
|
|
2018-08-29 08:21:01 -05:00
|
|
|
#![allow(nonstandard_style)]
|
2015-07-13 20:11:44 -05:00
|
|
|
#![allow(private_no_mangle_fns)]
|
|
|
|
|
rustc: Implement custom panic runtimes
This commit is an implementation of [RFC 1513] which allows applications to
alter the behavior of panics at compile time. A new compiler flag, `-C panic`,
is added and accepts the values `unwind` or `panic`, with the default being
`unwind`. This model affects how code is generated for the local crate, skipping
generation of landing pads with `-C panic=abort`.
[RFC 1513]: https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md
Panic implementations are then provided by crates tagged with
`#![panic_runtime]` and lazily required by crates with
`#![needs_panic_runtime]`. The panic strategy (`-C panic` value) of the panic
runtime must match the final product, and if the panic strategy is not `abort`
then the entire DAG must have the same panic strategy.
With the `-C panic=abort` strategy, users can expect a stable method to disable
generation of landing pads, improving optimization in niche scenarios,
decreasing compile time, and decreasing output binary size. With the `-C
panic=unwind` strategy users can expect the existing ability to isolate failure
in Rust code from the outside world.
Organizationally, this commit dismantles the `sys_common::unwind` module in
favor of some bits moving part of it to `libpanic_unwind` and the rest into the
`panicking` module in libstd. The custom panic runtime support is pretty similar
to the custom allocator support with the only major difference being how the
panic runtime is injected (takes the `-C panic` flag into account).
2016-04-08 18:18:40 -05:00
|
|
|
use alloc::boxed::Box;
|
2015-07-13 20:11:44 -05:00
|
|
|
|
rustc: Implement custom panic runtimes
This commit is an implementation of [RFC 1513] which allows applications to
alter the behavior of panics at compile time. A new compiler flag, `-C panic`,
is added and accepts the values `unwind` or `panic`, with the default being
`unwind`. This model affects how code is generated for the local crate, skipping
generation of landing pads with `-C panic=abort`.
[RFC 1513]: https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md
Panic implementations are then provided by crates tagged with
`#![panic_runtime]` and lazily required by crates with
`#![needs_panic_runtime]`. The panic strategy (`-C panic` value) of the panic
runtime must match the final product, and if the panic strategy is not `abort`
then the entire DAG must have the same panic strategy.
With the `-C panic=abort` strategy, users can expect a stable method to disable
generation of landing pads, improving optimization in niche scenarios,
decreasing compile time, and decreasing output binary size. With the `-C
panic=unwind` strategy users can expect the existing ability to isolate failure
in Rust code from the outside world.
Organizationally, this commit dismantles the `sys_common::unwind` module in
favor of some bits moving part of it to `libpanic_unwind` and the rest into the
`panicking` module in libstd. The custom panic runtime support is pretty similar
to the custom allocator support with the only major difference being how the
panic runtime is injected (takes the `-C panic` flag into account).
2016-04-08 18:18:40 -05:00
|
|
|
use core::any::Any;
|
|
|
|
use core::intrinsics;
|
2016-06-24 13:54:52 -05:00
|
|
|
use core::ptr;
|
2016-07-22 16:57:54 -05:00
|
|
|
use dwarf::eh::{EHContext, EHAction, find_eh_action};
|
rustc: Implement custom panic runtimes
This commit is an implementation of [RFC 1513] which allows applications to
alter the behavior of panics at compile time. A new compiler flag, `-C panic`,
is added and accepts the values `unwind` or `panic`, with the default being
`unwind`. This model affects how code is generated for the local crate, skipping
generation of landing pads with `-C panic=abort`.
[RFC 1513]: https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md
Panic implementations are then provided by crates tagged with
`#![panic_runtime]` and lazily required by crates with
`#![needs_panic_runtime]`. The panic strategy (`-C panic` value) of the panic
runtime must match the final product, and if the panic strategy is not `abort`
then the entire DAG must have the same panic strategy.
With the `-C panic=abort` strategy, users can expect a stable method to disable
generation of landing pads, improving optimization in niche scenarios,
decreasing compile time, and decreasing output binary size. With the `-C
panic=unwind` strategy users can expect the existing ability to isolate failure
in Rust code from the outside world.
Organizationally, this commit dismantles the `sys_common::unwind` module in
favor of some bits moving part of it to `libpanic_unwind` and the rest into the
`panicking` module in libstd. The custom panic runtime support is pretty similar
to the custom allocator support with the only major difference being how the
panic runtime is injected (takes the `-C panic` flag into account).
2016-04-08 18:18:40 -05:00
|
|
|
use windows as c;
|
2015-07-13 20:11:44 -05:00
|
|
|
|
|
|
|
// Define our exception codes:
|
|
|
|
// according to http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx,
|
|
|
|
// [31:30] = 3 (error), 2 (warning), 1 (info), 0 (success)
|
|
|
|
// [29] = 1 (user-defined)
|
|
|
|
// [28] = 0 (reserved)
|
|
|
|
// we define bits:
|
|
|
|
// [24:27] = type
|
|
|
|
// [0:23] = magic
|
2015-11-02 18:23:22 -06:00
|
|
|
const ETYPE: c::DWORD = 0b1110_u32 << 28;
|
|
|
|
const MAGIC: c::DWORD = 0x525354; // "RST"
|
2015-07-13 20:11:44 -05:00
|
|
|
|
2016-05-29 05:36:29 -05:00
|
|
|
const RUST_PANIC: c::DWORD = ETYPE | (1 << 24) | MAGIC;
|
2015-07-13 20:11:44 -05:00
|
|
|
|
|
|
|
#[repr(C)]
|
|
|
|
struct PanicData {
|
2018-07-11 10:11:08 -05:00
|
|
|
data: Box<dyn Any + Send>,
|
2015-07-13 20:11:44 -05:00
|
|
|
}
|
|
|
|
|
2018-07-11 10:11:08 -05:00
|
|
|
pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
|
2015-07-13 20:11:44 -05:00
|
|
|
let panic_ctx = Box::new(PanicData { data: data });
|
2015-11-02 18:23:22 -06:00
|
|
|
let params = [Box::into_raw(panic_ctx) as c::ULONG_PTR];
|
|
|
|
c::RaiseException(RUST_PANIC,
|
|
|
|
c::EXCEPTION_NONCONTINUABLE,
|
|
|
|
params.len() as c::DWORD,
|
|
|
|
¶ms as *const c::ULONG_PTR);
|
rustc: Implement custom panic runtimes
This commit is an implementation of [RFC 1513] which allows applications to
alter the behavior of panics at compile time. A new compiler flag, `-C panic`,
is added and accepts the values `unwind` or `panic`, with the default being
`unwind`. This model affects how code is generated for the local crate, skipping
generation of landing pads with `-C panic=abort`.
[RFC 1513]: https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md
Panic implementations are then provided by crates tagged with
`#![panic_runtime]` and lazily required by crates with
`#![needs_panic_runtime]`. The panic strategy (`-C panic` value) of the panic
runtime must match the final product, and if the panic strategy is not `abort`
then the entire DAG must have the same panic strategy.
With the `-C panic=abort` strategy, users can expect a stable method to disable
generation of landing pads, improving optimization in niche scenarios,
decreasing compile time, and decreasing output binary size. With the `-C
panic=unwind` strategy users can expect the existing ability to isolate failure
in Rust code from the outside world.
Organizationally, this commit dismantles the `sys_common::unwind` module in
favor of some bits moving part of it to `libpanic_unwind` and the rest into the
`panicking` module in libstd. The custom panic runtime support is pretty similar
to the custom allocator support with the only major difference being how the
panic runtime is injected (takes the `-C panic` flag into account).
2016-04-08 18:18:40 -05:00
|
|
|
u32::max_value()
|
2015-07-13 20:11:44 -05:00
|
|
|
}
|
|
|
|
|
2015-10-23 20:18:44 -05:00
|
|
|
pub fn payload() -> *mut u8 {
|
2016-06-24 13:54:52 -05:00
|
|
|
ptr::null_mut()
|
2015-10-23 20:18:44 -05:00
|
|
|
}
|
|
|
|
|
2018-07-11 10:11:08 -05:00
|
|
|
pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
|
2015-07-13 20:11:44 -05:00
|
|
|
let panic_ctx = Box::from_raw(ptr as *mut PanicData);
|
|
|
|
return panic_ctx.data;
|
|
|
|
}
|
|
|
|
|
|
|
|
// SEH doesn't support resuming unwinds after calling a landing pad like
|
|
|
|
// libunwind does. For this reason, MSVC compiler outlines landing pads into
|
|
|
|
// separate functions that can be called directly from the personality function
|
|
|
|
// but are nevertheless able to find and modify stack frame of the "parent"
|
|
|
|
// function.
|
|
|
|
//
|
|
|
|
// Since this cannot be done with libdwarf-style landing pads,
|
|
|
|
// rust_eh_personality instead catches RUST_PANICs, runs the landing pad, then
|
|
|
|
// reraises the exception.
|
|
|
|
//
|
|
|
|
// Note that it makes certain assumptions about the exception:
|
|
|
|
//
|
|
|
|
// 1. That RUST_PANIC is non-continuable, so no lower stack frame may choose to
|
|
|
|
// resume execution.
|
|
|
|
// 2. That the first parameter of the exception is a pointer to an extra data
|
|
|
|
// area (PanicData).
|
|
|
|
// Since these assumptions do not generally hold true for foreign exceptions
|
|
|
|
// (system faults, C++ exceptions, etc), we make no attempt to invoke our
|
|
|
|
// landing pads (and, thus, destructors!) for anything other than RUST_PANICs.
|
|
|
|
// This is considered acceptable, because the behavior of throwing exceptions
|
|
|
|
// through a C ABI boundary is undefined.
|
|
|
|
|
|
|
|
#[lang = "eh_personality"]
|
|
|
|
#[cfg(not(test))]
|
2016-05-29 05:36:29 -05:00
|
|
|
unsafe extern "C" fn rust_eh_personality(exceptionRecord: *mut c::EXCEPTION_RECORD,
|
|
|
|
establisherFrame: c::LPVOID,
|
|
|
|
contextRecord: *mut c::CONTEXT,
|
|
|
|
dispatcherContext: *mut c::DISPATCHER_CONTEXT)
|
|
|
|
-> c::EXCEPTION_DISPOSITION {
|
2015-07-13 20:11:44 -05:00
|
|
|
let er = &*exceptionRecord;
|
|
|
|
let dc = &*dispatcherContext;
|
|
|
|
|
2016-05-29 05:36:29 -05:00
|
|
|
if er.ExceptionFlags & c::EXCEPTION_UNWIND == 0 {
|
|
|
|
// we are in the dispatch phase
|
2015-07-13 20:11:44 -05:00
|
|
|
if er.ExceptionCode == RUST_PANIC {
|
|
|
|
if let Some(lpad) = find_landing_pad(dc) {
|
2015-11-02 18:23:22 -06:00
|
|
|
c::RtlUnwindEx(establisherFrame,
|
|
|
|
lpad as c::LPVOID,
|
|
|
|
exceptionRecord,
|
|
|
|
er.ExceptionInformation[0] as c::LPVOID, // pointer to PanicData
|
|
|
|
contextRecord,
|
|
|
|
dc.HistoryTable);
|
2015-07-13 20:11:44 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-11-02 18:23:22 -06:00
|
|
|
c::ExceptionContinueSearch
|
2015-07-13 20:11:44 -05:00
|
|
|
}
|
|
|
|
|
2015-10-18 16:28:47 -05:00
|
|
|
#[lang = "eh_unwind_resume"]
|
2018-04-04 09:16:25 -05:00
|
|
|
#[unwind(allowed)]
|
2016-05-29 05:36:29 -05:00
|
|
|
unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! {
|
2015-11-02 18:23:22 -06:00
|
|
|
let params = [panic_ctx as c::ULONG_PTR];
|
|
|
|
c::RaiseException(RUST_PANIC,
|
|
|
|
c::EXCEPTION_NONCONTINUABLE,
|
|
|
|
params.len() as c::DWORD,
|
|
|
|
¶ms as *const c::ULONG_PTR);
|
rustc: Implement custom panic runtimes
This commit is an implementation of [RFC 1513] which allows applications to
alter the behavior of panics at compile time. A new compiler flag, `-C panic`,
is added and accepts the values `unwind` or `panic`, with the default being
`unwind`. This model affects how code is generated for the local crate, skipping
generation of landing pads with `-C panic=abort`.
[RFC 1513]: https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md
Panic implementations are then provided by crates tagged with
`#![panic_runtime]` and lazily required by crates with
`#![needs_panic_runtime]`. The panic strategy (`-C panic` value) of the panic
runtime must match the final product, and if the panic strategy is not `abort`
then the entire DAG must have the same panic strategy.
With the `-C panic=abort` strategy, users can expect a stable method to disable
generation of landing pads, improving optimization in niche scenarios,
decreasing compile time, and decreasing output binary size. With the `-C
panic=unwind` strategy users can expect the existing ability to isolate failure
in Rust code from the outside world.
Organizationally, this commit dismantles the `sys_common::unwind` module in
favor of some bits moving part of it to `libpanic_unwind` and the rest into the
`panicking` module in libstd. The custom panic runtime support is pretty similar
to the custom allocator support with the only major difference being how the
panic runtime is injected (takes the `-C panic` flag into account).
2016-04-08 18:18:40 -05:00
|
|
|
intrinsics::abort();
|
2015-07-13 20:11:44 -05:00
|
|
|
}
|
|
|
|
|
2015-11-02 18:23:22 -06:00
|
|
|
unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option<usize> {
|
2016-07-22 16:57:54 -05:00
|
|
|
let eh_ctx = EHContext {
|
|
|
|
// The return address points 1 byte past the call instruction,
|
|
|
|
// which could be in the next IP range in LSDA range table.
|
|
|
|
ip: dc.ControlPc as usize - 1,
|
2015-07-13 20:11:44 -05:00
|
|
|
func_start: dc.ImageBase as usize + (*dc.FunctionEntry).BeginAddress as usize,
|
2016-07-22 16:57:54 -05:00
|
|
|
get_text_start: &|| dc.ImageBase as usize,
|
|
|
|
get_data_start: &|| unimplemented!(),
|
2015-07-13 20:11:44 -05:00
|
|
|
};
|
2016-07-22 16:57:54 -05:00
|
|
|
match find_eh_action(dc.HandlerData, &eh_ctx) {
|
2017-06-06 13:34:10 -05:00
|
|
|
Err(_) |
|
|
|
|
Ok(EHAction::None) => None,
|
|
|
|
Ok(EHAction::Cleanup(lpad)) |
|
|
|
|
Ok(EHAction::Catch(lpad)) => Some(lpad),
|
|
|
|
Ok(EHAction::Terminate) => intrinsics::abort(),
|
2016-07-22 16:57:54 -05:00
|
|
|
}
|
2015-07-13 20:11:44 -05:00
|
|
|
}
|