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