|
39 | 39 | use alloc::boxed::Box; |
40 | 40 | use core::any::Any; |
41 | 41 |
|
42 | | -use crate::dwarf::eh::{self, EHAction, EHContext}; |
43 | | -use libc::{c_int, uintptr_t}; |
44 | 42 | use unwind as uw; |
45 | 43 |
|
46 | 44 | #[repr(C)] |
@@ -89,263 +87,3 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class { |
89 | 87 | // M O Z \0 R U S T -- vendor, language |
90 | 88 | 0x4d4f5a_00_52555354 |
91 | 89 | } |
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 | | -} |
0 commit comments