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