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 }+/