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