[clang] Handle __declspec() attributes in using
[llvm-project.git] / libcxxabi / src / aix_state_tab_eh.inc
blob128a0ab34af7e54cce32fd3fda415b013b985d96
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 //  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 //===----------------------------------------------------------------------===//
13 #include <new>
14 #include <stdio.h>
15 #include <sys/debug.h>
17 #if !__has_cpp_attribute(clang::optnone)
18 #error This file requires clang::optnone attribute support
19 #endif
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
30   fields:
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
39     of the array;
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
43     function.
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 {
69 extern "C" {
71 // Macros for debugging the state table parsing.
72 #ifdef NDEBUG
73 #  define _LIBCXXABI_TRACE_STATETAB(msg, ...)
74 #  define _LIBCXXABI_TRACE_STATETAB0(msg)
75 #  define _LIBCXXABI_TRACE_STATETAB1(msg)
76 #  define _LIBCXXABI_TRACING_STATETAB 0
77 #else
78 static bool state_tab_dbg() {
79   static bool checked = false;
80   static bool log = false;
81   if (!checked) {
82     log = (getenv("LIBCXXABI_PRINT_STATTAB") != NULL);
83     checked = true;
84   }
85   return log;
88 #  define _LIBCXXABI_TRACE_STATETAB(msg, ...)                                  \
89      do {                                                                      \
90        if (state_tab_dbg())                                                    \
91          fprintf(stderr, "libcxxabi: " msg, __VA_ARGS__);                      \
92      } while (0)
93 #  define _LIBCXXABI_TRACE_STATETAB0(msg)                                      \
94      do {                                                                      \
95        if (state_tab_dbg())                                                    \
96          fprintf(stderr, "libcxxabi: " msg);                                   \
97      } while (0)
98 #  define _LIBCXXABI_TRACE_STATETAB1(msg)                                      \
99      do {                                                                      \
100        if (state_tab_dbg())                                                    \
101          fprintf(stderr, msg);                                                 \
102      } while (0)
104 #  define _LIBCXXABI_TRACING_STATETAB state_tab_dbg()
105 #endif // NDEBUG
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
131                                      // destroyed.
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
137                                      // a global object.
140 namespace {
141 // The finite state machine to be walked.
142 struct FSMEntry {
143   union {
144     // Offset of the object within its stack frame or containing object.
145     intptr_t offset;
146     // Address of a global object.
147     intptr_t address;
148     // Address of the next state if it is an old conditional state change entry.
149     intptr_t nextStatePtr;
150   };
151   union {
152     // Address of the destructor function.
153     void (*destructor)(void*, size_t);
154     // The address of the catch block or cleanup code.
155     void* landingPad;
156   };
157   union {
158     // The flag for actions (when the value is negative).
159     FSMEntryCount actionFlag;
160     // The element count (when the value is positive or zero).
161     size_t elementCount;
162   };
163   size_t elemSize;
164   FSMEntryFlag flags;
165   uint16_t nextState;
168 struct FSM {
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 {
176   int32_t state;
177   struct FSM* table;
178   intptr_t thisValue;
179   int32_t ignoreVBasePtrs;
181 } // namespace
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));
195   try {
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");
200     } else {
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");
205     }
206   } catch (...) {
207     _LIBCXXABI_TRACE_STATETAB0("Uncaught exception in destructor, terminating\n");
208     std::terminate();
209   }
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));
217   try {
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");
222   } catch (...) {
223     _LIBCXXABI_TRACE_STATETAB0("Uncaught exception in delete(), terminating\n");
224     std::terminate();
225   }
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.
236   while (*p)
237     ++p;
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)
244     ++p;
246   // Skip field tb_offset if it exists.
247   if (TBTable->tb.has_tboff)
248     ++p;
250   // Skip field hand_mask if it exists.
251   if (TBTable->tb.int_hndl)
252     ++p;
254   // Skip fields ctl_info and ctl_info_disp if they exist.
255   if (TBTable->tb.has_ctl)
256     p += 1 + *p;
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));
262   }
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) {
272   void* addr;
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);
286   } else {
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",
289                               addr);
290   }
291   return addr;
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) {
306     // Do Phase 1
307     if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND)) {
308       // None of these flags should be set during Phase 1.
309       //   Client error
310       results.reason = _URC_FATAL_PHASE1_ERROR;
311       return;
312     }
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.
317       //    Client error
318       results.reason = _URC_FATAL_PHASE2_ERROR;
319       return;
320     }
321   } else {
322     // Neither _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE is set.
323     //   Client error
324     results.reason = _URC_FATAL_PHASE1_ERROR;
325     return;
326   }
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));
343   }
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;
351     return;
352   }
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;
365     } else {
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;
369     }
370     return;
371   }
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 "
384                                 "%7ld %#7x %7d\n",
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);
389     }
390   }
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;
408           return;
409         }
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
414         // match.
415         _LIBCXXABI_TRACE_STATETAB0("Found a catch handler, return _URC_HANDLER_FOUND\n");
416         results.reason = _URC_HANDLER_FOUND;
417         return;
418       }
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;
422         return;
423       }
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.
432       }
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.
440       }
441       // Go to the next state.
442       currState = currFSMEntry->nextState;
443     }
444     _LIBCXXABI_TRACE_STATETAB0("No catch handler found, return _URC_CONTINUE_UNWIND\n");
445     results.reason = _URC_CONTINUE_UNWIND;
446     return;
447   }
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");
455         std::terminate();
456       }
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.
467       }
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.
476       }
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
483                  ? "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;
490         return;
491       }
492       if (currFSMEntry->elementCount > 0) {
493         if (currFSMEntry->flags & FSMEntryFlag::vBaseFlag && state->ignoreVBasePtrs) {
494           _LIBCXXABI_TRACE_STATETAB0("Ignoring virtual base dtor.\n");
495         } else {
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);
507         }
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));
519         }
520         _LIBCXXABI_TRACE_STATETAB("Delete object at %p\n", addr);
521         invoke_delete(currFSMEntry, addr);
522       } else {
523         _LIBCXXABI_TRACE_STATETAB("Unknown entry in FSM (count=%ld), ignored\n",
524                                   currFSMEntry->elementCount);
525       } // End of action switching.
527       // Go to next state.
528       state->state = currFSMEntry->nextState;
529     }
530     _LIBCXXABI_TRACE_STATETAB0("No catch handler, return _URC_CONTINUE_UNWIND\n");
531     results.reason = _URC_CONTINUE_UNWIND;
532     return;
533   }
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
552     //   halts unwinding
553     return results.reason;
554   }
555   if (actions & _UA_CLEANUP_PHASE) {
556     // Phase 2 cleanup:
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;
570     }
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;
574   }
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");
592     return false;
593   }
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;
607   } else {
608     _LIBCXXABI_TRACE_STATETAB("exceptionObject %p is NOT a dependent\n", reinterpret_cast<void*>(exceptionObject));
609     exceptionHeader = reinterpret_cast<__cxa_exception*>(exceptionObject + 1) - 1;
610   }
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;
625     obj = thrownObject;
626     _LIBCXXABI_TRACE_STATETAB("Match found for thrownObject=%p\n", thrownObject);
627     return true;
628   }
629   _LIBCXXABI_TRACE_STATETAB0("No match\n");
630   return false;
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 };
692   if (!cdfunc)
693     return 0;
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.
698     (*cdfunc)();
699     return 0;
700   }
701   try {
702     (*cdfunc)();
703   } catch (...) {
704     if (action == Action::Terminate)
705       std::terminate();
706     if (cleanup)
707       (*cleanup)(cleanuparg);
708     if (action == Action::Rethrow)
709       throw;
710     assert(action == Action::None);
711     return -1; // FAILED
712   }
713   return 0;
716 }  // extern "C"
718 }  // __cxxabiv1