deh.d revision 1.1.1.3 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