1 module rt.eh.ldc_dwarf; 2 3 import unwind; 4 import lwdr.tracking; 5 import lifetime.class_ : _d_isbaseof; 6 7 enum GNU_ARM_EABI_Unwinder = true; 8 9 /** 10 * Declare all known and handled exception classes. 11 * D exceptions -- "GNUCD\0\0\0". 12 * C++ exceptions -- "GNUCC++\0" 13 * C++ dependent exceptions -- "GNUCC++\x01" 14 */ 15 static if (GNU_ARM_EABI_Unwinder) 16 { 17 enum _Unwind_Exception_Class gdcExceptionClass = "GNUCD\0\0\0"; 18 enum _Unwind_Exception_Class gxxExceptionClass = "GNUCC++\0"; 19 enum _Unwind_Exception_Class gxxDependentExceptionClass = "GNUCC++\x01"; 20 } 21 else 22 { 23 enum _Unwind_Exception_Class gdcExceptionClass = 24 (cast(_Unwind_Exception_Class)'G' << 56) | 25 (cast(_Unwind_Exception_Class)'N' << 48) | 26 (cast(_Unwind_Exception_Class)'U' << 40) | 27 (cast(_Unwind_Exception_Class)'C' << 32) | 28 (cast(_Unwind_Exception_Class)'D' << 24); 29 30 enum _Unwind_Exception_Class gxxExceptionClass = 31 (cast(_Unwind_Exception_Class)'G' << 56) | 32 (cast(_Unwind_Exception_Class)'N' << 48) | 33 (cast(_Unwind_Exception_Class)'U' << 40) | 34 (cast(_Unwind_Exception_Class)'C' << 32) | 35 (cast(_Unwind_Exception_Class)'C' << 24) | 36 (cast(_Unwind_Exception_Class)'+' << 16) | 37 (cast(_Unwind_Exception_Class)'+' << 8) | 38 (cast(_Unwind_Exception_Class)0 << 0); 39 40 enum _Unwind_Exception_Class gxxDependentExceptionClass = 41 gxxExceptionClass + 1; 42 } 43 44 /** 45 * Checks for GDC exception class. 46 */ 47 bool isGdcExceptionClass(_Unwind_Exception_Class c) @nogc 48 { 49 static if (GNU_ARM_EABI_Unwinder) 50 { 51 return c[0] == gdcExceptionClass[0] 52 && c[1] == gdcExceptionClass[1] 53 && c[2] == gdcExceptionClass[2] 54 && c[3] == gdcExceptionClass[3] 55 && c[4] == gdcExceptionClass[4] 56 && c[5] == gdcExceptionClass[5] 57 && c[6] == gdcExceptionClass[6] 58 && c[7] == gdcExceptionClass[7]; 59 } 60 else 61 { 62 return c == gdcExceptionClass; 63 } 64 } 65 66 /** 67 * Checks for any C++ exception class. 68 */ 69 bool isGxxExceptionClass(_Unwind_Exception_Class c) @nogc 70 { 71 static if (GNU_ARM_EABI_Unwinder) 72 { 73 return c[0] == gxxExceptionClass[0] 74 && c[1] == gxxExceptionClass[1] 75 && c[2] == gxxExceptionClass[2] 76 && c[3] == gxxExceptionClass[3] 77 && c[4] == gxxExceptionClass[4] 78 && c[5] == gxxExceptionClass[5] 79 && c[6] == gxxExceptionClass[6] 80 && (c[7] == gxxExceptionClass[7] 81 || c[7] == gxxDependentExceptionClass[7]); 82 } 83 else 84 { 85 return c == gxxExceptionClass 86 || c == gxxDependentExceptionClass; 87 } 88 } 89 90 /** 91 * Checks for primary or dependent, but not that it is a C++ exception. 92 */ 93 bool isDependentException(_Unwind_Exception_Class c) @nogc 94 { 95 static if (GNU_ARM_EABI_Unwinder) 96 return (c[7] == '\x01'); 97 else 98 return (c & 1); 99 } 100 101 /** 102 * A D exception object consists of a header, which is a wrapper 103 * around an unwind object header with additional D specific 104 * information, prefixed by the exception object itself. 105 */ 106 struct ExceptionHeader 107 { 108 // Because of a lack of __aligned__ style attribute, our object 109 // and the unwind object are the first two fields. 110 static if (Throwable.alignof < _Unwind_Exception.alignof) 111 ubyte[_Unwind_Exception.alignof - Throwable.alignof] pad; 112 113 // The object being thrown. The compiled code expects this to 114 // be immediately before the generic exception header. 115 Throwable object; 116 117 // The generic exception header. 118 _Unwind_Exception unwindHeader; 119 120 static assert(unwindHeader.offsetof - object.offsetof == object.sizeof); 121 122 // Cache handler details between Phase 1 and Phase 2. 123 static if (GNU_ARM_EABI_Unwinder) 124 { 125 // Nothing here yet. 126 } 127 else 128 { 129 // Which catch was found. 130 int handler; 131 132 // Language Specific Data Area for function enclosing the handler. 133 const(ubyte)* languageSpecificData; 134 135 // Pointer to catch code. 136 _Unwind_Ptr landingPad; 137 138 // Canonical Frame Address (CFA) for the enclosing handler. 139 _Unwind_Word canonicalFrameAddress; 140 } 141 142 // Stack other thrown exceptions in current thread through here. 143 ExceptionHeader* next; 144 145 // Thread local stack of chained exceptions. 146 static ExceptionHeader* stack; 147 148 // Pre-allocate storage for 1 instance per thread. 149 // Use calloc/free for multiple exceptions in flight. 150 static ExceptionHeader ehstorage; 151 152 /** 153 * Allocate and initialize an ExceptionHeader. 154 */ 155 static ExceptionHeader* create(Throwable o) @nogc 156 { 157 auto eh = &ehstorage; 158 159 // Check exception object in use. 160 if (eh.object) 161 { 162 eh = cast(ExceptionHeader*) lwdrInternal_alloc(ExceptionHeader.sizeof); 163 // Out of memory while throwing - not much else can be done. 164 if (!eh) 165 assert(false); 166 //terminate("out of memory", __LINE__); 167 } 168 eh.object = o; 169 170 eh.unwindHeader.exception_class = gdcExceptionClass; 171 172 return eh; 173 } 174 175 /** 176 * Free ExceptionHeader that was created by create(). 177 */ 178 static void free(ExceptionHeader* eh) @nogc 179 { 180 *eh = ExceptionHeader.init; 181 if (eh != &ehstorage) 182 lwdrInternal_free(eh); 183 } 184 185 /** 186 * Push this onto stack of chained exceptions. 187 */ 188 void push() @nogc 189 { 190 next = stack; 191 stack = &this; 192 } 193 194 /** 195 * Pop and return top of chained exception stack. 196 */ 197 static ExceptionHeader* pop() @nogc 198 { 199 auto eh = stack; 200 stack = eh.next; 201 return eh; 202 } 203 204 /** 205 * Save stage1 handler information in the exception object. 206 */ 207 static void save(_Unwind_Exception* unwindHeader, 208 _Unwind_Word cfa, int handler, 209 const(ubyte)* lsda, _Unwind_Ptr landingPad) @nogc 210 { 211 static if (GNU_ARM_EABI_Unwinder) 212 { 213 unwindHeader.barrier_cache.sp = cfa; 214 unwindHeader.barrier_cache.bitpattern[1] = cast(_uw)handler; 215 unwindHeader.barrier_cache.bitpattern[2] = cast(_uw)lsda; 216 unwindHeader.barrier_cache.bitpattern[3] = cast(_uw)landingPad; 217 } 218 else 219 { 220 ExceptionHeader* eh = toExceptionHeader(unwindHeader); 221 eh.canonicalFrameAddress = cfa; 222 eh.handler = handler; 223 eh.languageSpecificData = lsda; 224 eh.landingPad = landingPad; 225 } 226 } 227 228 /** 229 * Restore the catch handler data saved during phase1. 230 */ 231 static void restore(_Unwind_Exception* unwindHeader, out int handler, 232 out const(ubyte)* lsda, out _Unwind_Ptr landingPad, 233 out _Unwind_Word cfa) @nogc 234 { 235 static if (GNU_ARM_EABI_Unwinder) 236 { 237 cfa = unwindHeader.barrier_cache.sp; 238 handler = cast(int)unwindHeader.barrier_cache.bitpattern[1]; 239 lsda = cast(ubyte*)unwindHeader.barrier_cache.bitpattern[2]; 240 landingPad = cast(_Unwind_Ptr)unwindHeader.barrier_cache.bitpattern[3]; 241 } 242 else 243 { 244 ExceptionHeader* eh = toExceptionHeader(unwindHeader); 245 cfa = eh.canonicalFrameAddress; 246 handler = eh.handler; 247 lsda = eh.languageSpecificData; 248 landingPad = cast(_Unwind_Ptr)eh.landingPad; 249 } 250 } 251 252 /** 253 * Convert from pointer to unwindHeader to pointer to ExceptionHeader 254 * that it is embedded inside of. 255 */ 256 static ExceptionHeader* toExceptionHeader(_Unwind_Exception* exc) @nogc 257 { 258 return cast(ExceptionHeader*)(cast(void*)exc - ExceptionHeader.unwindHeader.offsetof); 259 } 260 } 261 262 /** 263 * Map to C++ std::type_info's virtual functions from D, 264 * being careful to not require linking with libstdc++. 265 * So it is given a different name. 266 */ 267 extern(C++) interface CxxTypeInfo 268 { 269 void dtor1(); 270 void dtor2(); 271 bool __is_pointer_p() const; 272 bool __is_function_p() const; 273 bool __do_catch(const CxxTypeInfo, void**, uint) const; 274 bool __do_upcast(const void*, void**) const; 275 } 276 277 /** 278 * Structure of a C++ exception, represented as a C structure. 279 * See unwind-cxx.h for the full definition. 280 */ 281 struct CxaExceptionHeader 282 { 283 union 284 { 285 CxxTypeInfo exceptionType; 286 void* primaryException; 287 } 288 void function(void*) exceptionDestructor; 289 void function() unexpectedHandler; 290 void function() terminateHandler; 291 CxaExceptionHeader* nextException; 292 int handlerCount; 293 294 static if (GNU_ARM_EABI_Unwinder) 295 { 296 CxaExceptionHeader* nextPropagatingException; 297 int propagationCount; 298 } 299 else 300 { 301 int handlerSwitchValue; 302 const(ubyte)* actionRecord; 303 const(ubyte)* languageSpecificData; 304 _Unwind_Ptr catchTemp; 305 void* adjustedPtr; 306 } 307 308 _Unwind_Exception unwindHeader; 309 310 /** 311 * There's no saving between phases, so only cache pointer. 312 * __cxa_begin_catch expects this to be set. 313 */ 314 static void save(_Unwind_Exception* unwindHeader, void* thrownPtr) @nogc 315 { 316 static if (GNU_ARM_EABI_Unwinder) 317 unwindHeader.barrier_cache.bitpattern[0] = cast(_uw) thrownPtr; 318 else 319 { 320 auto eh = toExceptionHeader(unwindHeader); 321 eh.adjustedPtr = thrownPtr; 322 } 323 } 324 325 /** 326 * Get pointer to the thrown object if the thrown object type behind the 327 * exception is implicitly convertible to the catch type. 328 */ 329 static void* getAdjustedPtr(_Unwind_Exception* exc, CxxTypeInfo catchType) 330 { 331 void* thrownPtr; 332 333 // A dependent C++ exceptions is just a wrapper around the unwind header. 334 // A primary C++ exception has the thrown object located immediately after it. 335 if (isDependentException(exc.exception_class)) 336 thrownPtr = toExceptionHeader(exc).primaryException; 337 else 338 thrownPtr = cast(void*)(exc + 1); 339 340 // Pointer types need to adjust the actual pointer, not the pointer that is 341 // the exception object. This also has the effect of passing pointer types 342 // "by value" through the __cxa_begin_catch return value. 343 const throw_type = (cast(CxaExceptionHeader*)thrownPtr - 1).exceptionType; 344 345 if (throw_type.__is_pointer_p()) 346 thrownPtr = *cast(void**)thrownPtr; 347 348 // Pointer adjustment may be necessary due to multiple inheritance 349 if (catchType is throw_type 350 || catchType.__do_catch(throw_type, &thrownPtr, 1)) 351 return thrownPtr; 352 353 return null; 354 } 355 356 /** 357 * Convert from pointer to unwindHeader to pointer to CxaExceptionHeader 358 * that it is embedded inside of. 359 */ 360 static CxaExceptionHeader* toExceptionHeader(_Unwind_Exception* exc) @nogc 361 { 362 return cast(CxaExceptionHeader*)(exc + 1) - 1; 363 } 364 } 365 366 /** 367 * Called if exception handling must be abandoned for any reason. 368 */ 369 private void terminate(string msg, uint line) @nogc 370 { 371 assert(false); 372 } 373 374 /** 375 * Called when fibers switch contexts. 376 */ 377 extern(C) void* _d_eh_swapContext(void* newContext) nothrow @nogc 378 { 379 auto old = ExceptionHeader.stack; 380 ExceptionHeader.stack = cast(ExceptionHeader*)newContext; 381 return old; 382 } 383 384 extern(C) void* _d_eh_enter_catch(_Unwind_Exception* unwindHeader) 385 { 386 return __gdc_begin_catch(unwindHeader); 387 } 388 389 /** 390 * Called before starting a catch. Returns the exception object. 391 */ 392 extern(C) void* __gdc_begin_catch(_Unwind_Exception* unwindHeader) 393 { 394 ExceptionHeader* header = ExceptionHeader.toExceptionHeader(unwindHeader); 395 396 void* objectp = cast(void*)header.object; 397 398 // Something went wrong when stacking up chained headers... 399 if (header != ExceptionHeader.pop()) 400 terminate("catch error", __LINE__); 401 402 // Handling for this exception is complete. 403 _Unwind_DeleteException(&header.unwindHeader); 404 405 return objectp; 406 } 407 408 extern(C) void _d_throw_exception(Throwable object) 409 { 410 _d_throw(object); 411 } 412 413 /** 414 * Perform a throw, D style. Throw will unwind through this call, 415 * so there better not be any handlers or exception thrown here. 416 */ 417 extern(C) void _d_throw(Throwable object) 418 { 419 // If possible, avoid always allocating new memory for exception headers. 420 ExceptionHeader *eh = ExceptionHeader.create(object); 421 422 // Add to thrown exception stack. 423 eh.push(); 424 425 // Called by unwinder when exception object needs destruction by other than our code. 426 extern(C) void exception_cleanup(_Unwind_Reason_Code code, _Unwind_Exception* exc) 427 { 428 // If we haven't been caught by a foreign handler, then this is 429 // some sort of unwind error. In that case just die immediately. 430 // _Unwind_DeleteException in the HP-UX IA64 libunwind library 431 // returns _URC_NO_REASON and not _URC_FOREIGN_EXCEPTION_CAUGHT 432 // like the GCC _Unwind_DeleteException function does. 433 if (code != _URC_FOREIGN_EXCEPTION_CAUGHT && code != _URC_NO_REASON) 434 terminate("uncaught exception", __LINE__); 435 436 auto eh = ExceptionHeader.toExceptionHeader(exc); 437 ExceptionHeader.free(eh); 438 } 439 440 eh.unwindHeader.exception_cleanup = &exception_cleanup; 441 442 // Runtime now expects us to do this first before unwinding. 443 444 //_d_createTrace(eh.object, null); 445 446 // We're happy with setjmp/longjmp exceptions or region-based 447 // exception handlers: entry points are provided here for both. 448 _Unwind_Reason_Code r = void; 449 450 version (GNU_SjLj_Exceptions) 451 r = _Unwind_SjLj_RaiseException(&eh.unwindHeader); 452 else 453 r = _Unwind_RaiseException(&eh.unwindHeader); 454 455 // If code == _URC_END_OF_STACK, then we reached top of stack without finding 456 // a handler for the exception. Since each thread is run in a try/catch, 457 // this oughtn't happen. If code is something else, we encountered some sort 458 // of heinous lossage from which we could not recover. As is the way of such 459 // things, almost certainly we will have crashed before now, rather than 460 // actually being able to diagnose the problem. 461 if (r == _URC_END_OF_STACK) 462 { 463 __gdc_begin_catch(&eh.unwindHeader); 464 //_d_print_throwable(object); 465 terminate("uncaught exception", __LINE__); 466 } 467 468 terminate("unwind error", __LINE__); 469 } 470 471 static if (GNU_ARM_EABI_Unwinder) 472 { 473 enum personality_fn_attributes = "";//attribute("target", ("general-regs-only")); 474 } 475 else 476 { 477 enum personality_fn_attributes = ""; 478 } 479 480 /** 481 * Read and extract information from the LSDA (.gcc_except_table section). 482 */ 483 @personality_fn_attributes 484 _Unwind_Reason_Code scanLSDA(const(ubyte)* lsda, _Unwind_Exception_Class exceptionClass, 485 _Unwind_Action actions, _Unwind_Exception* unwindHeader, 486 _Unwind_Context* context, _Unwind_Word cfa, 487 out _Unwind_Ptr landingPad, out int handler) 488 { 489 // If no LSDA, then there are no handlers or cleanups. 490 if (lsda is null) 491 return CONTINUE_UNWINDING(unwindHeader, context); 492 493 // Parse the LSDA header 494 auto p = lsda; 495 496 auto Start = (context ? _Unwind_GetRegionStart(context) : 0); 497 498 // Find @LPStart, the base to which landing pad offsets are relative. 499 ubyte LPStartEncoding = *p++; 500 _Unwind_Ptr LPStart = 0; 501 502 if (LPStartEncoding != DW_EH_PE_omit) 503 LPStart = read_encoded_value(context, LPStartEncoding, &p); 504 else 505 LPStart = Start; 506 507 // Find @TType, the base of the handler and exception spec type data. 508 ubyte TTypeEncoding = *p++; 509 const(ubyte)* TType = null; 510 511 if (TTypeEncoding != DW_EH_PE_omit) 512 { 513 static if (__traits(compiles, _TTYPE_ENCODING)) 514 { 515 // Older ARM EABI toolchains set this value incorrectly, so use a 516 // hardcoded OS-specific format. 517 TTypeEncoding = _TTYPE_ENCODING; 518 } 519 auto TTbase = read_uleb128(&p); 520 TType = p + TTbase; 521 } 522 523 // The encoding and length of the call-site table; the action table 524 // immediately follows. 525 ubyte CSEncoding = *p++; 526 auto CSTableSize = read_uleb128(&p); 527 const(ubyte)* actionTable = p + CSTableSize; 528 529 auto TTypeBase = base_of_encoded_value(TTypeEncoding, context); 530 531 // Get instruction pointer (ip) at start of instruction that threw. 532 version (CRuntime_Glibc) 533 { 534 int ip_before_insn; 535 auto ip = _Unwind_GetIPInfo(context, &ip_before_insn); 536 if (!ip_before_insn) 537 --ip; 538 } 539 else 540 { 541 auto ip = _Unwind_GetIP(context); 542 --ip; 543 } 544 545 bool saw_cleanup = false; 546 bool saw_handler = false; 547 const(ubyte)* actionRecord = null; 548 549 version (GNU_SjLj_Exceptions) 550 { 551 // The given "IP" is an index into the call-site table, with two 552 // exceptions -- -1 means no-action, and 0 means terminate. 553 // But since we're using uleb128 values, we've not got random 554 // access to the array. 555 if (cast(int) ip <= 0) 556 { 557 return _URC_CONTINUE_UNWIND; 558 } 559 else 560 { 561 _uleb128_t CSLandingPad, CSAction; 562 do 563 { 564 CSLandingPad = read_uleb128(p); 565 CSAction = read_uleb128(p); 566 } 567 while (--ip); 568 569 // Can never have null landing pad for sjlj -- that would have 570 // been indicated by a -1 call site index. 571 landingPad = CSLandingPad + 1; 572 if (CSAction) 573 actionRecord = actionTable + CSAction - 1; 574 } 575 } 576 else 577 { 578 // Search the call-site table for the action associated with this IP. 579 while (p < actionTable) 580 { 581 // Note that all call-site encodings are "absolute" displacements. 582 auto CSStart = read_encoded_value(null, CSEncoding, &p); 583 auto CSLen = read_encoded_value(null, CSEncoding, &p); 584 auto CSLandingPad = read_encoded_value(null, CSEncoding, &p); 585 auto CSAction = read_uleb128(&p); 586 587 // The table is sorted, so if we've passed the ip, stop. 588 if (ip < Start + CSStart) 589 p = actionTable; 590 else if (ip < Start + CSStart + CSLen) 591 { 592 if (CSLandingPad) 593 landingPad = LPStart + CSLandingPad; 594 if (CSAction) 595 actionRecord = actionTable + CSAction - 1; 596 break; 597 } 598 } 599 } 600 601 if (landingPad == 0) 602 { 603 // IP is present, but has a null landing pad. 604 // No cleanups or handlers to be run. 605 } 606 else if (actionRecord is null) 607 { 608 // If ip is present, has a non-null landing pad, and a null 609 // action table offset, then there are only cleanups present. 610 // Cleanups use a zero switch value, as set above. 611 saw_cleanup = true; 612 } 613 else 614 { 615 // Otherwise we have a catch handler or exception specification. 616 handler = actionTableLookup(actions, unwindHeader, actionRecord, 617 lsda, exceptionClass, TTypeBase, 618 TType, TTypeEncoding, 619 saw_handler, saw_cleanup); 620 } 621 622 // IP is not in table. No associated cleanups. 623 if (!saw_handler && !saw_cleanup) 624 return CONTINUE_UNWINDING(unwindHeader, context); 625 626 if (actions & _UA_SEARCH_PHASE) 627 { 628 if (!saw_handler) 629 return CONTINUE_UNWINDING(unwindHeader, context); 630 631 // For domestic exceptions, we cache data from phase 1 for phase 2. 632 if (isGdcExceptionClass(exceptionClass)) 633 ExceptionHeader.save(unwindHeader, cfa, handler, lsda, landingPad); 634 635 return _URC_HANDLER_FOUND; 636 } 637 638 return 0; 639 } 640 641 /** 642 * Look up and return the handler index of the classType in Action Table. 643 */ 644 int actionTableLookup(_Unwind_Action actions, _Unwind_Exception* unwindHeader, 645 const(ubyte)* actionRecord, const(ubyte)* lsda, 646 _Unwind_Exception_Class exceptionClass, 647 _Unwind_Ptr TTypeBase, const(ubyte)* TType, 648 ubyte TTypeEncoding, 649 out bool saw_handler, out bool saw_cleanup) 650 { 651 ClassInfo thrownType; 652 if (isGdcExceptionClass(exceptionClass)) 653 { 654 thrownType = getClassInfo(unwindHeader, lsda); 655 } 656 657 while (1) 658 { 659 auto ap = actionRecord; 660 auto ARFilter = read_sleb128(&ap); 661 auto apn = ap; 662 auto ARDisp = read_sleb128(&ap); 663 664 if (ARFilter == 0) 665 { 666 // Zero filter values are cleanups. 667 saw_cleanup = true; 668 } 669 else if (actions & _UA_FORCE_UNWIND) 670 { 671 // During forced unwinding, we only run cleanups. 672 } 673 else if (ARFilter > 0) 674 { 675 // Positive filter values are handlers. 676 auto encodedSize = size_of_encoded_value(TTypeEncoding); 677 678 // ARFilter is the negative index from TType, which is where 679 // the ClassInfo is stored. 680 const(ubyte)* tp = TType - ARFilter * encodedSize; 681 682 auto entry = read_encoded_value_with_base(TTypeEncoding, TTypeBase, &tp); 683 ClassInfo ci = cast(ClassInfo)cast(void*)(entry); 684 685 // D does not have catch-all handlers, and so the following 686 // assumes that we will never handle a null value. 687 assert(ci !is null); 688 689 if (ci.classinfo is __cpp_type_info_ptr.classinfo 690 && isGxxExceptionClass(exceptionClass)) 691 { 692 // catchType is the catch clause type_info. 693 auto catchType = cast(CxxTypeInfo)((cast(__cpp_type_info_ptr)cast(void*)ci).ptr); 694 auto thrownPtr = CxaExceptionHeader.getAdjustedPtr(unwindHeader, catchType); 695 696 if (thrownPtr !is null) 697 { 698 if (actions & _UA_SEARCH_PHASE) 699 CxaExceptionHeader.save(unwindHeader, thrownPtr); 700 saw_handler = true; 701 return cast(int)ARFilter; 702 } 703 } 704 else if (isGdcExceptionClass(exceptionClass) 705 && _d_isbaseof(thrownType, ci)) 706 { 707 saw_handler = true; 708 return cast(int)ARFilter; 709 } 710 else 711 { 712 // ??? What to do about other GNU language exceptions. 713 } 714 } 715 else 716 { 717 // Negative filter values are exception specifications, 718 // which D does not use. 719 break; 720 } 721 722 if (ARDisp == 0) 723 break; 724 actionRecord = apn + ARDisp; 725 } 726 727 return 0; 728 } 729 730 /** 731 * Look at the chain of inflight exceptions and pick the class type that'll 732 * be looked for in catch clauses. 733 */ 734 ClassInfo getClassInfo(_Unwind_Exception* unwindHeader, 735 const(ubyte)* currentLsd) @nogc 736 { 737 ExceptionHeader* eh = ExceptionHeader.toExceptionHeader(unwindHeader); 738 // The first thrown Exception at the top of the stack takes precedence 739 // over others that are inflight, unless an Error was thrown, in which 740 // case, we search for error handlers instead. 741 Throwable ehobject = eh.object; 742 for (ExceptionHeader* ehn = eh.next; ehn; ehn = ehn.next) 743 { 744 const(ubyte)* nextLsd = void; 745 _Unwind_Ptr nextLandingPad = void; 746 _Unwind_Word nextCfa = void; 747 int nextHandler = void; 748 749 ExceptionHeader.restore(&ehn.unwindHeader, nextHandler, nextLsd, nextLandingPad, nextCfa); 750 751 // Don't combine when the exceptions are from different functions. 752 if (currentLsd != nextLsd) 753 break; 754 755 Error e = cast(Error)ehobject; 756 if (e is null || (cast(Error)ehn.object) !is null) 757 { 758 currentLsd = nextLsd; 759 ehobject = ehn.object; 760 } 761 } 762 return ehobject.classinfo; 763 } 764 765 /** 766 * Called when the personality function has found neither a cleanup or handler. 767 * To support ARM EABI personality routines, that must also unwind the stack. 768 */ 769 @personality_fn_attributes 770 _Unwind_Reason_Code CONTINUE_UNWINDING(_Unwind_Exception* unwindHeader, _Unwind_Context* context) 771 { 772 static if (GNU_ARM_EABI_Unwinder) 773 { 774 if (__gnu_unwind_frame(unwindHeader, context) != _URC_OK) 775 return _URC_FAILURE; 776 } 777 return _URC_CONTINUE_UNWIND; 778 } 779 780 /** 781 * Using a different personality function name causes link failures 782 * when trying to mix code using different exception handling models. 783 */ 784 version (GNU_SEH_Exceptions) 785 { 786 enum PERSONALITY_FUNCTION = "__gdc_personality_imp"; 787 788 extern(C) EXCEPTION_DISPOSITION __gdc_personality_seh0(void* ms_exc, void* this_frame, 789 void* ms_orig_context, void* ms_disp) 790 { 791 return _GCC_specific_handler(ms_exc, this_frame, ms_orig_context, 792 ms_disp, &gdc_personality); 793 } 794 } 795 else version (GNU_SjLj_Exceptions) 796 { 797 enum PERSONALITY_FUNCTION = "__gdc_personality_sj0"; 798 799 private int __builtin_eh_return_data_regno(int x) { return x; } 800 } 801 else 802 { 803 enum PERSONALITY_FUNCTION = "__gdc_personality_v0"; 804 } 805 806 extern(C) _Unwind_Reason_Code _d_eh_personality(_Unwind_State state, _Unwind_Exception* unwindHeader, _Unwind_Context* context) 807 { 808 return gdc_personality(state, unwindHeader, context); 809 } 810 811 /** 812 * The "personality" function, specific to each language. 813 */ 814 static if (GNU_ARM_EABI_Unwinder) 815 { 816 pragma(mangle, PERSONALITY_FUNCTION) 817 @personality_fn_attributes 818 extern(C) _Unwind_Reason_Code gdc_personality(_Unwind_State state, 819 _Unwind_Exception* unwindHeader, 820 _Unwind_Context* context) 821 { 822 _Unwind_Action actions; 823 824 switch (state & _US_ACTION_MASK) 825 { 826 case _US_VIRTUAL_UNWIND_FRAME: 827 // If the unwind state pattern is (_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND) 828 // then we don't need to search for any handler as it is not a real exception. 829 // Just unwind the stack. 830 if (state & _US_FORCE_UNWIND) 831 return CONTINUE_UNWINDING(unwindHeader, context); 832 actions = _UA_SEARCH_PHASE; 833 break; 834 835 case _US_UNWIND_FRAME_STARTING: 836 actions = _UA_CLEANUP_PHASE; 837 if (!(state & _US_FORCE_UNWIND) 838 && unwindHeader.barrier_cache.sp == _Unwind_GetGR(context, UNWIND_STACK_REG)) 839 actions |= _UA_HANDLER_FRAME; 840 break; 841 842 case _US_UNWIND_FRAME_RESUME: 843 return CONTINUE_UNWINDING(unwindHeader, context); 844 845 default: 846 terminate("unwind error", __LINE__); 847 } 848 actions |= state & _US_FORCE_UNWIND; 849 850 // The dwarf unwinder assumes the context structure holds things like 851 // the function and LSDA pointers. The ARM implementation caches these 852 // in the exception header (UCB). To avoid rewriting everything we make 853 // the virtual IP register point at the UCB. 854 _Unwind_SetGR(context, UNWIND_POINTER_REG, cast(_Unwind_Ptr)unwindHeader); 855 856 return __gdc_personality(actions, unwindHeader.exception_class, 857 unwindHeader, context); 858 } 859 } 860 else 861 { 862 pragma(mangle, PERSONALITY_FUNCTION) 863 extern(C) _Unwind_Reason_Code gdc_personality(int iversion, 864 _Unwind_Action actions, 865 _Unwind_Exception_Class exceptionClass, 866 _Unwind_Exception* unwindHeader, 867 _Unwind_Context* context) 868 { 869 // Interface version check. 870 if (iversion != 1) 871 return _URC_FATAL_PHASE1_ERROR; 872 873 return __gdc_personality(actions, exceptionClass, unwindHeader, context); 874 } 875 } 876 877 @personality_fn_attributes 878 private _Unwind_Reason_Code __gdc_personality(_Unwind_Action actions, 879 _Unwind_Exception_Class exceptionClass, 880 _Unwind_Exception* unwindHeader, 881 _Unwind_Context* context) 882 { 883 const(ubyte)* lsda; 884 _Unwind_Ptr landingPad; 885 _Unwind_Word cfa; 886 int handler; 887 888 // Shortcut for phase 2 found handler for domestic exception. 889 if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME) 890 && isGdcExceptionClass(exceptionClass)) 891 { 892 ExceptionHeader.restore(unwindHeader, handler, lsda, landingPad, cfa); 893 // Shouldn't have cached a null landing pad in phase 1. 894 if (landingPad == 0) 895 terminate("unwind error", __LINE__); 896 } 897 else 898 { 899 lsda = cast(ubyte*)_Unwind_GetLanguageSpecificData(context); 900 901 static if (GNU_ARM_EABI_Unwinder) 902 cfa = _Unwind_GetGR(context, UNWIND_STACK_REG); 903 else 904 cfa = _Unwind_GetCFA(context); 905 906 auto result = scanLSDA(lsda, exceptionClass, actions, unwindHeader, 907 context, cfa, landingPad, handler); 908 909 // Positive on handler found in phase 1, continue unwinding, or failure. 910 if (result) 911 return result; 912 } 913 914 // Unexpected negative handler, call terminate directly. 915 if (handler < 0) 916 terminate("unwind error", __LINE__); 917 918 // We can't use any of the deh routines with foreign exceptions, 919 // because they all expect unwindHeader to be an ExceptionHeader. 920 if (isGdcExceptionClass(exceptionClass)) 921 { 922 // If there are any in-flight exceptions being thrown, chain our 923 // current object onto the end of the prevous object. 924 ExceptionHeader* eh = ExceptionHeader.toExceptionHeader(unwindHeader); 925 auto currentLsd = lsda; 926 bool bypassed = false; 927 928 while (eh.next) 929 { 930 ExceptionHeader* ehn = eh.next; 931 const(ubyte)* nextLsd = void; 932 _Unwind_Ptr nextLandingPad = void; 933 _Unwind_Word nextCfa = void; 934 int nextHandler = void; 935 936 ExceptionHeader.restore(&ehn.unwindHeader, nextHandler, nextLsd, nextLandingPad, nextCfa); 937 938 Error e = cast(Error)eh.object; 939 if (e !is null && !cast(Error)ehn.object) 940 { 941 // We found an Error, bypass the exception chain. 942 currentLsd = nextLsd; 943 eh = ehn; 944 bypassed = true; 945 continue; 946 } 947 948 // Don't combine when the exceptions are from different functions. 949 if (currentLsd != nextLsd) 950 break; 951 952 // Add our object onto the end of the existing chain. 953 Throwable n = ehn.object; 954 while (n.next) 955 n = n.next; 956 n.next = eh.object; 957 958 // Replace our exception object with in-flight one 959 eh.object = ehn.object; 960 if (nextHandler != handler && !bypassed) 961 { 962 handler = nextHandler; 963 ExceptionHeader.save(unwindHeader, cfa, handler, lsda, landingPad); 964 } 965 966 // Exceptions chained, can now throw away the previous header. 967 eh.next = ehn.next; 968 _Unwind_DeleteException(&ehn.unwindHeader); 969 } 970 971 if (bypassed) 972 { 973 eh = ExceptionHeader.toExceptionHeader(unwindHeader); 974 Error e = cast(Error)eh.object; 975 auto ehn = eh.next; 976 e.bypassedException = ehn.object; 977 eh.next = ehn.next; 978 _Unwind_DeleteException(&ehn.unwindHeader); 979 } 980 } 981 982 // Set up registers and jump to cleanup or handler. 983 // For targets with pointers smaller than the word size, we must extend the 984 // pointer, and this extension is target dependent. 985 _Unwind_SetGR(context, 0, 986 cast(_Unwind_Ptr)unwindHeader); 987 _Unwind_SetGR(context, 1, handler); 988 _Unwind_SetIP(context, landingPad); 989 990 return _URC_INSTALL_CONTEXT; 991 }