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