1 | //===------------------------- UnwindLevel1.c -----------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | // |
8 | // Implements C++ ABI Exception Handling Level 1 as documented at: |
9 | // http://mentorembedded.github.io/cxx-abi/abi-eh.html |
10 | // using libunwind |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | // ARM EHABI does not specify _Unwind_{Get,Set}{GR,IP}(). Thus, we are |
15 | // defining inline functions to delegate the function calls to |
16 | // _Unwind_VRS_{Get,Set}(). However, some applications might declare the |
17 | // function protetype directly (instead of including <unwind.h>), thus we need |
18 | // to export these functions from libunwind.so as well. |
19 | #define _LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE 1 |
20 | |
21 | #include <inttypes.h> |
22 | #include <stdint.h> |
23 | #include <stdbool.h> |
24 | #include <stdlib.h> |
25 | #include <stdio.h> |
26 | #include <string.h> |
27 | |
28 | #include "config.h" |
29 | #include "libunwind.h" |
30 | #include "libunwind_ext.h" |
31 | #include "unwind.h" |
32 | |
33 | #if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) |
34 | |
35 | #ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND |
36 | |
37 | static _Unwind_Reason_Code |
38 | unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { |
39 | __unw_init_local(cursor, uc); |
40 | |
41 | // Walk each frame looking for a place to stop. |
42 | bool handlerNotFound = true; |
43 | while (handlerNotFound) { |
44 | // Ask libunwind to get next frame (skip over first which is |
45 | // _Unwind_RaiseException). |
46 | int stepResult = __unw_step(cursor); |
47 | if (stepResult == 0) { |
48 | _LIBUNWIND_TRACE_UNWINDING( |
49 | "unwind_phase1(ex_ojb=%p): __unw_step() reached " |
50 | "bottom => _URC_END_OF_STACK" , |
51 | (void *)exception_object); |
52 | return _URC_END_OF_STACK; |
53 | } else if (stepResult < 0) { |
54 | _LIBUNWIND_TRACE_UNWINDING( |
55 | "unwind_phase1(ex_ojb=%p): __unw_step failed => " |
56 | "_URC_FATAL_PHASE1_ERROR" , |
57 | (void *)exception_object); |
58 | return _URC_FATAL_PHASE1_ERROR; |
59 | } |
60 | |
61 | // See if frame has code to run (has personality routine). |
62 | unw_proc_info_t frameInfo; |
63 | unw_word_t sp; |
64 | if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { |
65 | _LIBUNWIND_TRACE_UNWINDING( |
66 | "unwind_phase1(ex_ojb=%p): __unw_get_proc_info " |
67 | "failed => _URC_FATAL_PHASE1_ERROR" , |
68 | (void *)exception_object); |
69 | return _URC_FATAL_PHASE1_ERROR; |
70 | } |
71 | |
72 | // When tracing, print state information. |
73 | if (_LIBUNWIND_TRACING_UNWINDING) { |
74 | char functionBuf[512]; |
75 | const char *functionName = functionBuf; |
76 | unw_word_t offset; |
77 | if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), |
78 | &offset) != UNW_ESUCCESS) || |
79 | (frameInfo.start_ip + offset > frameInfo.end_ip)) |
80 | functionName = ".anonymous." ; |
81 | unw_word_t pc; |
82 | __unw_get_reg(cursor, UNW_REG_IP, &pc); |
83 | _LIBUNWIND_TRACE_UNWINDING( |
84 | "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR |
85 | ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "" , |
86 | (void *)exception_object, pc, frameInfo.start_ip, functionName, |
87 | frameInfo.lsda, frameInfo.handler); |
88 | } |
89 | |
90 | // If there is a personality routine, ask it if it will want to stop at |
91 | // this frame. |
92 | if (frameInfo.handler != 0) { |
93 | __personality_routine p = |
94 | (__personality_routine)(uintptr_t)(frameInfo.handler); |
95 | _LIBUNWIND_TRACE_UNWINDING( |
96 | "unwind_phase1(ex_ojb=%p): calling personality function %p" , |
97 | (void *)exception_object, (void *)(uintptr_t)p); |
98 | _Unwind_Reason_Code personalityResult = |
99 | (*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class, |
100 | exception_object, (struct _Unwind_Context *)(cursor)); |
101 | switch (personalityResult) { |
102 | case _URC_HANDLER_FOUND: |
103 | // found a catch clause or locals that need destructing in this frame |
104 | // stop search and remember stack pointer at the frame |
105 | handlerNotFound = false; |
106 | __unw_get_reg(cursor, UNW_REG_SP, &sp); |
107 | exception_object->private_2 = (uintptr_t)sp; |
108 | _LIBUNWIND_TRACE_UNWINDING( |
109 | "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND" , |
110 | (void *)exception_object); |
111 | return _URC_NO_REASON; |
112 | |
113 | case _URC_CONTINUE_UNWIND: |
114 | _LIBUNWIND_TRACE_UNWINDING( |
115 | "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND" , |
116 | (void *)exception_object); |
117 | // continue unwinding |
118 | break; |
119 | |
120 | default: |
121 | // something went wrong |
122 | _LIBUNWIND_TRACE_UNWINDING( |
123 | "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR" , |
124 | (void *)exception_object); |
125 | return _URC_FATAL_PHASE1_ERROR; |
126 | } |
127 | } |
128 | } |
129 | return _URC_NO_REASON; |
130 | } |
131 | |
132 | |
133 | static _Unwind_Reason_Code |
134 | unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { |
135 | __unw_init_local(cursor, uc); |
136 | |
137 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)" , |
138 | (void *)exception_object); |
139 | |
140 | // Walk each frame until we reach where search phase said to stop. |
141 | while (true) { |
142 | |
143 | // Ask libunwind to get next frame (skip over first which is |
144 | // _Unwind_RaiseException). |
145 | int stepResult = __unw_step(cursor); |
146 | if (stepResult == 0) { |
147 | _LIBUNWIND_TRACE_UNWINDING( |
148 | "unwind_phase2(ex_ojb=%p): __unw_step() reached " |
149 | "bottom => _URC_END_OF_STACK" , |
150 | (void *)exception_object); |
151 | return _URC_END_OF_STACK; |
152 | } else if (stepResult < 0) { |
153 | _LIBUNWIND_TRACE_UNWINDING( |
154 | "unwind_phase2(ex_ojb=%p): __unw_step failed => " |
155 | "_URC_FATAL_PHASE1_ERROR" , |
156 | (void *)exception_object); |
157 | return _URC_FATAL_PHASE2_ERROR; |
158 | } |
159 | |
160 | // Get info about this frame. |
161 | unw_word_t sp; |
162 | unw_proc_info_t frameInfo; |
163 | __unw_get_reg(cursor, UNW_REG_SP, &sp); |
164 | if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { |
165 | _LIBUNWIND_TRACE_UNWINDING( |
166 | "unwind_phase2(ex_ojb=%p): __unw_get_proc_info " |
167 | "failed => _URC_FATAL_PHASE1_ERROR" , |
168 | (void *)exception_object); |
169 | return _URC_FATAL_PHASE2_ERROR; |
170 | } |
171 | |
172 | // When tracing, print state information. |
173 | if (_LIBUNWIND_TRACING_UNWINDING) { |
174 | char functionBuf[512]; |
175 | const char *functionName = functionBuf; |
176 | unw_word_t offset; |
177 | if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), |
178 | &offset) != UNW_ESUCCESS) || |
179 | (frameInfo.start_ip + offset > frameInfo.end_ip)) |
180 | functionName = ".anonymous." ; |
181 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR |
182 | ", func=%s, sp=0x%" PRIxPTR ", lsda=0x%" PRIxPTR |
183 | ", personality=0x%" PRIxPTR, |
184 | (void *)exception_object, frameInfo.start_ip, |
185 | functionName, sp, frameInfo.lsda, |
186 | frameInfo.handler); |
187 | } |
188 | |
189 | // If there is a personality routine, tell it we are unwinding. |
190 | if (frameInfo.handler != 0) { |
191 | __personality_routine p = |
192 | (__personality_routine)(uintptr_t)(frameInfo.handler); |
193 | _Unwind_Action action = _UA_CLEANUP_PHASE; |
194 | if (sp == exception_object->private_2) { |
195 | // Tell personality this was the frame it marked in phase 1. |
196 | action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); |
197 | } |
198 | _Unwind_Reason_Code personalityResult = |
199 | (*p)(1, action, exception_object->exception_class, exception_object, |
200 | (struct _Unwind_Context *)(cursor)); |
201 | switch (personalityResult) { |
202 | case _URC_CONTINUE_UNWIND: |
203 | // Continue unwinding |
204 | _LIBUNWIND_TRACE_UNWINDING( |
205 | "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND" , |
206 | (void *)exception_object); |
207 | if (sp == exception_object->private_2) { |
208 | // Phase 1 said we would stop at this frame, but we did not... |
209 | _LIBUNWIND_ABORT("during phase1 personality function said it would " |
210 | "stop here, but now in phase2 it did not stop here" ); |
211 | } |
212 | break; |
213 | case _URC_INSTALL_CONTEXT: |
214 | _LIBUNWIND_TRACE_UNWINDING( |
215 | "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT" , |
216 | (void *)exception_object); |
217 | // Personality routine says to transfer control to landing pad. |
218 | // We may get control back if landing pad calls _Unwind_Resume(). |
219 | if (_LIBUNWIND_TRACING_UNWINDING) { |
220 | unw_word_t pc; |
221 | __unw_get_reg(cursor, UNW_REG_IP, &pc); |
222 | __unw_get_reg(cursor, UNW_REG_SP, &sp); |
223 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " |
224 | "user code with ip=0x%" PRIxPTR |
225 | ", sp=0x%" PRIxPTR, |
226 | (void *)exception_object, pc, sp); |
227 | } |
228 | __unw_resume(cursor); |
229 | // __unw_resume() only returns if there was an error. |
230 | return _URC_FATAL_PHASE2_ERROR; |
231 | default: |
232 | // Personality routine returned an unknown result code. |
233 | _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d" , |
234 | personalityResult); |
235 | return _URC_FATAL_PHASE2_ERROR; |
236 | } |
237 | } |
238 | } |
239 | |
240 | // Clean up phase did not resume at the frame that the search phase |
241 | // said it would... |
242 | return _URC_FATAL_PHASE2_ERROR; |
243 | } |
244 | |
245 | static _Unwind_Reason_Code |
246 | unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, |
247 | _Unwind_Exception *exception_object, |
248 | _Unwind_Stop_Fn stop, void *stop_parameter) { |
249 | __unw_init_local(cursor, uc); |
250 | |
251 | // Walk each frame until we reach where search phase said to stop |
252 | while (__unw_step(cursor) > 0) { |
253 | |
254 | // Update info about this frame. |
255 | unw_proc_info_t frameInfo; |
256 | if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { |
257 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): __unw_step " |
258 | "failed => _URC_END_OF_STACK" , |
259 | (void *)exception_object); |
260 | return _URC_FATAL_PHASE2_ERROR; |
261 | } |
262 | |
263 | // When tracing, print state information. |
264 | if (_LIBUNWIND_TRACING_UNWINDING) { |
265 | char functionBuf[512]; |
266 | const char *functionName = functionBuf; |
267 | unw_word_t offset; |
268 | if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), |
269 | &offset) != UNW_ESUCCESS) || |
270 | (frameInfo.start_ip + offset > frameInfo.end_ip)) |
271 | functionName = ".anonymous." ; |
272 | _LIBUNWIND_TRACE_UNWINDING( |
273 | "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR |
274 | ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR, |
275 | (void *)exception_object, frameInfo.start_ip, functionName, |
276 | frameInfo.lsda, frameInfo.handler); |
277 | } |
278 | |
279 | // Call stop function at each frame. |
280 | _Unwind_Action action = |
281 | (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); |
282 | _Unwind_Reason_Code stopResult = |
283 | (*stop)(1, action, exception_object->exception_class, exception_object, |
284 | (struct _Unwind_Context *)(cursor), stop_parameter); |
285 | _LIBUNWIND_TRACE_UNWINDING( |
286 | "unwind_phase2_forced(ex_ojb=%p): stop function returned %d" , |
287 | (void *)exception_object, stopResult); |
288 | if (stopResult != _URC_NO_REASON) { |
289 | _LIBUNWIND_TRACE_UNWINDING( |
290 | "unwind_phase2_forced(ex_ojb=%p): stopped by stop function" , |
291 | (void *)exception_object); |
292 | return _URC_FATAL_PHASE2_ERROR; |
293 | } |
294 | |
295 | // If there is a personality routine, tell it we are unwinding. |
296 | if (frameInfo.handler != 0) { |
297 | __personality_routine p = |
298 | (__personality_routine)(intptr_t)(frameInfo.handler); |
299 | _LIBUNWIND_TRACE_UNWINDING( |
300 | "unwind_phase2_forced(ex_ojb=%p): calling personality function %p" , |
301 | (void *)exception_object, (void *)(uintptr_t)p); |
302 | _Unwind_Reason_Code personalityResult = |
303 | (*p)(1, action, exception_object->exception_class, exception_object, |
304 | (struct _Unwind_Context *)(cursor)); |
305 | switch (personalityResult) { |
306 | case _URC_CONTINUE_UNWIND: |
307 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " |
308 | "personality returned " |
309 | "_URC_CONTINUE_UNWIND" , |
310 | (void *)exception_object); |
311 | // Destructors called, continue unwinding |
312 | break; |
313 | case _URC_INSTALL_CONTEXT: |
314 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " |
315 | "personality returned " |
316 | "_URC_INSTALL_CONTEXT" , |
317 | (void *)exception_object); |
318 | // We may get control back if landing pad calls _Unwind_Resume(). |
319 | __unw_resume(cursor); |
320 | break; |
321 | default: |
322 | // Personality routine returned an unknown result code. |
323 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " |
324 | "personality returned %d, " |
325 | "_URC_FATAL_PHASE2_ERROR" , |
326 | (void *)exception_object, personalityResult); |
327 | return _URC_FATAL_PHASE2_ERROR; |
328 | } |
329 | } |
330 | } |
331 | |
332 | // Call stop function one last time and tell it we've reached the end |
333 | // of the stack. |
334 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " |
335 | "function with _UA_END_OF_STACK" , |
336 | (void *)exception_object); |
337 | _Unwind_Action lastAction = |
338 | (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); |
339 | (*stop)(1, lastAction, exception_object->exception_class, exception_object, |
340 | (struct _Unwind_Context *)(cursor), stop_parameter); |
341 | |
342 | // Clean up phase did not resume at the frame that the search phase said it |
343 | // would. |
344 | return _URC_FATAL_PHASE2_ERROR; |
345 | } |
346 | |
347 | |
348 | /// Called by __cxa_throw. Only returns if there is a fatal error. |
349 | _LIBUNWIND_EXPORT _Unwind_Reason_Code |
350 | _Unwind_RaiseException(_Unwind_Exception *exception_object) { |
351 | _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)" , |
352 | (void *)exception_object); |
353 | unw_context_t uc; |
354 | unw_cursor_t cursor; |
355 | __unw_getcontext(&uc); |
356 | |
357 | // Mark that this is a non-forced unwind, so _Unwind_Resume() |
358 | // can do the right thing. |
359 | exception_object->private_1 = 0; |
360 | exception_object->private_2 = 0; |
361 | |
362 | // phase 1: the search phase |
363 | _Unwind_Reason_Code phase1 = unwind_phase1(&uc, &cursor, exception_object); |
364 | if (phase1 != _URC_NO_REASON) |
365 | return phase1; |
366 | |
367 | // phase 2: the clean up phase |
368 | return unwind_phase2(&uc, &cursor, exception_object); |
369 | } |
370 | |
371 | |
372 | |
373 | /// When _Unwind_RaiseException() is in phase2, it hands control |
374 | /// to the personality function at each frame. The personality |
375 | /// may force a jump to a landing pad in that function, the landing |
376 | /// pad code may then call _Unwind_Resume() to continue with the |
377 | /// unwinding. Note: the call to _Unwind_Resume() is from compiler |
378 | /// geneated user code. All other _Unwind_* routines are called |
379 | /// by the C++ runtime __cxa_* routines. |
380 | /// |
381 | /// Note: re-throwing an exception (as opposed to continuing the unwind) |
382 | /// is implemented by having the code call __cxa_rethrow() which |
383 | /// in turn calls _Unwind_Resume_or_Rethrow(). |
384 | _LIBUNWIND_EXPORT void |
385 | _Unwind_Resume(_Unwind_Exception *exception_object) { |
386 | _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)" , (void *)exception_object); |
387 | unw_context_t uc; |
388 | unw_cursor_t cursor; |
389 | __unw_getcontext(&uc); |
390 | |
391 | if (exception_object->private_1 != 0) |
392 | unwind_phase2_forced(&uc, &cursor, exception_object, |
393 | (_Unwind_Stop_Fn) exception_object->private_1, |
394 | (void *)exception_object->private_2); |
395 | else |
396 | unwind_phase2(&uc, &cursor, exception_object); |
397 | |
398 | // Clients assume _Unwind_Resume() does not return, so all we can do is abort. |
399 | _LIBUNWIND_ABORT("_Unwind_Resume() can't return" ); |
400 | } |
401 | |
402 | |
403 | |
404 | /// Not used by C++. |
405 | /// Unwinds stack, calling "stop" function at each frame. |
406 | /// Could be used to implement longjmp(). |
407 | _LIBUNWIND_EXPORT _Unwind_Reason_Code |
408 | _Unwind_ForcedUnwind(_Unwind_Exception *exception_object, |
409 | _Unwind_Stop_Fn stop, void *stop_parameter) { |
410 | _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)" , |
411 | (void *)exception_object, (void *)(uintptr_t)stop); |
412 | unw_context_t uc; |
413 | unw_cursor_t cursor; |
414 | __unw_getcontext(&uc); |
415 | |
416 | // Mark that this is a forced unwind, so _Unwind_Resume() can do |
417 | // the right thing. |
418 | exception_object->private_1 = (uintptr_t) stop; |
419 | exception_object->private_2 = (uintptr_t) stop_parameter; |
420 | |
421 | // do it |
422 | return unwind_phase2_forced(&uc, &cursor, exception_object, stop, stop_parameter); |
423 | } |
424 | |
425 | |
426 | /// Called by personality handler during phase 2 to get LSDA for current frame. |
427 | _LIBUNWIND_EXPORT uintptr_t |
428 | _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { |
429 | unw_cursor_t *cursor = (unw_cursor_t *)context; |
430 | unw_proc_info_t frameInfo; |
431 | uintptr_t result = 0; |
432 | if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) |
433 | result = (uintptr_t)frameInfo.lsda; |
434 | _LIBUNWIND_TRACE_API( |
435 | "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR, |
436 | (void *)context, result); |
437 | if (result != 0) { |
438 | if (*((uint8_t *)result) != 0xFF) |
439 | _LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF" , |
440 | result); |
441 | } |
442 | return result; |
443 | } |
444 | |
445 | |
446 | /// Called by personality handler during phase 2 to find the start of the |
447 | /// function. |
448 | _LIBUNWIND_EXPORT uintptr_t |
449 | _Unwind_GetRegionStart(struct _Unwind_Context *context) { |
450 | unw_cursor_t *cursor = (unw_cursor_t *)context; |
451 | unw_proc_info_t frameInfo; |
452 | uintptr_t result = 0; |
453 | if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) |
454 | result = (uintptr_t)frameInfo.start_ip; |
455 | _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR, |
456 | (void *)context, result); |
457 | return result; |
458 | } |
459 | |
460 | #endif // !_LIBUNWIND_SUPPORT_SEH_UNWIND |
461 | |
462 | /// Called by personality handler during phase 2 if a foreign exception |
463 | // is caught. |
464 | _LIBUNWIND_EXPORT void |
465 | _Unwind_DeleteException(_Unwind_Exception *exception_object) { |
466 | _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)" , |
467 | (void *)exception_object); |
468 | if (exception_object->exception_cleanup != NULL) |
469 | (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, |
470 | exception_object); |
471 | } |
472 | |
473 | /// Called by personality handler during phase 2 to get register values. |
474 | _LIBUNWIND_EXPORT uintptr_t |
475 | _Unwind_GetGR(struct _Unwind_Context *context, int index) { |
476 | unw_cursor_t *cursor = (unw_cursor_t *)context; |
477 | unw_word_t result; |
478 | __unw_get_reg(cursor, index, &result); |
479 | _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIxPTR, |
480 | (void *)context, index, result); |
481 | return (uintptr_t)result; |
482 | } |
483 | |
484 | /// Called by personality handler during phase 2 to alter register values. |
485 | _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, |
486 | uintptr_t value) { |
487 | _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIxPTR |
488 | ")" , |
489 | (void *)context, index, value); |
490 | unw_cursor_t *cursor = (unw_cursor_t *)context; |
491 | __unw_set_reg(cursor, index, value); |
492 | } |
493 | |
494 | /// Called by personality handler during phase 2 to get instruction pointer. |
495 | _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { |
496 | unw_cursor_t *cursor = (unw_cursor_t *)context; |
497 | unw_word_t result; |
498 | __unw_get_reg(cursor, UNW_REG_IP, &result); |
499 | _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR, |
500 | (void *)context, result); |
501 | return (uintptr_t)result; |
502 | } |
503 | |
504 | /// Called by personality handler during phase 2 to alter instruction pointer, |
505 | /// such as setting where the landing pad is, so _Unwind_Resume() will |
506 | /// start executing in the landing pad. |
507 | _LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, |
508 | uintptr_t value) { |
509 | _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIxPTR ")" , |
510 | (void *)context, value); |
511 | unw_cursor_t *cursor = (unw_cursor_t *)context; |
512 | __unw_set_reg(cursor, UNW_REG_IP, value); |
513 | } |
514 | |
515 | #endif // !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) |
516 | |