|
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)]
|
@@ -90,232 +88,6 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
|
90 | 88 | 0x4d4f5a_00_52555354
|
91 | 89 | }
|
92 | 90 |
|
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 | 91 | // Frame unwind info registration
|
320 | 92 | //
|
321 | 93 | // Each module's image contains a frame unwind info section (usually
|
|
0 commit comments