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