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