1 //===----------------------------------------------------------------------===//
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
8 // This file implements the personality and helper functions for the state
9 // table based EH used by IBM legacy compilers xlC and xlclang++ on AIX.
11 //===----------------------------------------------------------------------===//
15 #include <sys/debug.h>
17 #if !__has_cpp_attribute(clang::optnone)
18 #error This file requires clang::optnone attribute support
22 The legacy IBM xlC and xlclang++ compilers use the state table for EH
23 instead of the range table. Destructors, or addresses of the possible catch
24 sites or cleanup code are specified in the state table which is a finite
25 state machine (FSM). Each function that has a state table also has an
26 autolocal state variable. The state variable represents the current state
27 of the function for EH and is found through the traceback table of the
28 function during unwinding, which is located at the end of each function.
29 The FSM is an array of state entries. Each state entry has the following
32 * offset/address/pointer - the offset used to locate the object, or the
33 address of a global object, or the address of the next state if it is an
34 old conditional state change entry;
35 * dtor/landing pad - address of the destructor function to invoke,
36 or address of the catch block or cleanup code in the user code to branch to;
37 * element count/action flag - the number of elements or the flag for actions;
38 * element size - if the object is an array this is the size of one element
40 * flags - flags used to control how fields in the entry are interpreted;
41 * next state - the state to execute next after the action for this state is
42 performed. The value of zero indicates the end of the state for this
45 The following is the description of 'element count/action flag' field.
46 +-----------------------------------------------------------------------------+
47 | value | description | action |
48 +-------+------------------------+--------------------------------------------+
49 | > 1 | object is an array | calls __cxa_vec_cleanup to run dtor for |
50 | | | each member of the array |
51 +-------+------------------------+--------------------------------------------+
52 | 1, 0 | object is a scalar | calls dtor for the object |
53 +-------+------------------------+--------------------------------------------+
54 | -1 | begin catch | branches to the handler which performes |
55 | | | catch-match. If there is no catch that |
56 | | | matches the exception it will be rethrown |
57 +-------+------------------------+--------------------------------------------+
58 | -2 | end catch | ends current catch block and continues |
59 | | | attempting to catch the exception |
60 +-------+------------------------+--------------------------------------------+
61 | -3 | delete the object | calls the delete function of the object |
62 +-------+------------------------+--------------------------------------------+
63 | -4 | cleanup label | branches to the user code for cleaning up |
64 +-------+------------------------+--------------------------------------------+
67 namespace __cxxabiv1 {
71 // Macros for debugging the state table parsing.
73 # define _LIBCXXABI_TRACE_STATETAB(msg, ...)
74 # define _LIBCXXABI_TRACE_STATETAB0(msg)
75 # define _LIBCXXABI_TRACE_STATETAB1(msg)
76 # define _LIBCXXABI_TRACING_STATETAB 0
78 static bool state_tab_dbg() {
79 static bool checked = false;
80 static bool log = false;
82 log = (getenv("LIBCXXABI_PRINT_STATTAB") != NULL);
88 # define _LIBCXXABI_TRACE_STATETAB(msg, ...) \
90 if (state_tab_dbg()) \
91 fprintf(stderr, "libcxxabi: " msg, __VA_ARGS__); \
93 # define _LIBCXXABI_TRACE_STATETAB0(msg) \
95 if (state_tab_dbg()) \
96 fprintf(stderr, "libcxxabi: " msg); \
98 # define _LIBCXXABI_TRACE_STATETAB1(msg) \
100 if (state_tab_dbg()) \
101 fprintf(stderr, msg); \
104 # define _LIBCXXABI_TRACING_STATETAB state_tab_dbg()
107 namespace __state_table_eh {
109 using destruct_f = void (*)(void*);
111 // Definition of flags for the state table entry field 'action flag'.
112 enum FSMEntryCount : intptr_t { beginCatch = -1, endCatch = -2, deleteObject = -3, cleanupLabel = -4, terminate = -5 };
114 // Definition of flags for the state table entry field 'flags'.
115 enum FSMEntryFlag : int16_t {
116 indirect = 0x100, // Object was thrown from a function where
117 // the return value optimization was used.
118 oldConditionalStateChange = 0x400, // State table entry is an indirect state
119 // change, dereference the address in
120 // offset as int for the target state.
121 // This is deprecated. This indicates
122 // the address is direct. (static local).
123 conditionalStateChange = 0x800, // State table entry is an indirect state
124 // change, dereference the address in
125 // offset as int for the target state.
126 // The temporary is an automatic. State
127 // change is used in cases such as
128 // (b?(T1(),foo()):(T2(),foo())),throw 42;
129 // which causes a conditional state change
130 // so that we know if T1 or T2 need to be
132 thisFlag = 0x01, // The address of the object for the
133 // cleanup action is based on the
134 // StateVariable::thisValue.
135 vBaseFlag = 0x02, // The object is of a virtual base class.
136 globalObj = 0x04 // FSMEntry::address is the address of
141 // The finite state machine to be walked.
144 // Offset of the object within its stack frame or containing object.
146 // Address of a global object.
148 // Address of the next state if it is an old conditional state change entry.
149 intptr_t nextStatePtr;
152 // Address of the destructor function.
153 void (*destructor)(void*, size_t);
154 // The address of the catch block or cleanup code.
158 // The flag for actions (when the value is negative).
159 FSMEntryCount actionFlag;
160 // The element count (when the value is positive or zero).
169 uint32_t magic; // Magic number of the state table.
170 int32_t numberOfStates;
171 FSMEntry table[1]; // Actually table[numberOfStates].
174 // The state variable on the stack.
175 struct StateVariable {
179 int32_t ignoreVBasePtrs;
183 // State table magic number
184 enum FSMMagic : uint32_t {
185 number = 0xbeefdead, // State table generated by xlC compiler.
186 number2 = 0xbeeedead, // State table generated by early version xlC compiler.
187 number3 = 0x1cedbeef // State table generated by xlclang++ compiler.
190 constexpr size_t dtorArgument = 0x02; // Flag to destructor indicating to free
191 // virtual bases, don't delete object.
193 static void invoke_destructor(FSMEntry* fsmEntry, void* addr) {
194 _LIBCXXABI_TRACE_STATETAB("Destruct object=%p, fsmEntry=%p\n", addr, reinterpret_cast<void*>(fsmEntry));
196 if (fsmEntry->elementCount == 1) {
197 _LIBCXXABI_TRACE_STATETAB0("calling scalar destructor\n");
198 (*fsmEntry->destructor)(addr, dtorArgument);
199 _LIBCXXABI_TRACE_STATETAB0("returned from scalar destructor\n");
201 _LIBCXXABI_TRACE_STATETAB0("calling vector destructor\n");
202 __cxa_vec_cleanup(addr, reinterpret_cast<size_t>(fsmEntry->elementCount), fsmEntry->elemSize,
203 reinterpret_cast<destruct_f>(fsmEntry->destructor));
204 _LIBCXXABI_TRACE_STATETAB0("returned from vector destructor\n");
207 _LIBCXXABI_TRACE_STATETAB0("Uncaught exception in destructor, terminating\n");
212 static void invoke_delete(FSMEntry* fsmEntry, void* addr) {
213 char* objectAddress = *reinterpret_cast<char**>(addr);
215 _LIBCXXABI_TRACE_STATETAB("Delete object=%p, fsmEntry=%p\n", reinterpret_cast<void*>(objectAddress),
216 reinterpret_cast<void*>(fsmEntry));
218 _LIBCXXABI_TRACE_STATETAB0("..calling delete()\n");
219 // 'destructor' holds a function pointer to delete().
220 (*fsmEntry->destructor)(objectAddress, fsmEntry->elemSize);
221 _LIBCXXABI_TRACE_STATETAB0("..returned from delete()\n");
223 _LIBCXXABI_TRACE_STATETAB0("Uncaught exception in delete(), terminating\n");
228 // Get the frame address of the current function from its traceback table
229 // which is at the end of each function.
230 static uintptr_t get_frame_addr(_Unwind_Context* context) {
231 int framePointerReg = 1; // default frame pointer == SP.
232 uint32_t* p = reinterpret_cast<uint32_t*>(_Unwind_GetIP(context));
234 // Keep looking forward until a word of 0 is found. The traceback
235 // table starts at the following word.
238 tbtable* TBTable = reinterpret_cast<tbtable*>(p + 1);
240 p = reinterpret_cast<uint32_t*>(&TBTable->tb_ext);
242 // Skip field parminfo if it exists.
243 if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
246 // Skip field tb_offset if it exists.
247 if (TBTable->tb.has_tboff)
250 // Skip field hand_mask if it exists.
251 if (TBTable->tb.int_hndl)
254 // Skip fields ctl_info and ctl_info_disp if they exist.
255 if (TBTable->tb.has_ctl)
258 // Skip fields name_len and name if exist.
259 if (TBTable->tb.name_present) {
260 const uint16_t name_len = *reinterpret_cast<uint16_t*>(p);
261 p = reinterpret_cast<uint32_t*>(reinterpret_cast<char*>(p) + name_len + sizeof(uint16_t));
264 if (TBTable->tb.uses_alloca)
265 framePointerReg = *reinterpret_cast<char*>(p);
267 return _Unwind_GetGR(context, framePointerReg);
270 // Calculate the object address from the FSM entry.
271 static void* compute_addr_from_table(FSMEntry* fsmEntry, StateVariable* const state, _Unwind_Context* context) {
273 if (fsmEntry->flags & FSMEntryFlag::globalObj) {
274 addr = reinterpret_cast<void*>(fsmEntry->address);
275 _LIBCXXABI_TRACE_STATETAB("Address calculation (global obj) addr=fsmEntry->address=%p\n", addr);
276 } else if (fsmEntry->flags & FSMEntryFlag::thisFlag) {
277 addr = reinterpret_cast<void*>(state->thisValue + fsmEntry->offset);
278 _LIBCXXABI_TRACE_STATETAB("Address calculation (this obj) fsmEntry->offset=%ld : "
279 "state->thisValue=%ld addr=(fsmEntry->offset+state->thisValue)=%p\n",
280 fsmEntry->offset, state->thisValue, addr);
281 } else if (fsmEntry->flags & FSMEntryFlag::indirect) {
282 addr = reinterpret_cast<void*>(
283 *reinterpret_cast<char**>(get_frame_addr(context) + static_cast<uintptr_t>(fsmEntry->offset)));
284 _LIBCXXABI_TRACE_STATETAB("Address calculation (indirect obj) addr=%p, fsmEntry->offset=%ld \n",
285 addr, fsmEntry->offset);
287 addr = reinterpret_cast<void*>(get_frame_addr(context) + static_cast<uintptr_t>(fsmEntry->offset));
288 _LIBCXXABI_TRACE_STATETAB("Address calculation. (local obj) addr=fsmEntry->offset=%p\n",
294 static void scan_state_tab(scan_results& results, _Unwind_Action actions, bool native_exception,
295 _Unwind_Exception* unwind_exception, _Unwind_Context* context) {
296 // Initialize results to found nothing but an error.
297 results.ttypeIndex = 0;
298 results.actionRecord = 0;
299 results.languageSpecificData = 0;
300 results.landingPad = 0;
301 results.adjustedPtr = 0;
302 results.reason = _URC_FATAL_PHASE1_ERROR;
304 // Check for consistent actions.
305 if (actions & _UA_SEARCH_PHASE) {
307 if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND)) {
308 // None of these flags should be set during Phase 1.
310 results.reason = _URC_FATAL_PHASE1_ERROR;
313 } else if (actions & _UA_CLEANUP_PHASE) {
314 if ((actions & _UA_HANDLER_FRAME) && (actions & _UA_FORCE_UNWIND)) {
315 // _UA_HANDLER_FRAME should only be set if phase 1 found a handler.
316 // If _UA_FORCE_UNWIND is set, phase 1 shouldn't have happened.
318 results.reason = _URC_FATAL_PHASE2_ERROR;
322 // Neither _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE is set.
324 results.reason = _URC_FATAL_PHASE1_ERROR;
328 if (_LIBCXXABI_TRACING_STATETAB) {
329 _LIBCXXABI_TRACE_STATETAB1("\n");
330 _LIBCXXABI_TRACE_STATETAB("%s: actions=%d (", __func__, actions);
332 if (_UA_SEARCH_PHASE & actions)
333 _LIBCXXABI_TRACE_STATETAB1("_UA_SEARCH_PHASE ");
334 if (_UA_CLEANUP_PHASE & actions)
335 _LIBCXXABI_TRACE_STATETAB1("_UA_CLEANUP_PHASE ");
336 if (_UA_HANDLER_FRAME & actions)
337 _LIBCXXABI_TRACE_STATETAB1("_UA_HANDLER_FRAME ");
338 if (_UA_FORCE_UNWIND & actions)
339 _LIBCXXABI_TRACE_STATETAB1("_UA_FORCE_UNWIND ");
340 _LIBCXXABI_TRACE_STATETAB1(")\n");
341 _LIBCXXABI_TRACE_STATETAB(" unwind_exception=%p context=%p\n", reinterpret_cast<void*>(unwind_exception),
342 reinterpret_cast<void*>(context));
345 // Start scan by getting state table address.
346 StateVariable* const state = reinterpret_cast<StateVariable* const>(_Unwind_GetLanguageSpecificData(context));
347 if (state->state <= 0) {
348 // The state is not correct - give up on this routine.
349 _LIBCXXABI_TRACE_STATETAB("state=%d and is <= 0), continue unwinding\n", state->state);
350 results.reason = _URC_CONTINUE_UNWIND;
353 // Parse the state table.
354 FSM* const fsm = state->table;
355 FSMEntry* currFSMEntry;
357 if (fsm->magic != FSMMagic::number && fsm->magic != FSMMagic::number2 && fsm->magic != FSMMagic::number3) {
358 // Something is wrong with the state table we found.
359 if (_UA_SEARCH_PHASE & actions) {
360 _LIBCXXABI_TRACE_STATETAB0("Invalid FSM table, return _URC_FATAL_PHASE1_ERROR\n");
361 results.reason = _URC_FATAL_PHASE1_ERROR;
362 } else if (_UA_CLEANUP_PHASE & actions) {
363 _LIBCXXABI_TRACE_STATETAB0("Invalid FSM table, return _URC_FATAL_PHASE2_ERROR\n");
364 results.reason = _URC_FATAL_PHASE2_ERROR;
366 // We should never get here.
367 _LIBCXXABI_TRACE_STATETAB0("Invalid FSM table + RT Internal error, return _URC_FATAL_PHASE2_ERROR\n");
368 results.reason = _URC_FATAL_PHASE2_ERROR;
373 if (_LIBCXXABI_TRACING_STATETAB) {
374 // Print the state table for debugging purposes.
375 _LIBCXXABI_TRACE_STATETAB("state->state=%d, state->ignoreVBasePtrs=%d\n", state->state, state->ignoreVBasePtrs);
376 _LIBCXXABI_TRACE_STATETAB("fsm->magic=%#x, fsm->numberOfStates=%d\n", fsm->magic, fsm->numberOfStates);
377 // Print out the FSM table.
378 _LIBCXXABI_TRACE_STATETAB0("FSM table:\n");
379 _LIBCXXABI_TRACE_STATETAB("%12s %10s %8s %10s %7s %7s %7s %7s\n", "Entry Addr", "state", "Offset", "DTR/lpad",
380 "count", "el_size", "flags", "next");
381 for (int i = 0; i < fsm->numberOfStates; i++) {
382 currFSMEntry = &fsm->table[i];
383 _LIBCXXABI_TRACE_STATETAB("%12p (%8d) %8ld %10p %7ld "
385 reinterpret_cast<void*>(&currFSMEntry), i + 1, currFSMEntry->offset,
386 reinterpret_cast<void*>(currFSMEntry->destructor),
387 currFSMEntry->elementCount, currFSMEntry->elemSize, currFSMEntry->flags,
388 currFSMEntry->nextState);
392 if (_UA_SEARCH_PHASE & actions) {
393 // Start walking the state table. Use a local copy of state->state so when
394 // we return from search phase we don't change the state number.
395 int currState = state->state;
397 while (currState > 0) {
398 currFSMEntry = &fsm->table[currState - 1];
399 _LIBCXXABI_TRACE_STATETAB("Processing state=%d, flags=0x%hx\n", currState, currFSMEntry->flags);
401 if (currFSMEntry->actionFlag == FSMEntryCount::beginCatch) {
402 // Found a catch handler.
403 if (fsm->magic == FSMMagic::number) {
404 _LIBCXXABI_TRACE_STATETAB0("Found a xlC catch handler, return _URC_FATAL_PHASE1_ERROR\n");
405 // xlC catch handlers cannot be entered because they use a
406 // proprietary EH runtime that is not interoperable.
407 results.reason = _URC_FATAL_PHASE1_ERROR;
410 // xlclang++ compiled frames use CXA-abi EH calls and any catch
411 // block will include a catch(...) block so it is safe to assume that
412 // the handler is found without checking the catch match. The
413 // catch(...) block will rethrow the exception if there isn't a
415 _LIBCXXABI_TRACE_STATETAB0("Found a catch handler, return _URC_HANDLER_FOUND\n");
416 results.reason = _URC_HANDLER_FOUND;
419 if (currFSMEntry->actionFlag == FSMEntryCount::terminate) {
420 _LIBCXXABI_TRACE_STATETAB0("Found the terminate state, return _URC_HANDLER_FOUND\n");
421 results.reason = _URC_HANDLER_FOUND;
424 if (currFSMEntry->flags & FSMEntryFlag::oldConditionalStateChange) {
425 // Deprecated conditional expression.
426 currState = *reinterpret_cast<int*>(currFSMEntry->nextStatePtr);
427 _LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::oldConditionalStateChange, dereference "
428 "currFSMEntry->nextStatePtr(%ld), set state=%d\n",
429 currFSMEntry->nextStatePtr, currState);
430 continue; // We are done this iteration of the loop, since
431 // we changed a state.
433 if (currFSMEntry->flags & FSMEntryFlag::conditionalStateChange) {
434 void* addr = compute_addr_from_table(currFSMEntry, state, context);
435 currState = *reinterpret_cast<int*>(addr);
436 _LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::conditionalStateChange, dereference "
437 "addr(%p), set state=%d\n", addr, currState);
438 continue; // We are done this iteration of the loop, since we
439 // changed the state.
441 // Go to the next state.
442 currState = currFSMEntry->nextState;
444 _LIBCXXABI_TRACE_STATETAB0("No catch handler found, return _URC_CONTINUE_UNWIND\n");
445 results.reason = _URC_CONTINUE_UNWIND;
448 if (_UA_CLEANUP_PHASE & actions) {
449 // Start walking the state table.
450 while (state->state > 0) {
451 currFSMEntry = &fsm->table[state->state - 1];
453 if (currFSMEntry->actionFlag == FSMEntryCount::terminate) {
454 _LIBCXXABI_TRACE_STATETAB0("Reached terminate state. Call terminate.\n");
457 // Perform action according to the currFSMEntry->actionFlag,
458 // except when flag is FSMEntryFlag::conditionalStateChange or
459 // FSMEntryFlag::oldConditionalStateChange.
460 _LIBCXXABI_TRACE_STATETAB("Processing state=%d, flags=0x%hx\n", state->state, currFSMEntry->flags);
461 if (currFSMEntry->flags & FSMEntryFlag::oldConditionalStateChange) {
462 state->state = *reinterpret_cast<int*>(currFSMEntry->nextStatePtr);
463 _LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::oldConditionalStateChange, dereference "
464 "currFSMEntry->nextStatePtr(%ld), set state=%d\n",
465 currFSMEntry->nextStatePtr, state->state);
466 continue; // We are done with this iteration of the loop, since we changed a state.
468 if (currFSMEntry->flags & FSMEntryFlag::conditionalStateChange) {
469 // A conditional state table entry holds the address of a local
470 // that holds the next state.
471 void* addr = compute_addr_from_table(currFSMEntry, state, context);
472 state->state = *reinterpret_cast<int*>(addr);
473 _LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::conditionalStateChange, dereference "
474 "addr(%p), set state=%d\n", addr, state->state);
475 continue; // We are done with this iteration of the loop, since we changed a state.
477 if (currFSMEntry->actionFlag == FSMEntryCount::beginCatch || currFSMEntry->actionFlag == FSMEntryCount::endCatch ||
478 currFSMEntry->actionFlag == FSMEntryCount::cleanupLabel) {
480 _LIBCXXABI_TRACE_STATETAB(
481 "FSMEntryCount::%s: handler %p/%p, return _URC_HANDLER_FOUND\n",
482 (currFSMEntry->actionFlag == FSMEntryCount::beginCatch
484 : (currFSMEntry->actionFlag == FSMEntryCount::endCatch ? "endCatch" : "cleanupLabel")),
485 currFSMEntry->landingPad, *reinterpret_cast<void**>(currFSMEntry->landingPad));
487 state->state = currFSMEntry->nextState;
488 results.landingPad = reinterpret_cast<uintptr_t>(*reinterpret_cast<void**>(currFSMEntry->landingPad));
489 results.reason = _URC_HANDLER_FOUND;
492 if (currFSMEntry->elementCount > 0) {
493 if (currFSMEntry->flags & FSMEntryFlag::vBaseFlag && state->ignoreVBasePtrs) {
494 _LIBCXXABI_TRACE_STATETAB0("Ignoring virtual base dtor.\n");
496 // We need to invoke the virtual base destructor. This must be
497 // a frame from the legacy xlC compiler as the xlclang++ compiler
498 // generates inline cleanup code rather than specifying
499 // the destructor via the state table.
500 void* addr = compute_addr_from_table(currFSMEntry, state, context);
502 // An extra indirect to get to the object according to the object
503 // model used by the xlC compiler.
504 addr = reinterpret_cast<void*>(*reinterpret_cast<char**>(addr));
505 _LIBCXXABI_TRACE_STATETAB("Invoke dtor for object=%p\n", addr);
506 invoke_destructor(currFSMEntry, addr);
508 } else if (currFSMEntry->actionFlag == FSMEntryCount::deleteObject) {
509 void* addr = compute_addr_from_table(currFSMEntry, state, context);
510 if (currFSMEntry->flags & FSMEntryFlag::vBaseFlag) {
511 // We need to invoke the virtual base delete function. This must be
512 // a frame from the legacy xlC compiler as the xlclang++ compiler
513 // generates inline cleanup code rather than specifying
514 // the delete function via the state table.
516 // An extra indirect to get to the object according to the object
517 // model used by the xlC compiler.
518 addr = reinterpret_cast<void*>(*reinterpret_cast<char**>(addr));
520 _LIBCXXABI_TRACE_STATETAB("Delete object at %p\n", addr);
521 invoke_delete(currFSMEntry, addr);
523 _LIBCXXABI_TRACE_STATETAB("Unknown entry in FSM (count=%ld), ignored\n",
524 currFSMEntry->elementCount);
525 } // End of action switching.
528 state->state = currFSMEntry->nextState;
530 _LIBCXXABI_TRACE_STATETAB0("No catch handler, return _URC_CONTINUE_UNWIND\n");
531 results.reason = _URC_CONTINUE_UNWIND;
534 _LIBCXXABI_TRACE_STATETAB0("No state table entry for this exception, call_terminate()\n");
535 // It is possible that no state table entry specify how to handle
536 // this exception. By spec, terminate it immediately.
537 call_terminate(native_exception, unwind_exception);
540 // Personality routine for EH using the state table.
541 _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
542 __xlcxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionClass,
543 _Unwind_Exception* unwind_exception, _Unwind_Context* context) {
544 if (version != 1 || unwind_exception == 0 || context == 0)
545 return _URC_FATAL_PHASE1_ERROR;
547 bool native_exception = (exceptionClass & get_vendor_and_language) == (kOurExceptionClass & get_vendor_and_language);
548 scan_results results;
549 scan_state_tab(results, actions, native_exception, unwind_exception, context);
550 if (actions & _UA_SEARCH_PHASE) {
551 // Phase 1 search: All we're looking for in phase 1 is a handler that
553 return results.reason;
555 if (actions & _UA_CLEANUP_PHASE) {
557 if (results.reason == _URC_HANDLER_FOUND) {
558 // Store the address of unwind_exception in the stack field
559 // reserved for compilers (SP + 3 * sizeof(uintptr_t)) in the stack of
560 // the caller of the function containing the landing pad (within the link
561 // area for the call to the latter) for __xlc_exception_handle()
562 // to retrieve when it is called by the landing pad.
563 uintptr_t *currentSP = reinterpret_cast<uintptr_t*>(_Unwind_GetGR(context, 1));
564 uintptr_t *callersSP = reinterpret_cast<uintptr_t*>(currentSP[0]);
565 callersSP[3] = reinterpret_cast<uintptr_t>(unwind_exception);
566 _LIBCXXABI_TRACE_STATETAB("Handshake: set unwind_exception=%p in stack=%p\n", reinterpret_cast<void*>(unwind_exception), reinterpret_cast<void*>(callersSP));
567 // Jump to the handler.
568 _Unwind_SetIP(context, results.landingPad);
569 return _URC_INSTALL_CONTEXT;
571 // Did not find a handler. Return the results of the scan. Normally
572 // _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE2_ERROR.
573 return results.reason;
575 // We were called improperly: neither a phase 1 or phase 2 search.
576 return _URC_FATAL_PHASE1_ERROR;
578 } // namespace __state_table_eh
580 // The following are EH helper functions for xlclang++ compiled code.
582 // __xlc_catch_matchv2
583 // Check whether the thrown object matches the catch handler's exception
584 // declaration. If there is a match, the function returns true with adjusted
585 // address of the thrown object. Otherwise, returns false.
586 _LIBCXXABI_FUNC_VIS bool
587 __xlc_catch_matchv2(_Unwind_Exception* exceptionObject, std::type_info* catchTypeInfo, void*& obj) {
588 _LIBCXXABI_TRACE_STATETAB("Entering %s, exceptionObject=%p\n", __func__, reinterpret_cast<void*>(exceptionObject));
590 if (!__isOurExceptionClass(exceptionObject)) {
591 _LIBCXXABI_TRACE_STATETAB0("No match, not a C++ exception\n");
595 __cxa_exception* exceptionHeader = 0;
597 if (__getExceptionClass(exceptionObject) == kOurDependentExceptionClass) {
598 // Walk to the __cxa_dependent_exception primary exception for the
599 // exception object and its type_info.
600 __cxa_dependent_exception* dependentExceptionHeader =
601 reinterpret_cast<__cxa_dependent_exception*>(exceptionObject + 1) - 1;
602 exceptionHeader = reinterpret_cast<__cxa_exception*>(dependentExceptionHeader->primaryException) - 1;
603 _LIBCXXABI_TRACE_STATETAB("exceptionObject 0x%p is a dependent, primary 0x%p\n",
604 reinterpret_cast<void*>(exceptionObject),
605 reinterpret_cast<void*>(&exceptionHeader->unwindHeader));
606 exceptionObject = &exceptionHeader->unwindHeader;
608 _LIBCXXABI_TRACE_STATETAB("exceptionObject %p is NOT a dependent\n", reinterpret_cast<void*>(exceptionObject));
609 exceptionHeader = reinterpret_cast<__cxa_exception*>(exceptionObject + 1) - 1;
612 void* thrownObject = reinterpret_cast<void*>(exceptionObject + 1);
613 std::type_info* throwTypeInfo = exceptionHeader->exceptionType;
615 // Get the type info for the thrown type and this catch clause and
616 // see if the catch caluse can catch that type.
618 __cxxabiv1::__shim_type_info* catchType = reinterpret_cast<__cxxabiv1::__shim_type_info*>(catchTypeInfo);
619 __cxxabiv1::__shim_type_info* throwType = reinterpret_cast<__cxxabiv1::__shim_type_info*>(throwTypeInfo);
620 _LIBCXXABI_TRACE_STATETAB("UnwindException=%p, thrownObject=%p, throwTypeInfo=%p(%s), catchTypeInfo=%p(%s)\n",
621 reinterpret_cast<void*>(exceptionObject), thrownObject, reinterpret_cast<void*>(throwType),
622 throwType->name(), reinterpret_cast<void*>(catchType), catchType->name());
623 if (catchType->can_catch(throwType, thrownObject)) {
624 exceptionHeader->adjustedPtr = thrownObject;
626 _LIBCXXABI_TRACE_STATETAB("Match found for thrownObject=%p\n", thrownObject);
629 _LIBCXXABI_TRACE_STATETAB0("No match\n");
633 // __xlc_throw_badexception
634 // This function is for xlclang++. It allocates and throws a bad_exception.
635 // During unwinding for this bad_exception, the previous exception which is
636 // not matching the throw spec will be cleaned up. Thus having the same
637 // effect as replace the top most exception (which is bad) with a bad_exception.
638 _LIBCXXABI_FUNC_VIS void __xlc_throw_badexception() {
639 _LIBCXXABI_TRACE_STATETAB("Entering function: %s\n\n", __func__);
640 void* newexception = new (__cxa_allocate_exception(sizeof(std::bad_exception))) std::bad_exception;
641 __cxa_throw(newexception, const_cast<std::type_info*>(&typeid(std::bad_exception)), 0);
644 // force_a_stackframe
645 // This function is called by __xlc_exception_handle() to ensure a stack frame
646 // is created for __xlc_exception_handle().
647 __attribute__((noinline, optnone))
648 static void force_a_stackframe() {}
650 // __xlc_exception_handle
651 // This function is for xlclang++. It returns the address of the exception
652 // object stored in the reserved field in the stack of the caller of the
653 // function that calls __xlc_exception_handle() (within the link area for the
654 // call to the latter). The address is stored by the personality routine for
655 // xlclang++ compiled code. The implementation of __xlc_exception_handle()
656 // assumes a stack frame is created for it. The following ensures this
657 // assumption holds true: 1) a call to force_a_stackframe() is made inside
658 // __xlc_exception_handle() to make it non-leaf; and 2) optimizations are
659 // disabled for this function with attribute 'optnone'. Note: this function
660 // may not work as expected if these are changed.
661 __attribute__((optnone))
662 _LIBCXXABI_FUNC_VIS uintptr_t __xlc_exception_handle() {
663 // Make a call to force_a_stackframe() so that the compiler creates a stack
664 // frame for this function.
665 force_a_stackframe();
667 // Get the SP of this function, i.e., __xlc_exception_handle().
668 uintptr_t *lastStack;
669 asm("mr %0, 1" : "=r"(lastStack));
670 // Get the SP of the caller of __xlc_exception_handle().
671 uintptr_t *callerStack = reinterpret_cast<uintptr_t*>(lastStack[0]);
672 // Get the SP of the caller of the caller.
673 uintptr_t *callerStack2 = reinterpret_cast<uintptr_t*>(callerStack[0]);
674 uintptr_t exceptionObject = callerStack2[3];
675 _LIBCXXABI_TRACE_STATETAB("Handshake: exceptionObject=%p from stack=%p\n", reinterpret_cast<void*>(exceptionObject), reinterpret_cast<void*>(callerStack2));
676 return exceptionObject;
679 // xlclang++ may generate calls to __Deleted_Virtual.
680 _LIBCXXABI_FUNC_VIS void __Deleted_Virtual() { abort(); }
682 // __catchThrownException is called during AIX library initialization and
683 // termination to handle exceptions. An implementation is also provided in
684 // libC.a(shrcore.o). This implementation is provided for applications that
685 // link with -lc++ (the xlclang++ or ibm-clang++ link default.)
686 _LIBCXXABI_FUNC_VIS int
687 __catchThrownException(void (*cdfunc)(void), // function which may fail
688 void (*cleanup)(void*), // cleanup function
689 void* cleanuparg, // parameter to cleanup function
690 int action) { // control exception throwing and termination
691 enum Action : int { None = 0, Rethrow = 1, Terminate = 2 };
694 if (action == Action::Rethrow && !cleanup) {
695 // No cleanup and rethrow is effectively no-op.
696 // Avoid the catch handler when possible to allow exceptions generated
697 // from xlC binaries to flow through.
704 if (action == Action::Terminate)
707 (*cleanup)(cleanuparg);
708 if (action == Action::Rethrow)
710 assert(action == Action::None);