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. 10// 11//===----------------------------------------------------------------------===// 12 13#include <new> 14#include <stdio.h> 15#include <sys/debug.h> 16 17#if !__has_cpp_attribute(clang::optnone) 18#error This file requires clang::optnone attribute support 19#endif 20 21/* 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: 31 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. 44 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+-------+------------------------+--------------------------------------------+ 65*/ 66 67namespace __cxxabiv1 { 68 69extern "C" { 70 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 78static 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; 86} 87 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) 103 104# define _LIBCXXABI_TRACING_STATETAB state_tab_dbg() 105#endif // NDEBUG 106 107namespace __state_table_eh { 108 109using destruct_f = void (*)(void*); 110 111// Definition of flags for the state table entry field 'action flag'. 112enum FSMEntryCount : intptr_t { beginCatch = -1, endCatch = -2, deleteObject = -3, cleanupLabel = -4, terminate = -5 }; 113 114// Definition of flags for the state table entry field 'flags'. 115enum 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. 138}; 139 140namespace { 141// The finite state machine to be walked. 142struct 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; 166}; 167 168struct FSM { 169 uint32_t magic; // Magic number of the state table. 170 int32_t numberOfStates; 171 FSMEntry table[1]; // Actually table[numberOfStates]. 172}; 173 174// The state variable on the stack. 175struct StateVariable { 176 int32_t state; 177 struct FSM* table; 178 intptr_t thisValue; 179 int32_t ignoreVBasePtrs; 180}; 181} // namespace 182 183// State table magic number 184enum 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. 188}; 189 190constexpr size_t dtorArgument = 0x02; // Flag to destructor indicating to free 191 // virtual bases, don't delete object. 192 193static 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 } 210} 211 212static void invoke_delete(FSMEntry* fsmEntry, void* addr) { 213 char* objectAddress = *reinterpret_cast<char**>(addr); 214 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 } 226} 227 228// Get the frame address of the current function from its traceback table 229// which is at the end of each function. 230static 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)); 233 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); 239 240 p = reinterpret_cast<uint32_t*>(&TBTable->tb_ext); 241 242 // Skip field parminfo if it exists. 243 if (TBTable->tb.fixedparms || TBTable->tb.floatparms) 244 ++p; 245 246 // Skip field tb_offset if it exists. 247 if (TBTable->tb.has_tboff) 248 ++p; 249 250 // Skip field hand_mask if it exists. 251 if (TBTable->tb.int_hndl) 252 ++p; 253 254 // Skip fields ctl_info and ctl_info_disp if they exist. 255 if (TBTable->tb.has_ctl) 256 p += 1 + *p; 257 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 } 263 264 if (TBTable->tb.uses_alloca) 265 framePointerReg = *reinterpret_cast<char*>(p); 266 267 return _Unwind_GetGR(context, framePointerReg); 268} 269 270// Calculate the object address from the FSM entry. 271static 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; 292} 293 294static 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; 303 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 } 327 328 if (_LIBCXXABI_TRACING_STATETAB) { 329 _LIBCXXABI_TRACE_STATETAB1("\n"); 330 _LIBCXXABI_TRACE_STATETAB("%s: actions=%d (", __func__, actions); 331 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 } 344 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; 356 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 } 372 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 } 391 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; 396 397 while (currState > 0) { 398 currFSMEntry = &fsm->table[currState - 1]; 399 _LIBCXXABI_TRACE_STATETAB("Processing state=%d, flags=0x%hx\n", currState, currFSMEntry->flags); 400 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]; 452 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) { 479 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)); 486 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); 501 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. 515 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. 526 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); 538} 539 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; 546 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; 577} 578} // namespace __state_table_eh 579 580// The following are EH helper functions for xlclang++ compiled code. 581 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)); 589 590 if (!__isOurExceptionClass(exceptionObject)) { 591 _LIBCXXABI_TRACE_STATETAB0("No match, not a C++ exception\n"); 592 return false; 593 } 594 595 __cxa_exception* exceptionHeader = 0; 596 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 } 611 612 void* thrownObject = reinterpret_cast<void*>(exceptionObject + 1); 613 std::type_info* throwTypeInfo = exceptionHeader->exceptionType; 614 615 // Get the type info for the thrown type and this catch clause and 616 // see if the catch caluse can catch that type. 617 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; 631} 632 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); 642} 643 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)) 648static void force_a_stackframe() {} 649 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(); 666 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; 677} 678 679// xlclang++ may generate calls to __Deleted_Virtual. 680_LIBCXXABI_FUNC_VIS void __Deleted_Virtual() { abort(); } 681 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; 714} 715 716} // extern "C" 717 718} // __cxxabiv1 719