[AMDGPU] New AMDGPUInsertSingleUseVDST pass (#72388)
[llvm-project.git] / libcxxabi / src / aix_state_tab_eh.inc
blob0cd94834b37adb089f59de0f90fe4f898dc8c10a
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>
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
26   fields:
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
35     of the array;
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
39     function.
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 {
65 extern "C" {
67 // Macros for debugging the state table parsing.
68 #ifdef NDEBUG
69 #  define _LIBCXXABI_TRACE_STATETAB(msg, ...)
70 #  define _LIBCXXABI_TRACE_STATETAB0(msg)
71 #  define _LIBCXXABI_TRACE_STATETAB1(msg)
72 #  define _LIBCXXABI_TRACING_STATETAB 0
73 #else
74 static bool state_tab_dbg() {
75   static bool checked = false;
76   static bool log = false;
77   if (!checked) {
78     log = (getenv("LIBCXXABI_PRINT_STATTAB") != NULL);
79     checked = true;
80   }
81   return log;
84 #  define _LIBCXXABI_TRACE_STATETAB(msg, ...)                                  \
85      do {                                                                      \
86        if (state_tab_dbg())                                                    \
87          fprintf(stderr, "libcxxabi: " msg, __VA_ARGS__);                      \
88      } while (0)
89 #  define _LIBCXXABI_TRACE_STATETAB0(msg)                                      \
90      do {                                                                      \
91        if (state_tab_dbg())                                                    \
92          fprintf(stderr, "libcxxabi: " msg);                                   \
93      } while (0)
94 #  define _LIBCXXABI_TRACE_STATETAB1(msg)                                      \
95      do {                                                                      \
96        if (state_tab_dbg())                                                    \
97          fprintf(stderr, msg);                                                 \
98      } while (0)
100 #  define _LIBCXXABI_TRACING_STATETAB state_tab_dbg()
101 #endif // NDEBUG
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
127                                      // destroyed.
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
133                                      // a global object.
136 namespace {
137 // The finite state machine to be walked.
138 struct FSMEntry {
139   union {
140     // Offset of the object within its stack frame or containing object.
141     intptr_t offset;
142     // Address of a global object.
143     intptr_t address;
144     // Address of the next state if it is an old conditional state change entry.
145     intptr_t nextStatePtr;
146   };
147   union {
148     // Address of the destructor function.
149     void (*destructor)(void*, size_t);
150     // The address of the catch block or cleanup code.
151     void* landingPad;
152   };
153   union {
154     // The flag for actions (when the value is negative).
155     FSMEntryCount actionFlag;
156     // The element count (when the value is positive or zero).
157     size_t elementCount;
158   };
159   size_t elemSize;
160   FSMEntryFlag flags;
161   uint16_t nextState;
164 struct FSM {
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 {
172   int32_t state;
173   struct FSM* table;
174   intptr_t thisValue;
175   int32_t ignoreVBasePtrs;
177 } // namespace
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));
191   try {
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");
196     } else {
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");
201     }
202   } catch (...) {
203     _LIBCXXABI_TRACE_STATETAB0("Uncaught exception in destructor, terminating\n");
204     std::terminate();
205   }
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));
213   try {
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");
218   } catch (...) {
219     _LIBCXXABI_TRACE_STATETAB0("Uncaught exception in delete(), terminating\n");
220     std::terminate();
221   }
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.
232   while (*p)
233     ++p;
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)
240     ++p;
242   // Skip field tb_offset if it exists.
243   if (TBTable->tb.has_tboff)
244     ++p;
246   // Skip field hand_mask if it exists.
247   if (TBTable->tb.int_hndl)
248     ++p;
250   // Skip fields ctl_info and ctl_info_disp if they exist.
251   if (TBTable->tb.has_ctl)
252     p += 1 + *p;
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));
258   }
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) {
268   void* addr;
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);
282   } else {
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",
285                               addr);
286   }
287   return addr;
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) {
302     // Do Phase 1
303     if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND)) {
304       // None of these flags should be set during Phase 1.
305       //   Client error
306       results.reason = _URC_FATAL_PHASE1_ERROR;
307       return;
308     }
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.
313       //    Client error
314       results.reason = _URC_FATAL_PHASE2_ERROR;
315       return;
316     }
317   } else {
318     // Neither _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE is set.
319     //   Client error
320     results.reason = _URC_FATAL_PHASE1_ERROR;
321     return;
322   }
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));
339   }
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;
347     return;
348   }
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;
361     } else {
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;
365     }
366     return;
367   }
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 "
380                                 "%7ld %#7x %7d\n",
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);
385     }
386   }
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;
404           return;
405         }
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
410         // match.
411         _LIBCXXABI_TRACE_STATETAB0("Found a catch handler, return _URC_HANDLER_FOUND\n");
412         results.reason = _URC_HANDLER_FOUND;
413         return;
414       }
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;
418         return;
419       }
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.
428       }
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.
436       }
437       // Go to the next state.
438       currState = currFSMEntry->nextState;
439     }
440     _LIBCXXABI_TRACE_STATETAB0("No catch handler found, return _URC_CONTINUE_UNWIND\n");
441     results.reason = _URC_CONTINUE_UNWIND;
442     return;
443   }
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");
451         std::terminate();
452       }
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.
463       }
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.
472       }
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
479                  ? "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;
486         return;
487       }
488       if (currFSMEntry->elementCount > 0) {
489         if (currFSMEntry->flags & FSMEntryFlag::vBaseFlag && state->ignoreVBasePtrs) {
490           _LIBCXXABI_TRACE_STATETAB0("Ignoring virtual base dtor.\n");
491         } else {
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);
503         }
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));
515         }
516         _LIBCXXABI_TRACE_STATETAB("Delete object at %p\n", addr);
517         invoke_delete(currFSMEntry, addr);
518       } else {
519         _LIBCXXABI_TRACE_STATETAB("Unknown entry in FSM (count=%ld), ignored\n",
520                                   currFSMEntry->elementCount);
521       } // End of action switching.
523       // Go to next state.
524       state->state = currFSMEntry->nextState;
525     }
526     _LIBCXXABI_TRACE_STATETAB0("No catch handler, return _URC_CONTINUE_UNWIND\n");
527     results.reason = _URC_CONTINUE_UNWIND;
528     return;
529   }
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
548     //   halts unwinding
549     return results.reason;
550   }
551   if (actions & _UA_CLEANUP_PHASE) {
552     // Phase 2 cleanup:
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;
567     }
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;
571   }
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");
589     return false;
590   }
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;
604   } else {
605     _LIBCXXABI_TRACE_STATETAB("exceptionObject %p is NOT a dependent\n", reinterpret_cast<void*>(exceptionObject));
606     exceptionHeader = reinterpret_cast<__cxa_exception*>(exceptionObject + 1) - 1;
607   }
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;
622     obj = thrownObject;
623     _LIBCXXABI_TRACE_STATETAB("Match found for thrownObject=%p\n", thrownObject);
624     return true;
625   }
626   _LIBCXXABI_TRACE_STATETAB0("No match\n");
627   return false;
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.
657     while (*p)
658       ++p;
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)
663       return currentStack;
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]);
670   }
671   // This should not happen.
672   _LIBCXXABI_TRACE_STATETAB0("skip_non_cxx_eh_aware_frames() reached the end of stack frames, aborting\n");
673   abort();
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
683 // frame is found.
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 };
719   if (!cdfunc)
720     return 0;
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.
725     (*cdfunc)();
726     return 0;
727   }
728   try {
729     (*cdfunc)();
730   } catch (...) {
731     if (action == Action::Terminate)
732       std::terminate();
733     if (cleanup)
734       (*cleanup)(cleanuparg);
735     if (action == Action::Rethrow)
736       throw;
737     assert(action == Action::None);
738     return -1; // FAILED
739   }
740   return 0;
743 } // extern "C"
745 }  // __cxxabiv1