Skip to content

Commit 91f128b

Browse files
committed
Auto merge of #92845 - Amanieu:std_personality, r=Mark-Simulacrum
Move EH 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. Fixes #41004
2 parents 1e978a3 + a7e4794 commit 91f128b

File tree

16 files changed

+379
-339
lines changed

16 files changed

+379
-339
lines changed

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

+7-11
Original file line numberDiff line numberDiff line change
@@ -103,18 +103,14 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
103103
}
104104
})
105105
.map(|def_id| {
106-
let (export_level, used) = if special_runtime_crate {
107-
let name = tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())).name;
108-
// We won't link right if these symbols are stripped during LTO.
109-
let used = match name {
110-
"rust_eh_personality"
111-
| "rust_eh_register_frames"
112-
| "rust_eh_unregister_frames" => true,
113-
_ => false,
114-
};
115-
(SymbolExportLevel::Rust, used)
106+
// We won't link right if this symbol is stripped during LTO.
107+
let name = tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())).name;
108+
let used = name == "rust_eh_personality";
109+
110+
let export_level = if special_runtime_crate {
111+
SymbolExportLevel::Rust
116112
} else {
117-
(symbol_export_level(tcx, def_id.to_def_id()), false)
113+
symbol_export_level(tcx, def_id.to_def_id())
118114
};
119115
let codegen_attrs = tcx.codegen_fn_attrs(def_id.to_def_id());
120116
debug!(

library/panic_abort/src/lib.rs

+4-29
Original file line numberDiff line numberDiff line change
@@ -113,27 +113,11 @@ 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-
}
116+
// In the past this module used to contain stubs for the personality
117+
// functions of various platforms, but these where removed when personality
118+
// functions were moved to std.
135119

136-
// Similar to above, this corresponds to the `eh_catch_typeinfo` lang item
120+
// This corresponds to the `eh_catch_typeinfo` lang item
137121
// that's only used on Emscripten currently.
138122
//
139123
// Since panics don't generate exceptions and foreign exceptions are
@@ -143,13 +127,4 @@ pub mod personalities {
143127
#[allow(non_upper_case_globals)]
144128
#[cfg(target_os = "emscripten")]
145129
static rust_eh_catch_typeinfo: [usize; 2] = [0; 2];
146-
147-
// These two are called by our startup objects on i686-pc-windows-gnu, but
148-
// they don't need to do anything so the bodies are nops.
149-
#[rustc_std_internal_symbol]
150-
#[cfg(all(target_os = "windows", target_env = "gnu", target_arch = "x86"))]
151-
pub extern "C" fn rust_eh_register_frames() {}
152-
#[rustc_std_internal_symbol]
153-
#[cfg(all(target_os = "windows", target_env = "gnu", target_arch = "x86"))]
154-
pub extern "C" fn rust_eh_unregister_frames() {}
155130
}

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

-262
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)]
@@ -89,263 +87,3 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
8987
// M O Z \0 R U S T -- vendor, language
9088
0x4d4f5a_00_52555354
9189
}
92-
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-
319-
// Frame unwind info registration
320-
//
321-
// Each module's image contains a frame unwind info section (usually
322-
// ".eh_frame"). When a module is loaded/unloaded into the process, the
323-
// unwinder must be informed about the location of this section in memory. The
324-
// methods of achieving that vary by the platform. On some (e.g., Linux), the
325-
// unwinder can discover unwind info sections on its own (by dynamically
326-
// enumerating currently loaded modules via the dl_iterate_phdr() API and
327-
// finding their ".eh_frame" sections); Others, like Windows, require modules
328-
// to actively register their unwind info sections via unwinder API.
329-
//
330-
// This module defines two symbols which are referenced and called from
331-
// rsbegin.rs to register our information with the GCC runtime. The
332-
// implementation of stack unwinding is (for now) deferred to libgcc_eh, however
333-
// Rust crates use these Rust-specific entry points to avoid potential clashes
334-
// with any GCC runtime.
335-
#[cfg(all(target_os = "windows", target_arch = "x86", target_env = "gnu"))]
336-
pub mod eh_frame_registry {
337-
extern "C" {
338-
fn __register_frame_info(eh_frame_begin: *const u8, object: *mut u8);
339-
fn __deregister_frame_info(eh_frame_begin: *const u8, object: *mut u8);
340-
}
341-
342-
#[rustc_std_internal_symbol]
343-
pub unsafe extern "C" fn rust_eh_register_frames(eh_frame_begin: *const u8, object: *mut u8) {
344-
__register_frame_info(eh_frame_begin, object);
345-
}
346-
347-
#[rustc_std_internal_symbol]
348-
pub unsafe extern "C" fn rust_eh_unregister_frames(eh_frame_begin: *const u8, object: *mut u8) {
349-
__deregister_frame_info(eh_frame_begin, object);
350-
}
351-
}

library/panic_unwind/src/lib.rs

-5
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,6 @@ cfg_if::cfg_if! {
5252
all(target_family = "unix", not(target_os = "espidf")),
5353
all(target_vendor = "fortanix", target_env = "sgx"),
5454
))] {
55-
// Rust runtime's startup objects depend on these symbols, so make them public.
56-
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
57-
pub use real_imp::eh_frame_registry::*;
5855
#[path = "gcc.rs"]
5956
mod real_imp;
6057
} else {
@@ -92,8 +89,6 @@ extern "C" {
9289
fn __rust_foreign_exception() -> !;
9390
}
9491

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

0 commit comments

Comments
 (0)