Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/libunwind/src/Unwind-sjlj.c
35148 views
1
//===----------------------------------------------------------------------===//
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 setjump-longjump based C++ exceptions
9
//
10
//===----------------------------------------------------------------------===//
11
12
#include <unwind.h>
13
14
#include <inttypes.h>
15
#include <stdint.h>
16
#include <stdbool.h>
17
#include <stdlib.h>
18
19
#include "config.h"
20
21
/// With SJLJ based exceptions, any function that has a catch clause or needs to
22
/// do any clean up when an exception propagates through it, needs to call
23
/// \c _Unwind_SjLj_Register at the start of the function and
24
/// \c _Unwind_SjLj_Unregister at the end. The register function is called with
25
/// the address of a block of memory in the function's stack frame. The runtime
26
/// keeps a linked list (stack) of these blocks - one per thread. The calling
27
/// function also sets the personality and lsda fields of the block.
28
29
#if defined(_LIBUNWIND_BUILD_SJLJ_APIS)
30
31
struct _Unwind_FunctionContext {
32
// next function in stack of handlers
33
struct _Unwind_FunctionContext *prev;
34
35
#if defined(__ve__)
36
// VE requires to store 64 bit pointers in the buffer for SjLj exception.
37
// We expand the size of values defined here. This size must be matched
38
// to the size returned by TargetMachine::getSjLjDataSize().
39
40
// set by calling function before registering to be the landing pad
41
uint64_t resumeLocation;
42
43
// set by personality handler to be parameters passed to landing pad function
44
uint64_t resumeParameters[4];
45
#else
46
// set by calling function before registering to be the landing pad
47
uint32_t resumeLocation;
48
49
// set by personality handler to be parameters passed to landing pad function
50
uint32_t resumeParameters[4];
51
#endif
52
53
// set by calling function before registering
54
_Unwind_Personality_Fn personality; // arm offset=24
55
uintptr_t lsda; // arm offset=28
56
57
// variable length array, contains registers to restore
58
// 0 = r7, 1 = pc, 2 = sp
59
void *jbuf[];
60
};
61
62
#if defined(_LIBUNWIND_HAS_NO_THREADS)
63
# define _LIBUNWIND_THREAD_LOCAL
64
#else
65
# if __STDC_VERSION__ >= 201112L
66
# define _LIBUNWIND_THREAD_LOCAL _Thread_local
67
# elif defined(_MSC_VER)
68
# define _LIBUNWIND_THREAD_LOCAL __declspec(thread)
69
# elif defined(__GNUC__) || defined(__clang__)
70
# define _LIBUNWIND_THREAD_LOCAL __thread
71
# else
72
# error Unable to create thread local storage
73
# endif
74
#endif
75
76
77
#if !defined(FOR_DYLD)
78
79
#if defined(__APPLE__)
80
#include <System/pthread_machdep.h>
81
#else
82
static _LIBUNWIND_THREAD_LOCAL struct _Unwind_FunctionContext *stack = NULL;
83
#endif
84
85
static struct _Unwind_FunctionContext *
86
__Unwind_SjLj_GetTopOfFunctionStack(void) {
87
#if defined(__APPLE__)
88
return _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key);
89
#else
90
return stack;
91
#endif
92
}
93
94
static void
95
__Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) {
96
#if defined(__APPLE__)
97
_pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc);
98
#else
99
stack = fc;
100
#endif
101
}
102
103
#endif
104
105
106
/// Called at start of each function that catches exceptions
107
_LIBUNWIND_EXPORT void
108
_Unwind_SjLj_Register(struct _Unwind_FunctionContext *fc) {
109
fc->prev = __Unwind_SjLj_GetTopOfFunctionStack();
110
__Unwind_SjLj_SetTopOfFunctionStack(fc);
111
}
112
113
114
/// Called at end of each function that catches exceptions
115
_LIBUNWIND_EXPORT void
116
_Unwind_SjLj_Unregister(struct _Unwind_FunctionContext *fc) {
117
__Unwind_SjLj_SetTopOfFunctionStack(fc->prev);
118
}
119
120
121
static _Unwind_Reason_Code
122
unwind_phase1(struct _Unwind_Exception *exception_object) {
123
_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
124
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1: initial function-context=%p",
125
(void *)c);
126
127
// walk each frame looking for a place to stop
128
for (bool handlerNotFound = true; handlerNotFound; c = c->prev) {
129
130
// check for no more frames
131
if (c == NULL) {
132
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): reached "
133
"bottom => _URC_END_OF_STACK",
134
(void *)exception_object);
135
return _URC_END_OF_STACK;
136
}
137
138
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p", (void *)c);
139
// if there is a personality routine, ask it if it will want to stop at this
140
// frame
141
if (c->personality != NULL) {
142
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): calling "
143
"personality function %p",
144
(void *)exception_object,
145
(void *)c->personality);
146
_Unwind_Reason_Code personalityResult = (*c->personality)(
147
1, _UA_SEARCH_PHASE, exception_object->exception_class,
148
exception_object, (struct _Unwind_Context *)c);
149
switch (personalityResult) {
150
case _URC_HANDLER_FOUND:
151
// found a catch clause or locals that need destructing in this frame
152
// stop search and remember function context
153
handlerNotFound = false;
154
exception_object->private_2 = (uintptr_t) c;
155
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
156
"_URC_HANDLER_FOUND",
157
(void *)exception_object);
158
return _URC_NO_REASON;
159
160
case _URC_CONTINUE_UNWIND:
161
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
162
"_URC_CONTINUE_UNWIND",
163
(void *)exception_object);
164
// continue unwinding
165
break;
166
167
default:
168
// something went wrong
169
_LIBUNWIND_TRACE_UNWINDING(
170
"unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",
171
(void *)exception_object);
172
return _URC_FATAL_PHASE1_ERROR;
173
}
174
}
175
}
176
return _URC_NO_REASON;
177
}
178
179
180
static _Unwind_Reason_Code
181
unwind_phase2(struct _Unwind_Exception *exception_object) {
182
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)",
183
(void *)exception_object);
184
185
// walk each frame until we reach where search phase said to stop
186
_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
187
while (true) {
188
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p",
189
(void *)exception_object, (void *)c);
190
191
// check for no more frames
192
if (c == NULL) {
193
_LIBUNWIND_TRACE_UNWINDING(
194
"unwind_phase2(ex_ojb=%p): __unw_step() reached "
195
"bottom => _URC_END_OF_STACK",
196
(void *)exception_object);
197
return _URC_END_OF_STACK;
198
}
199
200
// if there is a personality routine, tell it we are unwinding
201
if (c->personality != NULL) {
202
_Unwind_Action action = _UA_CLEANUP_PHASE;
203
if ((uintptr_t) c == exception_object->private_2)
204
action = (_Unwind_Action)(
205
_UA_CLEANUP_PHASE |
206
_UA_HANDLER_FRAME); // tell personality this was the frame it marked
207
// in phase 1
208
_Unwind_Reason_Code personalityResult =
209
(*c->personality)(1, action, exception_object->exception_class,
210
exception_object, (struct _Unwind_Context *)c);
211
switch (personalityResult) {
212
case _URC_CONTINUE_UNWIND:
213
// continue unwinding
214
_LIBUNWIND_TRACE_UNWINDING(
215
"unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND",
216
(void *)exception_object);
217
if ((uintptr_t) c == exception_object->private_2) {
218
// phase 1 said we would stop at this frame, but we did not...
219
_LIBUNWIND_ABORT("during phase1 personality function said it would "
220
"stop here, but now if phase2 it did not stop here");
221
}
222
break;
223
case _URC_INSTALL_CONTEXT:
224
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): "
225
"_URC_INSTALL_CONTEXT, will resume at "
226
"landing pad %p",
227
(void *)exception_object, c->jbuf[1]);
228
// personality routine says to transfer control to landing pad
229
// we may get control back if landing pad calls _Unwind_Resume()
230
__Unwind_SjLj_SetTopOfFunctionStack(c);
231
__builtin_longjmp(c->jbuf, 1);
232
// __unw_resume() only returns if there was an error
233
return _URC_FATAL_PHASE2_ERROR;
234
default:
235
// something went wrong
236
_LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",
237
personalityResult);
238
return _URC_FATAL_PHASE2_ERROR;
239
}
240
}
241
c = c->prev;
242
}
243
244
// clean up phase did not resume at the frame that the search phase said it
245
// would
246
return _URC_FATAL_PHASE2_ERROR;
247
}
248
249
250
static _Unwind_Reason_Code
251
unwind_phase2_forced(struct _Unwind_Exception *exception_object,
252
_Unwind_Stop_Fn stop, void *stop_parameter) {
253
// walk each frame until we reach where search phase said to stop
254
_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
255
while (true) {
256
257
// get next frame (skip over first which is _Unwind_RaiseException)
258
if (c == NULL) {
259
_LIBUNWIND_TRACE_UNWINDING(
260
"unwind_phase2(ex_ojb=%p): __unw_step() reached "
261
"bottom => _URC_END_OF_STACK",
262
(void *)exception_object);
263
return _URC_END_OF_STACK;
264
}
265
266
// call stop function at each frame
267
_Unwind_Action action =
268
(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
269
_Unwind_Reason_Code stopResult =
270
(*stop)(1, action, exception_object->exception_class, exception_object,
271
(struct _Unwind_Context *)c, stop_parameter);
272
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
273
"stop function returned %d",
274
(void *)exception_object, stopResult);
275
if (stopResult != _URC_NO_REASON) {
276
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
277
"stopped by stop function",
278
(void *)exception_object);
279
return _URC_FATAL_PHASE2_ERROR;
280
}
281
282
// if there is a personality routine, tell it we are unwinding
283
if (c->personality != NULL) {
284
_Unwind_Personality_Fn p = (_Unwind_Personality_Fn)c->personality;
285
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
286
"calling personality function %p",
287
(void *)exception_object, (void *)p);
288
_Unwind_Reason_Code personalityResult =
289
(*p)(1, action, exception_object->exception_class, exception_object,
290
(struct _Unwind_Context *)c);
291
switch (personalityResult) {
292
case _URC_CONTINUE_UNWIND:
293
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
294
"personality returned _URC_CONTINUE_UNWIND",
295
(void *)exception_object);
296
// destructors called, continue unwinding
297
break;
298
case _URC_INSTALL_CONTEXT:
299
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
300
"personality returned _URC_INSTALL_CONTEXT",
301
(void *)exception_object);
302
// we may get control back if landing pad calls _Unwind_Resume()
303
__Unwind_SjLj_SetTopOfFunctionStack(c);
304
__builtin_longjmp(c->jbuf, 1);
305
break;
306
default:
307
// something went wrong
308
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
309
"personality returned %d, "
310
"_URC_FATAL_PHASE2_ERROR",
311
(void *)exception_object, personalityResult);
312
return _URC_FATAL_PHASE2_ERROR;
313
}
314
}
315
c = c->prev;
316
}
317
318
// call stop function one last time and tell it we've reached the end of the
319
// stack
320
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
321
"function with _UA_END_OF_STACK",
322
(void *)exception_object);
323
_Unwind_Action lastAction =
324
(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
325
(*stop)(1, lastAction, exception_object->exception_class, exception_object,
326
(struct _Unwind_Context *)c, stop_parameter);
327
328
// clean up phase did not resume at the frame that the search phase said it
329
// would
330
return _URC_FATAL_PHASE2_ERROR;
331
}
332
333
334
/// Called by __cxa_throw. Only returns if there is a fatal error
335
_LIBUNWIND_EXPORT _Unwind_Reason_Code
336
_Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) {
337
_LIBUNWIND_TRACE_API("_Unwind_SjLj_RaiseException(ex_obj=%p)",
338
(void *)exception_object);
339
340
// mark that this is a non-forced unwind, so _Unwind_Resume() can do the right
341
// thing
342
exception_object->private_1 = 0;
343
exception_object->private_2 = 0;
344
345
// phase 1: the search phase
346
_Unwind_Reason_Code phase1 = unwind_phase1(exception_object);
347
if (phase1 != _URC_NO_REASON)
348
return phase1;
349
350
// phase 2: the clean up phase
351
return unwind_phase2(exception_object);
352
}
353
354
355
356
/// When _Unwind_RaiseException() is in phase2, it hands control
357
/// to the personality function at each frame. The personality
358
/// may force a jump to a landing pad in that function, the landing
359
/// pad code may then call _Unwind_Resume() to continue with the
360
/// unwinding. Note: the call to _Unwind_Resume() is from compiler
361
/// generated user code. All other _Unwind_* routines are called
362
/// by the C++ runtime __cxa_* routines.
363
///
364
/// Re-throwing an exception is implemented by having the code call
365
/// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow()
366
_LIBUNWIND_EXPORT void
367
_Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) {
368
_LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)",
369
(void *)exception_object);
370
371
if (exception_object->private_1 != 0)
372
unwind_phase2_forced(exception_object,
373
(_Unwind_Stop_Fn) exception_object->private_1,
374
(void *)exception_object->private_2);
375
else
376
unwind_phase2(exception_object);
377
378
// clients assume _Unwind_Resume() does not return, so all we can do is abort.
379
_LIBUNWIND_ABORT("_Unwind_SjLj_Resume() can't return");
380
}
381
382
383
/// Called by __cxa_rethrow().
384
_LIBUNWIND_EXPORT _Unwind_Reason_Code
385
_Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) {
386
_LIBUNWIND_TRACE_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), "
387
"private_1=%" PRIuPTR,
388
(void *)exception_object, exception_object->private_1);
389
// If this is non-forced and a stopping place was found, then this is a
390
// re-throw.
391
// Call _Unwind_RaiseException() as if this was a new exception.
392
if (exception_object->private_1 == 0) {
393
return _Unwind_SjLj_RaiseException(exception_object);
394
// should return if there is no catch clause, so that __cxa_rethrow can call
395
// std::terminate()
396
}
397
398
// Call through to _Unwind_Resume() which distinguishes between forced and
399
// regular exceptions.
400
_Unwind_SjLj_Resume(exception_object);
401
_LIBUNWIND_ABORT("__Unwind_SjLj_Resume_or_Rethrow() called "
402
"_Unwind_SjLj_Resume() which unexpectedly returned");
403
}
404
405
406
/// Called by personality handler during phase 2 to get LSDA for current frame.
407
_LIBUNWIND_EXPORT uintptr_t
408
_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
409
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
410
_LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) "
411
"=> 0x%" PRIuPTR,
412
(void *)context, ufc->lsda);
413
return ufc->lsda;
414
}
415
416
417
/// Called by personality handler during phase 2 to get register values.
418
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context,
419
int index) {
420
_LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)", (void *)context,
421
index);
422
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
423
return ufc->resumeParameters[index];
424
}
425
426
427
/// Called by personality handler during phase 2 to alter register values.
428
_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
429
uintptr_t new_value) {
430
_LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%" PRIxPTR
431
")",
432
(void *)context, index, new_value);
433
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
434
ufc->resumeParameters[index] = new_value;
435
}
436
437
438
/// Called by personality handler during phase 2 to get instruction pointer.
439
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
440
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
441
_LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR,
442
(void *)context, ufc->resumeLocation + 1);
443
return ufc->resumeLocation + 1;
444
}
445
446
447
/// Called by personality handler during phase 2 to get instruction pointer.
448
/// ipBefore is a boolean that says if IP is already adjusted to be the call
449
/// site address. Normally IP is the return address.
450
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
451
int *ipBefore) {
452
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
453
*ipBefore = 0;
454
_LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%" PRIxPTR,
455
(void *)context, (void *)ipBefore,
456
ufc->resumeLocation + 1);
457
return ufc->resumeLocation + 1;
458
}
459
460
461
/// Called by personality handler during phase 2 to alter instruction pointer.
462
_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
463
uintptr_t new_value) {
464
_LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%" PRIxPTR ")",
465
(void *)context, new_value);
466
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
467
ufc->resumeLocation = new_value - 1;
468
}
469
470
471
/// Called by personality handler during phase 2 to find the start of the
472
/// function.
473
_LIBUNWIND_EXPORT uintptr_t
474
_Unwind_GetRegionStart(struct _Unwind_Context *context) {
475
// Not supported or needed for sjlj based unwinding
476
(void)context;
477
_LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p)", (void *)context);
478
return 0;
479
}
480
481
482
/// Called by personality handler during phase 2 if a foreign exception
483
/// is caught.
484
_LIBUNWIND_EXPORT void
485
_Unwind_DeleteException(struct _Unwind_Exception *exception_object) {
486
_LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",
487
(void *)exception_object);
488
if (exception_object->exception_cleanup != NULL)
489
(*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
490
exception_object);
491
}
492
493
494
495
/// Called by personality handler during phase 2 to get base address for data
496
/// relative encodings.
497
_LIBUNWIND_EXPORT uintptr_t
498
_Unwind_GetDataRelBase(struct _Unwind_Context *context) {
499
// Not supported or needed for sjlj based unwinding
500
(void)context;
501
_LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context);
502
_LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");
503
}
504
505
506
/// Called by personality handler during phase 2 to get base address for text
507
/// relative encodings.
508
_LIBUNWIND_EXPORT uintptr_t
509
_Unwind_GetTextRelBase(struct _Unwind_Context *context) {
510
// Not supported or needed for sjlj based unwinding
511
(void)context;
512
_LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context);
513
_LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");
514
}
515
516
517
/// Called by personality handler to get "Call Frame Area" for current frame.
518
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
519
_LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p)", (void *)context);
520
if (context != NULL) {
521
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
522
// Setjmp/longjmp based exceptions don't have a true CFA.
523
// Instead, the SP in the jmpbuf is the closest approximation.
524
return (uintptr_t) ufc->jbuf[2];
525
}
526
return 0;
527
}
528
529
#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS)
530
531