Skip to content

Commit 5ff0876

Browse files
committed
Move personality functions to std
These were previously in the panic_unwind crate with dummy stubs in the panic_abort crate. However it turns out that this is insufficient: we still need a proper personality function even with -C panic=abort to handle the following cases: 1) `extern "C-unwind"` still needs to catch foreign exceptions with -C panic=abort to turn them into aborts. This requires landing pads and a personality function. 2) ARM EHABI uses the personality function when creating backtraces. The dummy personality function in panic_abort was causing backtrace generation to get stuck in a loop since the personality function is responsible for advancing the unwind state to the next frame.
1 parent db94dbc commit 5ff0876

File tree

12 files changed

+347
-277
lines changed

12 files changed

+347
-277
lines changed

library/panic_abort/src/lib.rs

-20
Original file line numberDiff line numberDiff line change
@@ -113,26 +113,6 @@ pub unsafe fn __rust_start_panic(_payload: *mut &mut dyn BoxMeUp) -> u32 {
113113
// binaries, but it should never be called as we don't link in an unwinding
114114
// runtime at all.
115115
pub mod personalities {
116-
#[rustc_std_internal_symbol]
117-
#[cfg(not(any(
118-
all(target_family = "wasm", not(target_os = "emscripten")),
119-
all(target_os = "windows", target_env = "gnu", target_arch = "x86_64",),
120-
)))]
121-
pub extern "C" fn rust_eh_personality() {}
122-
123-
// On x86_64-pc-windows-gnu we use our own personality function that needs
124-
// to return `ExceptionContinueSearch` as we're passing on all our frames.
125-
#[rustc_std_internal_symbol]
126-
#[cfg(all(target_os = "windows", target_env = "gnu", target_arch = "x86_64"))]
127-
pub extern "C" fn rust_eh_personality(
128-
_record: usize,
129-
_frame: usize,
130-
_context: usize,
131-
_dispatcher: usize,
132-
) -> u32 {
133-
1 // `ExceptionContinueSearch`
134-
}
135-
136116
// Similar to above, this corresponds to the `eh_catch_typeinfo` lang item
137117
// that's only used on Emscripten currently.
138118
//

library/panic_unwind/src/emcc.rs

-16
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use core::intrinsics;
1212
use core::mem;
1313
use core::ptr;
1414
use core::sync::atomic::{AtomicBool, Ordering};
15-
use libc::{self, c_int};
1615
use unwind as uw;
1716

1817
// This matches the layout of std::type_info in C++
@@ -105,21 +104,6 @@ extern "C" fn exception_cleanup(ptr: *mut libc::c_void) -> *mut libc::c_void {
105104
}
106105
}
107106

108-
// This is required by the compiler to exist (e.g., it's a lang item), but it's
109-
// never actually called by the compiler. Emscripten EH doesn't use a
110-
// personality function at all, it instead uses __cxa_find_matching_catch.
111-
// Wasm error handling would use __gxx_personality_wasm0.
112-
#[lang = "eh_personality"]
113-
unsafe extern "C" fn rust_eh_personality(
114-
_version: c_int,
115-
_actions: uw::_Unwind_Action,
116-
_exception_class: uw::_Unwind_Exception_Class,
117-
_exception_object: *mut uw::_Unwind_Exception,
118-
_context: *mut uw::_Unwind_Context,
119-
) -> uw::_Unwind_Reason_Code {
120-
core::intrinsics::abort()
121-
}
122-
123107
extern "C" {
124108
fn __cxa_allocate_exception(thrown_size: libc::size_t) -> *mut libc::c_void;
125109
fn __cxa_begin_catch(thrown_exception: *mut libc::c_void) -> *mut libc::c_void;

library/panic_unwind/src/gcc.rs

-228
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@
3939
use alloc::boxed::Box;
4040
use core::any::Any;
4141

42-
use crate::dwarf::eh::{self, EHAction, EHContext};
43-
use libc::{c_int, uintptr_t};
4442
use unwind as uw;
4543

4644
#[repr(C)]
@@ -90,232 +88,6 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
9088
0x4d4f5a_00_52555354
9189
}
9290

93-
// Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
94-
// and TargetLowering::getExceptionSelectorRegister() for each architecture,
95-
// then mapped to DWARF register numbers via register definition tables
96-
// (typically <arch>RegisterInfo.td, search for "DwarfRegNum").
97-
// See also https://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register.
98-
99-
#[cfg(target_arch = "x86")]
100-
const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX
101-
102-
#[cfg(target_arch = "x86_64")]
103-
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
104-
105-
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
106-
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1
107-
108-
#[cfg(target_arch = "m68k")]
109-
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // D0, D1
110-
111-
#[cfg(any(target_arch = "mips", target_arch = "mips64"))]
112-
const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1
113-
114-
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
115-
const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4
116-
117-
#[cfg(target_arch = "s390x")]
118-
const UNWIND_DATA_REG: (i32, i32) = (6, 7); // R6, R7
119-
120-
#[cfg(any(target_arch = "sparc", target_arch = "sparc64"))]
121-
const UNWIND_DATA_REG: (i32, i32) = (24, 25); // I0, I1
122-
123-
#[cfg(target_arch = "hexagon")]
124-
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1
125-
126-
#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))]
127-
const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11
128-
129-
// The following code is based on GCC's C and C++ personality routines. For reference, see:
130-
// https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
131-
// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
132-
133-
cfg_if::cfg_if! {
134-
if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "watchos"), not(target_os = "netbsd")))] {
135-
// ARM EHABI personality routine.
136-
// https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
137-
//
138-
// iOS uses the default routine instead since it uses SjLj unwinding.
139-
#[lang = "eh_personality"]
140-
unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State,
141-
exception_object: *mut uw::_Unwind_Exception,
142-
context: *mut uw::_Unwind_Context)
143-
-> uw::_Unwind_Reason_Code {
144-
let state = state as c_int;
145-
let action = state & uw::_US_ACTION_MASK as c_int;
146-
let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int {
147-
// Backtraces on ARM will call the personality routine with
148-
// state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
149-
// we want to continue unwinding the stack, otherwise all our backtraces
150-
// would end at __rust_try
151-
if state & uw::_US_FORCE_UNWIND as c_int != 0 {
152-
return continue_unwind(exception_object, context);
153-
}
154-
true
155-
} else if action == uw::_US_UNWIND_FRAME_STARTING as c_int {
156-
false
157-
} else if action == uw::_US_UNWIND_FRAME_RESUME as c_int {
158-
return continue_unwind(exception_object, context);
159-
} else {
160-
return uw::_URC_FAILURE;
161-
};
162-
163-
// The DWARF unwinder assumes that _Unwind_Context holds things like the function
164-
// and LSDA pointers, however ARM EHABI places them into the exception object.
165-
// To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which
166-
// take only the context pointer, GCC personality routines stash a pointer to
167-
// exception_object in the context, using location reserved for ARM's
168-
// "scratch register" (r12).
169-
uw::_Unwind_SetGR(context,
170-
uw::UNWIND_POINTER_REG,
171-
exception_object as uw::_Unwind_Ptr);
172-
// ...A more principled approach would be to provide the full definition of ARM's
173-
// _Unwind_Context in our libunwind bindings and fetch the required data from there
174-
// directly, bypassing DWARF compatibility functions.
175-
176-
let eh_action = match find_eh_action(context) {
177-
Ok(action) => action,
178-
Err(_) => return uw::_URC_FAILURE,
179-
};
180-
if search_phase {
181-
match eh_action {
182-
EHAction::None |
183-
EHAction::Cleanup(_) => return continue_unwind(exception_object, context),
184-
EHAction::Catch(_) => {
185-
// EHABI requires the personality routine to update the
186-
// SP value in the barrier cache of the exception object.
187-
(*exception_object).private[5] =
188-
uw::_Unwind_GetGR(context, uw::UNWIND_SP_REG);
189-
return uw::_URC_HANDLER_FOUND;
190-
}
191-
EHAction::Terminate => return uw::_URC_FAILURE,
192-
}
193-
} else {
194-
match eh_action {
195-
EHAction::None => return continue_unwind(exception_object, context),
196-
EHAction::Cleanup(lpad) |
197-
EHAction::Catch(lpad) => {
198-
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0,
199-
exception_object as uintptr_t);
200-
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
201-
uw::_Unwind_SetIP(context, lpad);
202-
return uw::_URC_INSTALL_CONTEXT;
203-
}
204-
EHAction::Terminate => return uw::_URC_FAILURE,
205-
}
206-
}
207-
208-
// On ARM EHABI the personality routine is responsible for actually
209-
// unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
210-
unsafe fn continue_unwind(exception_object: *mut uw::_Unwind_Exception,
211-
context: *mut uw::_Unwind_Context)
212-
-> uw::_Unwind_Reason_Code {
213-
if __gnu_unwind_frame(exception_object, context) == uw::_URC_NO_REASON {
214-
uw::_URC_CONTINUE_UNWIND
215-
} else {
216-
uw::_URC_FAILURE
217-
}
218-
}
219-
// defined in libgcc
220-
extern "C" {
221-
fn __gnu_unwind_frame(exception_object: *mut uw::_Unwind_Exception,
222-
context: *mut uw::_Unwind_Context)
223-
-> uw::_Unwind_Reason_Code;
224-
}
225-
}
226-
} else {
227-
// Default personality routine, which is used directly on most targets
228-
// and indirectly on Windows x86_64 via SEH.
229-
unsafe extern "C" fn rust_eh_personality_impl(version: c_int,
230-
actions: uw::_Unwind_Action,
231-
_exception_class: uw::_Unwind_Exception_Class,
232-
exception_object: *mut uw::_Unwind_Exception,
233-
context: *mut uw::_Unwind_Context)
234-
-> uw::_Unwind_Reason_Code {
235-
if version != 1 {
236-
return uw::_URC_FATAL_PHASE1_ERROR;
237-
}
238-
let eh_action = match find_eh_action(context) {
239-
Ok(action) => action,
240-
Err(_) => return uw::_URC_FATAL_PHASE1_ERROR,
241-
};
242-
if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
243-
match eh_action {
244-
EHAction::None |
245-
EHAction::Cleanup(_) => uw::_URC_CONTINUE_UNWIND,
246-
EHAction::Catch(_) => uw::_URC_HANDLER_FOUND,
247-
EHAction::Terminate => uw::_URC_FATAL_PHASE1_ERROR,
248-
}
249-
} else {
250-
match eh_action {
251-
EHAction::None => uw::_URC_CONTINUE_UNWIND,
252-
EHAction::Cleanup(lpad) |
253-
EHAction::Catch(lpad) => {
254-
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0,
255-
exception_object as uintptr_t);
256-
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
257-
uw::_Unwind_SetIP(context, lpad);
258-
uw::_URC_INSTALL_CONTEXT
259-
}
260-
EHAction::Terminate => uw::_URC_FATAL_PHASE2_ERROR,
261-
}
262-
}
263-
}
264-
265-
cfg_if::cfg_if! {
266-
if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] {
267-
// On x86_64 MinGW targets, the unwinding mechanism is SEH however the unwind
268-
// handler data (aka LSDA) uses GCC-compatible encoding.
269-
#[lang = "eh_personality"]
270-
#[allow(nonstandard_style)]
271-
unsafe extern "C" fn rust_eh_personality(exceptionRecord: *mut uw::EXCEPTION_RECORD,
272-
establisherFrame: uw::LPVOID,
273-
contextRecord: *mut uw::CONTEXT,
274-
dispatcherContext: *mut uw::DISPATCHER_CONTEXT)
275-
-> uw::EXCEPTION_DISPOSITION {
276-
uw::_GCC_specific_handler(exceptionRecord,
277-
establisherFrame,
278-
contextRecord,
279-
dispatcherContext,
280-
rust_eh_personality_impl)
281-
}
282-
} else {
283-
// The personality routine for most of our targets.
284-
#[lang = "eh_personality"]
285-
unsafe extern "C" fn rust_eh_personality(version: c_int,
286-
actions: uw::_Unwind_Action,
287-
exception_class: uw::_Unwind_Exception_Class,
288-
exception_object: *mut uw::_Unwind_Exception,
289-
context: *mut uw::_Unwind_Context)
290-
-> uw::_Unwind_Reason_Code {
291-
rust_eh_personality_impl(version,
292-
actions,
293-
exception_class,
294-
exception_object,
295-
context)
296-
}
297-
}
298-
}
299-
}
300-
}
301-
302-
unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) -> Result<EHAction, ()> {
303-
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
304-
let mut ip_before_instr: c_int = 0;
305-
let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
306-
let eh_context = EHContext {
307-
// The return address points 1 byte past the call instruction,
308-
// which could be in the next IP range in LSDA range table.
309-
//
310-
// `ip = -1` has special meaning, so use wrapping sub to allow for that
311-
ip: if ip_before_instr != 0 { ip } else { ip.wrapping_sub(1) },
312-
func_start: uw::_Unwind_GetRegionStart(context),
313-
get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
314-
get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
315-
};
316-
eh::find_eh_action(lsda, &eh_context)
317-
}
318-
31991
// Frame unwind info registration
32092
//
32193
// Each module's image contains a frame unwind info section (usually

library/panic_unwind/src/lib.rs

-2
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,6 @@ extern "C" {
9292
fn __rust_foreign_exception() -> !;
9393
}
9494

95-
mod dwarf;
96-
9795
#[rustc_std_internal_symbol]
9896
#[allow(improper_ctypes_definitions)]
9997
pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static) {

library/panic_unwind/src/seh.rs

-10
Original file line numberDiff line numberDiff line change
@@ -323,13 +323,3 @@ pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
323323
exception.data.take().unwrap()
324324
}
325325
}
326-
327-
// This is required by the compiler to exist (e.g., it's a lang item), but
328-
// it's never actually called by the compiler because _CxxFrameHandler3
329-
// is the personality function that is always used.
330-
// Hence this is just an aborting stub.
331-
#[lang = "eh_personality"]
332-
#[cfg(not(test))]
333-
fn rust_eh_personality() {
334-
core::intrinsics::abort()
335-
}

library/std/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,7 @@ pub mod alloc;
591591

592592
// Private support modules
593593
mod panicking;
594+
mod personality;
594595

595596
#[path = "../../backtrace/src/lib.rs"]
596597
#[allow(dead_code, unused_attributes)]

library/std/src/personality.rs

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//! This module contains the implementation of the `eh_personality` lang item.
2+
//!
3+
//! The actual implementation is heavily dependent on the target since Rust
4+
//! tries to use the native stack unwinding mechanism whenever possible.
5+
//!
6+
//! This personality function is still required with `-C panic=abort` because
7+
//! it is used to catch foreign exceptions from `extern "C-unwind"` and turn
8+
//! them into aborts.
9+
//!
10+
//! Additionally, ARM EHABI uses the personality function when generating
11+
//! backtraces.
12+
13+
mod dwarf;
14+
15+
#[cfg(not(test))]
16+
cfg_if::cfg_if! {
17+
if #[cfg(target_os = "emscripten")] {
18+
mod emcc;
19+
} else if #[cfg(target_env = "msvc")] {
20+
// This is required by the compiler to exist (e.g., it's a lang item),
21+
// but it's never actually called by the compiler because
22+
// _CxxFrameHandler3 is the personality function that is always used.
23+
// Hence this is just an aborting stub.
24+
#[lang = "eh_personality"]
25+
fn rust_eh_personality() {
26+
core::intrinsics::abort()
27+
}
28+
} else if #[cfg(any(
29+
all(target_family = "windows", target_env = "gnu"),
30+
target_os = "psp",
31+
target_os = "solid_asp3",
32+
all(target_family = "unix", not(target_os = "espidf")),
33+
all(target_vendor = "fortanix", target_env = "sgx"),
34+
))] {
35+
mod gcc;
36+
} else {
37+
// Targets that don't support unwinding.
38+
// - family=wasm
39+
// - os=none ("bare metal" targets)
40+
// - os=uefi
41+
// - os=espidf
42+
// - os=hermit
43+
// - nvptx64-nvidia-cuda
44+
// - arch=avr
45+
}
46+
}

library/panic_unwind/src/dwarf/eh.rs library/std/src/personality/dwarf/eh.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#![allow(non_upper_case_globals)]
1212
#![allow(unused)]
1313

14-
use crate::dwarf::DwarfReader;
14+
use super::DwarfReader;
1515
use core::mem;
1616

1717
pub const DW_EH_PE_omit: u8 = 0xFF;
File renamed without changes.

0 commit comments

Comments
 (0)