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>
18 The legacy IBM xlC and xlclang++ compilers use the state table for EH
19 instead of the range table. Destructors, or addresses of the possible catch
20 sites or cleanup code are specified in the state table which is a finite
21 state machine (FSM). Each function that has a state table also has an
22 autolocal state variable. The state variable represents the current state
23 of the function for EH and is found through the traceback table of the
24 function during unwinding, which is located at the end of each function.
25 The FSM is an array of state entries. Each state entry has the following
28 * offset/address/pointer - the offset used to locate the object, or the
29 address of a global object, or the address of the next state if it is an
30 old conditional state change entry;
31 * dtor/landing pad - address of the destructor function to invoke,
32 or address of the catch block or cleanup code in the user code to branch to;
33 * element count/action flag - the number of elements or the flag for actions;
34 * element size - if the object is an array this is the size of one element
36 * flags - flags used to control how fields in the entry are interpreted;
37 * next state - the state to execute next after the action for this state is
38 performed. The value of zero indicates the end of the state for this
41 The following is the description of 'element count/action flag' field.
42 +-----------------------------------------------------------------------------+
43 | value | description | action |
44 +-------+------------------------+--------------------------------------------+
45 | > 1 | object is an array | calls __cxa_vec_cleanup to run dtor for |
46 | | | each member of the array |
47 +-------+------------------------+--------------------------------------------+
48 | 1, 0 | object is a scalar | calls dtor for the object |
49 +-------+------------------------+--------------------------------------------+
50 | -1 | begin catch | branches to the handler which performes |
51 | | | catch-match. If there is no catch that |
52 | | | matches the exception it will be rethrown |
53 +-------+------------------------+--------------------------------------------+
54 | -2 | end catch | ends current catch block and continues |
55 | | | attempting to catch the exception |
56 +-------+------------------------+--------------------------------------------+
57 | -3 | delete the object | calls the delete function of the object |
58 +-------+------------------------+--------------------------------------------+
59 | -4 | cleanup label | branches to the user code for cleaning up |
60 +-------+------------------------+--------------------------------------------+
63 namespace __cxxabiv1 {
67 // Macros for debugging the state table parsing.
69 # define _LIBCXXABI_TRACE_STATETAB(msg, ...)
70 # define _LIBCXXABI_TRACE_STATETAB0(msg)
71 # define _LIBCXXABI_TRACE_STATETAB1(msg)
72 # define _LIBCXXABI_TRACING_STATETAB 0
74 static bool state_tab_dbg() {
75 static bool checked = false;
76 static bool log = false;
78 log = (getenv("LIBCXXABI_PRINT_STATTAB") != NULL);
84 # define _LIBCXXABI_TRACE_STATETAB(msg, ...) \
86 if (state_tab_dbg()) \
87 fprintf(stderr, "libcxxabi: " msg, __VA_ARGS__); \
89 # define _LIBCXXABI_TRACE_STATETAB0(msg) \
91 if (state_tab_dbg()) \
92 fprintf(stderr, "libcxxabi: " msg); \
94 # define _LIBCXXABI_TRACE_STATETAB1(msg) \
96 if (state_tab_dbg()) \
97 fprintf(stderr, msg); \
100 # define _LIBCXXABI_TRACING_STATETAB state_tab_dbg()
103 namespace __state_table_eh {
105 using destruct_f = void (*)(void*);
107 // Definition of flags for the state table entry field 'action flag'.
108 enum FSMEntryCount : intptr_t { beginCatch = -1, endCatch = -2, deleteObject = -3, cleanupLabel = -4, terminate = -5 };
110 // Definition of flags for the state table entry field 'flags'.
111 enum FSMEntryFlag : int16_t {
112 indirect = 0x100, // Object was thrown from a function where
113 // the return value optimization was used.
114 oldConditionalStateChange = 0x400, // State table entry is an indirect state
115 // change, dereference the address in
116 // offset as int for the target state.
117 // This is deprecated. This indicates
118 // the address is direct. (static local).
119 conditionalStateChange = 0x800, // State table entry is an indirect state
120 // change, dereference the address in
121 // offset as int for the target state.
122 // The temporary is an automatic. State
123 // change is used in cases such as
124 // (b?(T1(),foo()):(T2(),foo())),throw 42;
125 // which causes a conditional state change
126 // so that we know if T1 or T2 need to be
128 thisFlag = 0x01, // The address of the object for the
129 // cleanup action is based on the
130 // StateVariable::thisValue.
131 vBaseFlag = 0x02, // The object is of a virtual base class.
132 globalObj = 0x04 // FSMEntry::address is the address of
137 // The finite state machine to be walked.
140 // Offset of the object within its stack frame or containing object.
142 // Address of a global object.
144 // Address of the next state if it is an old conditional state change entry.
145 intptr_t nextStatePtr;
148 // Address of the destructor function.
149 void (*destructor)(void*, size_t);
150 // The address of the catch block or cleanup code.
154 // The flag for actions (when the value is negative).
155 FSMEntryCount actionFlag;
156 // The element count (when the value is positive or zero).
165 uint32_t magic; // Magic number of the state table.
166 int32_t numberOfStates;
167 FSMEntry table[1]; // Actually table[numberOfStates].
170 // The state variable on the stack.
171 struct StateVariable {
175 int32_t ignoreVBasePtrs;
179 // State table magic number
180 enum FSMMagic : uint32_t {
181 number = 0xbeefdead, // State table generated by xlC compiler.
182 number2 = 0xbeeedead, // State table generated by early version xlC compiler.
183 number3 = 0x1cedbeef // State table generated by xlclang++ compiler.
186 constexpr size_t dtorArgument = 0x02; // Flag to destructor indicating to free
187 // virtual bases, don't delete object.
189 static void invoke_destructor(FSMEntry* fsmEntry, void* addr) {
190 _LIBCXXABI_TRACE_STATETAB("Destruct object=%p, fsmEntry=%p\n", addr, reinterpret_cast<void*>(fsmEntry));
192 if (fsmEntry->elementCount == 1) {
193 _LIBCXXABI_TRACE_STATETAB0("calling scalar destructor\n");
194 (*fsmEntry->destructor)(addr, dtorArgument);
195 _LIBCXXABI_TRACE_STATETAB0("returned from scalar destructor\n");
197 _LIBCXXABI_TRACE_STATETAB0("calling vector destructor\n");
198 __cxa_vec_cleanup(addr, reinterpret_cast<size_t>(fsmEntry->elementCount), fsmEntry->elemSize,
199 reinterpret_cast<destruct_f>(fsmEntry->destructor));
200 _LIBCXXABI_TRACE_STATETAB0("returned from vector destructor\n");
203 _LIBCXXABI_TRACE_STATETAB0("Uncaught exception in destructor, terminating\n");
208 static void invoke_delete(FSMEntry* fsmEntry, void* addr) {
209 char* objectAddress = *reinterpret_cast<char**>(addr);
211 _LIBCXXABI_TRACE_STATETAB("Delete object=%p, fsmEntry=%p\n", reinterpret_cast<void*>(objectAddress),
212 reinterpret_cast<void*>(fsmEntry));
214 _LIBCXXABI_TRACE_STATETAB0("..calling delete()\n");
215 // 'destructor' holds a function pointer to delete().
216 (*fsmEntry->destructor)(objectAddress, fsmEntry->elemSize);
217 _LIBCXXABI_TRACE_STATETAB0("..returned from delete()\n");
219 _LIBCXXABI_TRACE_STATETAB0("Uncaught exception in delete(), terminating\n");
224 // Get the frame address of the current function from its traceback table
225 // which is at the end of each function.
226 static uintptr_t get_frame_addr(_Unwind_Context* context) {
227 int framePointerReg = 1; // default frame pointer == SP.
228 uint32_t* p = reinterpret_cast<uint32_t*>(_Unwind_GetIP(context));
230 // Keep looking forward until a word of 0 is found. The traceback
231 // table starts at the following word.
234 tbtable* TBTable = reinterpret_cast<tbtable*>(p + 1);
236 p = reinterpret_cast<uint32_t*>(&TBTable->tb_ext);
238 // Skip field parminfo if it exists.
239 if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
242 // Skip field tb_offset if it exists.
243 if (TBTable->tb.has_tboff)
246 // Skip field hand_mask if it exists.
247 if (TBTable->tb.int_hndl)
250 // Skip fields ctl_info and ctl_info_disp if they exist.
251 if (TBTable->tb.has_ctl)
254 // Skip fields name_len and name if exist.
255 if (TBTable->tb.name_present) {
256 const uint16_t name_len = *reinterpret_cast<uint16_t*>(p);
257 p = reinterpret_cast<uint32_t*>(reinterpret_cast<char*>(p) + name_len + sizeof(uint16_t));
260 if (TBTable->tb.uses_alloca)
261 framePointerReg = *reinterpret_cast<char*>(p);
263 return _Unwind_GetGR(context, framePointerReg);
266 // Calculate the object address from the FSM entry.
267 static void* compute_addr_from_table(FSMEntry* fsmEntry, StateVariable* const state, _Unwind_Context* context) {
269 if (fsmEntry->flags & FSMEntryFlag::globalObj) {
270 addr = reinterpret_cast<void*>(fsmEntry->address);
271 _LIBCXXABI_TRACE_STATETAB("Address calculation (global obj) addr=fsmEntry->address=%p\n", addr);
272 } else if (fsmEntry->flags & FSMEntryFlag::thisFlag) {
273 addr = reinterpret_cast<void*>(state->thisValue + fsmEntry->offset);
274 _LIBCXXABI_TRACE_STATETAB("Address calculation (this obj) fsmEntry->offset=%ld : "
275 "state->thisValue=%ld addr=(fsmEntry->offset+state->thisValue)=%p\n",
276 fsmEntry->offset, state->thisValue, addr);
277 } else if (fsmEntry->flags & FSMEntryFlag::indirect) {
278 addr = reinterpret_cast<void*>(
279 *reinterpret_cast<char**>(get_frame_addr(context) + static_cast<uintptr_t>(fsmEntry->offset)));
280 _LIBCXXABI_TRACE_STATETAB("Address calculation (indirect obj) addr=%p, fsmEntry->offset=%ld \n",
281 addr, fsmEntry->offset);
283 addr = reinterpret_cast<void*>(get_frame_addr(context) + static_cast<uintptr_t>(fsmEntry->offset));
284 _LIBCXXABI_TRACE_STATETAB("Address calculation. (local obj) addr=fsmEntry->offset=%p\n",
290 static void scan_state_tab(scan_results& results, _Unwind_Action actions, bool native_exception,
291 _Unwind_Exception* unwind_exception, _Unwind_Context* context) {
292 // Initialize results to found nothing but an error.
293 results.ttypeIndex = 0;
294 results.actionRecord = 0;
295 results.languageSpecificData = 0;
296 results.landingPad = 0;
297 results.adjustedPtr = 0;
298 results.reason = _URC_FATAL_PHASE1_ERROR;
300 // Check for consistent actions.
301 if (actions & _UA_SEARCH_PHASE) {
303 if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND)) {
304 // None of these flags should be set during Phase 1.
306 results.reason = _URC_FATAL_PHASE1_ERROR;
309 } else if (actions & _UA_CLEANUP_PHASE) {
310 if ((actions & _UA_HANDLER_FRAME) && (actions & _UA_FORCE_UNWIND)) {
311 // _UA_HANDLER_FRAME should only be set if phase 1 found a handler.
312 // If _UA_FORCE_UNWIND is set, phase 1 shouldn't have happened.
314 results.reason = _URC_FATAL_PHASE2_ERROR;
318 // Neither _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE is set.
320 results.reason = _URC_FATAL_PHASE1_ERROR;
324 if (_LIBCXXABI_TRACING_STATETAB) {
325 _LIBCXXABI_TRACE_STATETAB1("\n");
326 _LIBCXXABI_TRACE_STATETAB("%s: actions=%d (", __func__, actions);
328 if (_UA_SEARCH_PHASE & actions)
329 _LIBCXXABI_TRACE_STATETAB1("_UA_SEARCH_PHASE ");
330 if (_UA_CLEANUP_PHASE & actions)
331 _LIBCXXABI_TRACE_STATETAB1("_UA_CLEANUP_PHASE ");
332 if (_UA_HANDLER_FRAME & actions)
333 _LIBCXXABI_TRACE_STATETAB1("_UA_HANDLER_FRAME ");
334 if (_UA_FORCE_UNWIND & actions)
335 _LIBCXXABI_TRACE_STATETAB1("_UA_FORCE_UNWIND ");
336 _LIBCXXABI_TRACE_STATETAB1(")\n");
337 _LIBCXXABI_TRACE_STATETAB(" unwind_exception=%p context=%p\n", reinterpret_cast<void*>(unwind_exception),
338 reinterpret_cast<void*>(context));
341 // Start scan by getting state table address.
342 StateVariable* const state = reinterpret_cast<StateVariable* const>(_Unwind_GetLanguageSpecificData(context));
343 if (state->state <= 0) {
344 // The state is not correct - give up on this routine.
345 _LIBCXXABI_TRACE_STATETAB("state=%d and is <= 0), continue unwinding\n", state->state);
346 results.reason = _URC_CONTINUE_UNWIND;
349 // Parse the state table.
350 FSM* const fsm = state->table;
351 FSMEntry* currFSMEntry;
353 if (fsm->magic != FSMMagic::number && fsm->magic != FSMMagic::number2 && fsm->magic != FSMMagic::number3) {
354 // Something is wrong with the state table we found.
355 if (_UA_SEARCH_PHASE & actions) {
356 _LIBCXXABI_TRACE_STATETAB0("Invalid FSM table, return _URC_FATAL_PHASE1_ERROR\n");
357 results.reason = _URC_FATAL_PHASE1_ERROR;
358 } else if (_UA_CLEANUP_PHASE & actions) {
359 _LIBCXXABI_TRACE_STATETAB0("Invalid FSM table, return _URC_FATAL_PHASE2_ERROR\n");
360 results.reason = _URC_FATAL_PHASE2_ERROR;
362 // We should never get here.
363 _LIBCXXABI_TRACE_STATETAB0("Invalid FSM table + RT Internal error, return _URC_FATAL_PHASE2_ERROR\n");
364 results.reason = _URC_FATAL_PHASE2_ERROR;
369 if (_LIBCXXABI_TRACING_STATETAB) {
370 // Print the state table for debugging purposes.
371 _LIBCXXABI_TRACE_STATETAB("state->state=%d, state->ignoreVBasePtrs=%d\n", state->state, state->ignoreVBasePtrs);
372 _LIBCXXABI_TRACE_STATETAB("fsm->magic=%#x, fsm->numberOfStates=%d\n", fsm->magic, fsm->numberOfStates);
373 // Print out the FSM table.
374 _LIBCXXABI_TRACE_STATETAB0("FSM table:\n");
375 _LIBCXXABI_TRACE_STATETAB("%12s %10s %8s %10s %7s %7s %7s %7s\n", "Entry Addr", "state", "Offset", "DTR/lpad",
376 "count", "el_size", "flags", "next");
377 for (int i = 0; i < fsm->numberOfStates; i++) {
378 currFSMEntry = &fsm->table[i];
379 _LIBCXXABI_TRACE_STATETAB("%12p (%8d) %8ld %10p %7ld "
381 reinterpret_cast<void*>(&currFSMEntry), i + 1, currFSMEntry->offset,
382 reinterpret_cast<void*>(currFSMEntry->destructor),
383 currFSMEntry->elementCount, currFSMEntry->elemSize, currFSMEntry->flags,
384 currFSMEntry->nextState);
388 if (_UA_SEARCH_PHASE & actions) {
389 // Start walking the state table. Use a local copy of state->state so when
390 // we return from search phase we don't change the state number.
391 int currState = state->state;
393 while (currState > 0) {
394 currFSMEntry = &fsm->table[currState - 1];
395 _LIBCXXABI_TRACE_STATETAB("Processing state=%d, flags=0x%hx\n", currState, currFSMEntry->flags);
397 if (currFSMEntry->actionFlag == FSMEntryCount::beginCatch) {
398 // Found a catch handler.
399 if (fsm->magic == FSMMagic::number) {
400 _LIBCXXABI_TRACE_STATETAB0("Found a xlC catch handler, return _URC_FATAL_PHASE1_ERROR\n");
401 // xlC catch handlers cannot be entered because they use a
402 // proprietary EH runtime that is not interoperable.
403 results.reason = _URC_FATAL_PHASE1_ERROR;
406 // xlclang++ compiled frames use CXA-abi EH calls and any catch
407 // block will include a catch(...) block so it is safe to assume that
408 // the handler is found without checking the catch match. The
409 // catch(...) block will rethrow the exception if there isn't a
411 _LIBCXXABI_TRACE_STATETAB0("Found a catch handler, return _URC_HANDLER_FOUND\n");
412 results.reason = _URC_HANDLER_FOUND;
415 if (currFSMEntry->actionFlag == FSMEntryCount::terminate) {
416 _LIBCXXABI_TRACE_STATETAB0("Found the terminate state, return _URC_HANDLER_FOUND\n");
417 results.reason = _URC_HANDLER_FOUND;
420 if (currFSMEntry->flags & FSMEntryFlag::oldConditionalStateChange) {
421 // Deprecated conditional expression.
422 currState = *reinterpret_cast<int*>(currFSMEntry->nextStatePtr);
423 _LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::oldConditionalStateChange, dereference "
424 "currFSMEntry->nextStatePtr(%ld), set state=%d\n",
425 currFSMEntry->nextStatePtr, currState);
426 continue; // We are done this iteration of the loop, since
427 // we changed a state.
429 if (currFSMEntry->flags & FSMEntryFlag::conditionalStateChange) {
430 void* addr = compute_addr_from_table(currFSMEntry, state, context);
431 currState = *reinterpret_cast<int*>(addr);
432 _LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::conditionalStateChange, dereference "
433 "addr(%p), set state=%d\n", addr, currState);
434 continue; // We are done this iteration of the loop, since we
435 // changed the state.
437 // Go to the next state.
438 currState = currFSMEntry->nextState;
440 _LIBCXXABI_TRACE_STATETAB0("No catch handler found, return _URC_CONTINUE_UNWIND\n");
441 results.reason = _URC_CONTINUE_UNWIND;
444 if (_UA_CLEANUP_PHASE & actions) {
445 // Start walking the state table.
446 while (state->state > 0) {
447 currFSMEntry = &fsm->table[state->state - 1];
449 if (currFSMEntry->actionFlag == FSMEntryCount::terminate) {
450 _LIBCXXABI_TRACE_STATETAB0("Reached terminate state. Call terminate.\n");
453 // Perform action according to the currFSMEntry->actionFlag,
454 // except when flag is FSMEntryFlag::conditionalStateChange or
455 // FSMEntryFlag::oldConditionalStateChange.
456 _LIBCXXABI_TRACE_STATETAB("Processing state=%d, flags=0x%hx\n", state->state, currFSMEntry->flags);
457 if (currFSMEntry->flags & FSMEntryFlag::oldConditionalStateChange) {
458 state->state = *reinterpret_cast<int*>(currFSMEntry->nextStatePtr);
459 _LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::oldConditionalStateChange, dereference "
460 "currFSMEntry->nextStatePtr(%ld), set state=%d\n",
461 currFSMEntry->nextStatePtr, state->state);
462 continue; // We are done with this iteration of the loop, since we changed a state.
464 if (currFSMEntry->flags & FSMEntryFlag::conditionalStateChange) {
465 // A conditional state table entry holds the address of a local
466 // that holds the next state.
467 void* addr = compute_addr_from_table(currFSMEntry, state, context);
468 state->state = *reinterpret_cast<int*>(addr);
469 _LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::conditionalStateChange, dereference "
470 "addr(%p), set state=%d\n", addr, state->state);
471 continue; // We are done with this iteration of the loop, since we changed a state.
473 if (currFSMEntry->actionFlag == FSMEntryCount::beginCatch || currFSMEntry->actionFlag == FSMEntryCount::endCatch ||
474 currFSMEntry->actionFlag == FSMEntryCount::cleanupLabel) {
476 _LIBCXXABI_TRACE_STATETAB(
477 "FSMEntryCount::%s: handler %p/%p, return _URC_HANDLER_FOUND\n",
478 (currFSMEntry->actionFlag == FSMEntryCount::beginCatch
480 : (currFSMEntry->actionFlag == FSMEntryCount::endCatch ? "endCatch" : "cleanupLabel")),
481 currFSMEntry->landingPad, *reinterpret_cast<void**>(currFSMEntry->landingPad));
483 state->state = currFSMEntry->nextState;
484 results.landingPad = reinterpret_cast<uintptr_t>(*reinterpret_cast<void**>(currFSMEntry->landingPad));
485 results.reason = _URC_HANDLER_FOUND;
488 if (currFSMEntry->elementCount > 0) {
489 if (currFSMEntry->flags & FSMEntryFlag::vBaseFlag && state->ignoreVBasePtrs) {
490 _LIBCXXABI_TRACE_STATETAB0("Ignoring virtual base dtor.\n");
492 // We need to invoke the virtual base destructor. This must be
493 // a frame from the legacy xlC compiler as the xlclang++ compiler
494 // generates inline cleanup code rather than specifying
495 // the destructor via the state table.
496 void* addr = compute_addr_from_table(currFSMEntry, state, context);
498 // An extra indirect to get to the object according to the object
499 // model used by the xlC compiler.
500 addr = reinterpret_cast<void*>(*reinterpret_cast<char**>(addr));
501 _LIBCXXABI_TRACE_STATETAB("Invoke dtor for object=%p\n", addr);
502 invoke_destructor(currFSMEntry, addr);
504 } else if (currFSMEntry->actionFlag == FSMEntryCount::deleteObject) {
505 void* addr = compute_addr_from_table(currFSMEntry, state, context);
506 if (currFSMEntry->flags & FSMEntryFlag::vBaseFlag) {
507 // We need to invoke the virtual base delete function. This must be
508 // a frame from the legacy xlC compiler as the xlclang++ compiler
509 // generates inline cleanup code rather than specifying
510 // the delete function via the state table.
512 // An extra indirect to get to the object according to the object
513 // model used by the xlC compiler.
514 addr = reinterpret_cast<void*>(*reinterpret_cast<char**>(addr));
516 _LIBCXXABI_TRACE_STATETAB("Delete object at %p\n", addr);
517 invoke_delete(currFSMEntry, addr);
519 _LIBCXXABI_TRACE_STATETAB("Unknown entry in FSM (count=%ld), ignored\n",
520 currFSMEntry->elementCount);
521 } // End of action switching.
524 state->state = currFSMEntry->nextState;
526 _LIBCXXABI_TRACE_STATETAB0("No catch handler, return _URC_CONTINUE_UNWIND\n");
527 results.reason = _URC_CONTINUE_UNWIND;
530 _LIBCXXABI_TRACE_STATETAB0("No state table entry for this exception, call_terminate()\n");
531 // It is possible that no state table entry specify how to handle
532 // this exception. By spec, terminate it immediately.
533 call_terminate(native_exception, unwind_exception);
536 // Personality routine for EH using the state table.
537 _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
538 __xlcxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionClass,
539 _Unwind_Exception* unwind_exception, _Unwind_Context* context) {
540 if (version != 1 || unwind_exception == 0 || context == 0)
541 return _URC_FATAL_PHASE1_ERROR;
543 bool native_exception = (exceptionClass & get_vendor_and_language) == (kOurExceptionClass & get_vendor_and_language);
544 scan_results results;
545 scan_state_tab(results, actions, native_exception, unwind_exception, context);
546 if (actions & _UA_SEARCH_PHASE) {
547 // Phase 1 search: All we're looking for in phase 1 is a handler that
549 return results.reason;
551 if (actions & _UA_CLEANUP_PHASE) {
553 if (results.reason == _URC_HANDLER_FOUND) {
554 // Store the address of unwind_exception in the stack field
555 // reserved for compilers (SP + 3 * sizeof(uintptr_t)) in the stack of
556 // the caller of the function containing the landing pad (within the link
557 // area for the call to the latter) for __xlc_exception_handle()
558 // to retrieve when it is called by the landing pad.
559 uintptr_t *currentSP = reinterpret_cast<uintptr_t*>(_Unwind_GetGR(context, 1));
560 uintptr_t *callersSP = reinterpret_cast<uintptr_t*>(currentSP[0]);
561 callersSP[3] = reinterpret_cast<uintptr_t>(unwind_exception);
562 _LIBCXXABI_TRACE_STATETAB("Handshake: save unwind_exception=%p in stack=%p\n",
563 reinterpret_cast<void*>(unwind_exception), reinterpret_cast<void*>(callersSP));
564 // Jump to the handler.
565 _Unwind_SetIP(context, results.landingPad);
566 return _URC_INSTALL_CONTEXT;
568 // Did not find a handler. Return the results of the scan. Normally
569 // _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE2_ERROR.
570 return results.reason;
572 // We were called improperly: neither a phase 1 or phase 2 search.
573 return _URC_FATAL_PHASE1_ERROR;
575 } // namespace __state_table_eh
577 // The following are EH helper functions for xlclang++ compiled code.
579 // __xlc_catch_matchv2
580 // Check whether the thrown object matches the catch handler's exception
581 // declaration. If there is a match, the function returns true with adjusted
582 // address of the thrown object. Otherwise, returns false.
583 _LIBCXXABI_FUNC_VIS bool
584 __xlc_catch_matchv2(_Unwind_Exception* exceptionObject, std::type_info* catchTypeInfo, void*& obj) {
585 _LIBCXXABI_TRACE_STATETAB("Entering %s, exceptionObject=%p\n", __func__, reinterpret_cast<void*>(exceptionObject));
587 if (!__isOurExceptionClass(exceptionObject)) {
588 _LIBCXXABI_TRACE_STATETAB0("No match, not a C++ exception\n");
592 __cxa_exception* exceptionHeader = 0;
594 if (__getExceptionClass(exceptionObject) == kOurDependentExceptionClass) {
595 // Walk to the __cxa_dependent_exception primary exception for the
596 // exception object and its type_info.
597 __cxa_dependent_exception* dependentExceptionHeader =
598 reinterpret_cast<__cxa_dependent_exception*>(exceptionObject + 1) - 1;
599 exceptionHeader = reinterpret_cast<__cxa_exception*>(dependentExceptionHeader->primaryException) - 1;
600 _LIBCXXABI_TRACE_STATETAB("exceptionObject 0x%p is a dependent, primary 0x%p\n",
601 reinterpret_cast<void*>(exceptionObject),
602 reinterpret_cast<void*>(&exceptionHeader->unwindHeader));
603 exceptionObject = &exceptionHeader->unwindHeader;
605 _LIBCXXABI_TRACE_STATETAB("exceptionObject %p is NOT a dependent\n", reinterpret_cast<void*>(exceptionObject));
606 exceptionHeader = reinterpret_cast<__cxa_exception*>(exceptionObject + 1) - 1;
609 void* thrownObject = reinterpret_cast<void*>(exceptionObject + 1);
610 std::type_info* throwTypeInfo = exceptionHeader->exceptionType;
612 // Get the type info for the thrown type and this catch clause and
613 // see if the catch caluse can catch that type.
615 __cxxabiv1::__shim_type_info* catchType = reinterpret_cast<__cxxabiv1::__shim_type_info*>(catchTypeInfo);
616 __cxxabiv1::__shim_type_info* throwType = reinterpret_cast<__cxxabiv1::__shim_type_info*>(throwTypeInfo);
617 _LIBCXXABI_TRACE_STATETAB("UnwindException=%p, thrownObject=%p, throwTypeInfo=%p(%s), catchTypeInfo=%p(%s)\n",
618 reinterpret_cast<void*>(exceptionObject), thrownObject, reinterpret_cast<void*>(throwType),
619 throwType->name(), reinterpret_cast<void*>(catchType), catchType->name());
620 if (catchType->can_catch(throwType, thrownObject)) {
621 exceptionHeader->adjustedPtr = thrownObject;
623 _LIBCXXABI_TRACE_STATETAB("Match found for thrownObject=%p\n", thrownObject);
626 _LIBCXXABI_TRACE_STATETAB0("No match\n");
630 // __xlc_throw_badexception
631 // This function is for xlclang++. It allocates and throws a bad_exception.
632 // During unwinding for this bad_exception, the previous exception which is
633 // not matching the throw spec will be cleaned up. Thus having the same
634 // effect as replace the top most exception (which is bad) with a bad_exception.
635 _LIBCXXABI_FUNC_VIS void __xlc_throw_badexception() {
636 _LIBCXXABI_TRACE_STATETAB("Entering function: %s\n\n", __func__);
637 void* newexception = new (__cxa_allocate_exception(sizeof(std::bad_exception))) std::bad_exception;
638 __cxa_throw(newexception, const_cast<std::type_info*>(&typeid(std::bad_exception)), 0);
641 // skip_non_cxx_eh_aware_frames
642 // This function skips non-C++ EH aware stack frames by unwinding from the
643 // stack frame pointed by 'Sp' and returns the first C++ EH aware stack frame
644 // found. 'Pc' is an instruction address inside the function that owns the
645 // stack frame pointed to by 'Sp'.
646 static uintptr_t* skip_non_cxx_eh_aware_frames(uint32_t* Pc, uintptr_t* Sp) {
647 uint32_t* currentPc = Pc;
648 uintptr_t* currentStack = Sp;
650 // Loop until a C++ EH aware frame is found or the return address is 0,
651 // which is the return address of the startup function '__start'.
652 while (currentPc != 0) {
653 uint32_t* p = currentPc;
655 // Keep looking forward until a word of 0 is found. The traceback
656 // table starts at the following word.
659 tbtable* TBTable = reinterpret_cast<tbtable*>(p + 1);
661 // A stack frame with a C++ state table is C++ EH aware.
662 if (TBTable->tb.lang == TB_CPLUSPLUS && TBTable->tb.has_ctl)
665 // Move up one stack frame.
666 currentStack = reinterpret_cast<uintptr_t*>(currentStack[0]);
667 // Get the value of the LR (saved, prior to incrementing the SP, by the
668 // prolog of the function just inspected) from the frame.
669 currentPc = reinterpret_cast<uint32_t*>(currentStack[2]);
671 // This should not happen.
672 _LIBCXXABI_TRACE_STATETAB0("skip_non_cxx_eh_aware_frames() reached the end of stack frames, aborting\n");
676 // __xlc_exception_handle
677 // This function is for xlclang++. It returns the address of the exception
678 // object stored in the reserved field in the stack of the caller of the
679 // function that calls __xlc_exception_handle() (within the link area for the
680 // call to the latter). The address is stored by the personality routine for
681 // xlclang++ compiled code. If __xlc_exception_handle() is called by
682 // non-C++ EH aware functions, their frames are skipped until a C++ EH aware
684 // Note: make sure __xlc_excpetion_handle() is a non-leaf function. Currently
685 // it calls skip_non_cxx_eh_aware_frames(), which in turn calls abort().
686 _LIBCXXABI_FUNC_VIS uintptr_t __xlc_exception_handle() {
687 // Get the SP of this function, i.e., __xlc_exception_handle().
688 uintptr_t* lastStack = reinterpret_cast<uintptr_t*>(__builtin_frame_address(0));
689 // Move one frame up to the frame of the caller of __xlc_exception_handle().
690 lastStack = reinterpret_cast<uintptr_t*>(lastStack[0]);
691 // Get the return address of this function, i.e., __xlc_exception_handle().
692 uint32_t* returnAddress = reinterpret_cast<uint32_t*>(__builtin_return_address(0));
694 // Skip non-C++ EH aware frames and get the first C++ EH aware frame.
695 uintptr_t* callerStack = skip_non_cxx_eh_aware_frames(returnAddress, lastStack);
697 // Get the SP of the caller of the C++ EH aware caller.
698 callerStack = reinterpret_cast<uintptr_t*>(callerStack[0]);
699 // Retrieve the exception object in the stack slot saved by the personality.
700 uintptr_t exceptionObject = callerStack[3];
701 _LIBCXXABI_TRACE_STATETAB("Handshake: retrieve exceptionObject=%p from stack=%p\n",
702 reinterpret_cast<void*>(exceptionObject), reinterpret_cast<void*>(callerStack));
703 return exceptionObject;
706 // xlclang++ may generate calls to __Deleted_Virtual.
707 _LIBCXXABI_FUNC_VIS void __Deleted_Virtual() { abort(); }
709 // __catchThrownException is called during AIX library initialization and
710 // termination to handle exceptions. An implementation is also provided in
711 // libC.a(shrcore.o). This implementation is provided for applications that
712 // link with -lc++ (the xlclang++ or ibm-clang++ link default.)
713 _LIBCXXABI_FUNC_VIS int
714 __catchThrownException(void (*cdfunc)(void), // function which may fail
715 void (*cleanup)(void*), // cleanup function
716 void* cleanuparg, // parameter to cleanup function
717 int action) { // control exception throwing and termination
718 enum Action : int { None = 0, Rethrow = 1, Terminate = 2 };
721 if (action == Action::Rethrow && !cleanup) {
722 // No cleanup and rethrow is effectively no-op.
723 // Avoid the catch handler when possible to allow exceptions generated
724 // from xlC binaries to flow through.
731 if (action == Action::Terminate)
734 (*cleanup)(cleanuparg);
735 if (action == Action::Rethrow)
737 assert(action == Action::None);