]>
Commit | Line | Data |
---|---|---|
982f26e4 AC |
1 | /**************************************************************************** |
2 | * * | |
3 | * GNAT COMPILER COMPONENTS * | |
4 | * * | |
5 | * R A I S E - G C C * | |
6 | * * | |
7 | * C Implementation File * | |
8 | * * | |
1d005acc | 9 | * Copyright (C) 1992-2019, Free Software Foundation, Inc. * |
982f26e4 AC |
10 | * * |
11 | * GNAT is free software; you can redistribute it and/or modify it under * | |
12 | * terms of the GNU General Public License as published by the Free Soft- * | |
748086b7 | 13 | * ware Foundation; either version 3, or (at your option) any later ver- * |
982f26e4 AC |
14 | * sion. GNAT is distributed in the hope that it will be useful, but WITH- * |
15 | * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * | |
748086b7 JJ |
16 | * or FITNESS FOR A PARTICULAR PURPOSE. * |
17 | * * | |
18 | * As a special exception under Section 7 of GPL version 3, you are granted * | |
19 | * additional permissions described in the GCC Runtime Library Exception, * | |
20 | * version 3.1, as published by the Free Software Foundation. * | |
21 | * * | |
22 | * You should have received a copy of the GNU General Public License and * | |
23 | * a copy of the GCC Runtime Library Exception along with this program; * | |
24 | * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see * | |
25 | * <http://www.gnu.org/licenses/>. * | |
982f26e4 AC |
26 | * * |
27 | * GNAT was originally developed by the GNAT team at New York University. * | |
28 | * Extensive contributions were provided by Ada Core Technologies Inc. * | |
29 | * * | |
30 | ****************************************************************************/ | |
31 | ||
32 | /* Code related to the integration of the GCC mechanism for exception | |
33 | handling. */ | |
34 | ||
522aa6ee AC |
35 | #ifndef IN_RTS |
36 | /* For gnat1/gnatbind compilation: use host headers. */ | |
37 | # include "config.h" | |
38 | # include "system.h" | |
39 | /* Don't use fancy_abort. */ | |
40 | # undef abort | |
60aa5228 | 41 | #else |
a6fc663e | 42 | # if !defined(CERT) && !defined(STANDALONE) |
522aa6ee AC |
43 | # include "tconfig.h" |
44 | # include "tsystem.h" | |
45 | # else | |
a6fc663e | 46 | # include "runtime.h" |
522aa6ee AC |
47 | # define HAVE_GETIPINFO 1 |
48 | # endif | |
60aa5228 | 49 | #endif |
d7ffe14c | 50 | |
b381d30b | 51 | #include <stdarg.h> |
6cbfce7e AC |
52 | |
53 | #ifdef __cplusplus | |
54 | # include <cstdlib> | |
55 | #else | |
982f26e4 AC |
56 | typedef char bool; |
57 | # define true 1 | |
58 | # define false 0 | |
6cbfce7e | 59 | #endif |
982f26e4 | 60 | |
982f26e4 AC |
61 | #include "raise.h" |
62 | ||
df66d165 EB |
63 | #ifdef __APPLE__ |
64 | /* On MacOS X, versions older than 10.5 don't export _Unwind_GetIPInfo. */ | |
65 | #undef HAVE_GETIPINFO | |
66 | #if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 | |
67 | #define HAVE_GETIPINFO 1 | |
68 | #endif | |
69 | #endif | |
70 | ||
31821c0f AC |
71 | #if defined (__hpux__) && defined (USE_LIBUNWIND_EXCEPTIONS) |
72 | /* HP-UX B.11.31 ia64 libunwind doesn't have _Unwind_GetIPInfo. */ | |
73 | #undef HAVE_GETIPINFO | |
a6f0cb16 | 74 | #define _UA_END_OF_STACK 0 |
31821c0f AC |
75 | #endif |
76 | ||
982f26e4 AC |
77 | /* The names of a couple of "standard" routines for unwinding/propagation |
78 | actually vary depending on the underlying GCC scheme for exception handling | |
79 | (SJLJ or DWARF). We need a consistently named interface to import from | |
31821c0f | 80 | a-except, so wrappers are defined here. */ |
982f26e4 | 81 | |
522aa6ee AC |
82 | #ifndef IN_RTS |
83 | /* For gnat1/gnatbind compilation: cannot use unwind.h, as it is for the | |
84 | target. So mimic configure... | |
85 | This is a hack ???, the real fix is to link gnat1/gnatbind with the | |
86 | runtime of the build compiler. */ | |
87 | # ifdef EH_MECHANISM_arm | |
88 | # include "config/arm/unwind-arm.h" | |
89 | # else | |
90 | # include "unwind-generic.h" | |
91 | # endif | |
92 | #else | |
93 | # include "unwind.h" | |
94 | #endif | |
982f26e4 | 95 | |
6cbfce7e AC |
96 | #ifdef __cplusplus |
97 | extern "C" { | |
98 | #endif | |
99 | ||
982f26e4 AC |
100 | typedef struct _Unwind_Context _Unwind_Context; |
101 | typedef struct _Unwind_Exception _Unwind_Exception; | |
102 | ||
982f26e4 AC |
103 | _Unwind_Reason_Code |
104 | __gnat_Unwind_RaiseException (_Unwind_Exception *); | |
105 | ||
106 | _Unwind_Reason_Code | |
6cbfce7e | 107 | __gnat_Unwind_ForcedUnwind (_Unwind_Exception *, _Unwind_Stop_Fn, void *); |
982f26e4 | 108 | |
557b744a OH |
109 | extern struct Exception_Occurrence * |
110 | __gnat_setup_current_excep (_Unwind_Exception *, _Unwind_Action); | |
111 | ||
a6f0cb16 | 112 | extern void __gnat_unhandled_except_handler (_Unwind_Exception *); |
982f26e4 | 113 | |
60aa5228 | 114 | #ifdef CERT |
ac8380d5 AC |
115 | /* Called in case of error during propagation. */ |
116 | extern void __gnat_raise_abort (void) __attribute__ ((noreturn)); | |
60aa5228 | 117 | #define abort() __gnat_raise_abort() |
a6fc663e AC |
118 | |
119 | #elif defined(STANDALONE) | |
120 | #include <stdlib.h> | |
121 | #define inhibit_libc | |
60aa5228 AC |
122 | #endif |
123 | ||
982f26e4 AC |
124 | #include "unwind-pe.h" |
125 | ||
522aa6ee AC |
126 | #ifdef __ARM_EABI_UNWINDER__ |
127 | /* for memcmp */ | |
128 | #include <string.h> | |
129 | #endif | |
130 | ||
5accd7b6 AC |
131 | /* The known and handled exception classes. */ |
132 | ||
158d55fa AC |
133 | #ifdef __ARM_EABI_UNWINDER__ |
134 | #define CXX_EXCEPTION_CLASS "GNUCC++" | |
135 | #define GNAT_EXCEPTION_CLASS "GNU-Ada" | |
136 | #else | |
5accd7b6 AC |
137 | #define CXX_EXCEPTION_CLASS 0x474e5543432b2b00ULL |
138 | #define GNAT_EXCEPTION_CLASS 0x474e552d41646100ULL | |
158d55fa | 139 | #endif |
982f26e4 | 140 | |
5644b7e8 AC |
141 | /* Structure of a C++ exception, represented as a C structure... See |
142 | unwind-cxx.h for the full definition. */ | |
143 | ||
144 | struct __cxa_exception | |
145 | { | |
146 | void *exceptionType; | |
147 | void (*exceptionDestructor)(void *); | |
148 | ||
149 | void (*unexpectedHandler)(); | |
150 | void (*terminateHandler)(); | |
151 | ||
152 | struct __cxa_exception *nextException; | |
153 | ||
154 | int handlerCount; | |
155 | ||
156 | #ifdef __ARM_EABI_UNWINDER__ | |
157 | struct __cxa_exception* nextPropagatingException; | |
158 | ||
159 | int propagationCount; | |
160 | #else | |
161 | int handlerSwitchValue; | |
162 | const unsigned char *actionRecord; | |
163 | const unsigned char *languageSpecificData; | |
164 | _Unwind_Ptr catchTemp; | |
165 | void *adjustedPtr; | |
166 | #endif | |
167 | ||
168 | _Unwind_Exception unwindHeader; | |
169 | }; | |
170 | ||
982f26e4 AC |
171 | /* -------------------------------------------------------------- |
172 | -- The DB stuff below is there for debugging purposes only. -- | |
173 | -------------------------------------------------------------- */ | |
174 | ||
d7ffe14c AC |
175 | #ifndef inhibit_libc |
176 | ||
982f26e4 AC |
177 | #define DB_PHASES 0x1 |
178 | #define DB_CSITE 0x2 | |
179 | #define DB_ACTIONS 0x4 | |
180 | #define DB_REGIONS 0x8 | |
181 | ||
182 | #define DB_ERR 0x1000 | |
183 | ||
184 | /* The "action" stuff below is also there for debugging purposes only. */ | |
185 | ||
186 | typedef struct | |
187 | { | |
188 | _Unwind_Action phase; | |
b254da66 | 189 | const char * description; |
982f26e4 AC |
190 | } phase_descriptor; |
191 | ||
92db5dee | 192 | static const phase_descriptor phase_descriptors[] |
982f26e4 AC |
193 | = {{ _UA_SEARCH_PHASE, "SEARCH_PHASE" }, |
194 | { _UA_CLEANUP_PHASE, "CLEANUP_PHASE" }, | |
195 | { _UA_HANDLER_FRAME, "HANDLER_FRAME" }, | |
196 | { _UA_FORCE_UNWIND, "FORCE_UNWIND" }, | |
197 | { -1, 0}}; | |
198 | ||
199 | static int | |
200 | db_accepted_codes (void) | |
201 | { | |
202 | static int accepted_codes = -1; | |
203 | ||
204 | if (accepted_codes == -1) | |
205 | { | |
206 | char * db_env = (char *) getenv ("EH_DEBUG"); | |
207 | ||
208 | accepted_codes = db_env ? (atoi (db_env) | DB_ERR) : 0; | |
209 | /* Arranged for ERR stuff to always be visible when the variable | |
210 | is defined. One may just set the variable to 0 to see the ERR | |
211 | stuff only. */ | |
212 | } | |
213 | ||
214 | return accepted_codes; | |
215 | } | |
216 | ||
217 | #define DB_INDENT_INCREASE 0x01 | |
218 | #define DB_INDENT_DECREASE 0x02 | |
219 | #define DB_INDENT_OUTPUT 0x04 | |
220 | #define DB_INDENT_NEWLINE 0x08 | |
221 | #define DB_INDENT_RESET 0x10 | |
222 | ||
223 | #define DB_INDENT_UNIT 8 | |
224 | ||
225 | static void | |
226 | db_indent (int requests) | |
227 | { | |
228 | static int current_indentation_level = 0; | |
229 | ||
230 | if (requests & DB_INDENT_RESET) | |
31821c0f | 231 | current_indentation_level = 0; |
982f26e4 AC |
232 | |
233 | if (requests & DB_INDENT_INCREASE) | |
31821c0f | 234 | current_indentation_level ++; |
982f26e4 AC |
235 | |
236 | if (requests & DB_INDENT_DECREASE) | |
31821c0f | 237 | current_indentation_level --; |
982f26e4 AC |
238 | |
239 | if (requests & DB_INDENT_NEWLINE) | |
31821c0f | 240 | fprintf (stderr, "\n"); |
982f26e4 AC |
241 | |
242 | if (requests & DB_INDENT_OUTPUT) | |
31821c0f | 243 | fprintf (stderr, "%*s", current_indentation_level * DB_INDENT_UNIT, " "); |
982f26e4 AC |
244 | } |
245 | ||
246 | static void ATTRIBUTE_PRINTF_2 | |
6cbfce7e | 247 | db (int db_code, const char * msg_format, ...) |
982f26e4 AC |
248 | { |
249 | if (db_accepted_codes () & db_code) | |
250 | { | |
251 | va_list msg_args; | |
252 | ||
253 | db_indent (DB_INDENT_OUTPUT); | |
254 | ||
255 | va_start (msg_args, msg_format); | |
256 | vfprintf (stderr, msg_format, msg_args); | |
257 | va_end (msg_args); | |
258 | } | |
259 | } | |
260 | ||
261 | static void | |
262 | db_phases (int phases) | |
263 | { | |
c199ccf7 | 264 | const phase_descriptor *a = phase_descriptors; |
982f26e4 | 265 | |
51b0e05a | 266 | if (! (db_accepted_codes () & DB_PHASES)) |
982f26e4 AC |
267 | return; |
268 | ||
269 | db (DB_PHASES, "\n"); | |
270 | ||
271 | for (; a->description != 0; a++) | |
272 | if (phases & a->phase) | |
273 | db (DB_PHASES, "%s ", a->description); | |
274 | ||
275 | db (DB_PHASES, " :\n"); | |
276 | } | |
d7ffe14c AC |
277 | #else /* !inhibit_libc */ |
278 | #define db_phases(X) | |
279 | #define db_indent(X) | |
280 | #define db(X, ...) | |
281 | #endif /* !inhibit_libc */ | |
982f26e4 AC |
282 | |
283 | /* --------------------------------------------------------------- | |
284 | -- Now come a set of useful structures and helper routines. -- | |
285 | --------------------------------------------------------------- */ | |
286 | ||
287 | /* There are three major runtime tables involved, generated by the | |
288 | GCC back-end. Contents slightly vary depending on the underlying | |
289 | implementation scheme (dwarf zero cost / sjlj). | |
290 | ||
291 | ======================================= | |
292 | * Tables for the dwarf zero cost case * | |
293 | ======================================= | |
294 | ||
a2c1791d AC |
295 | They are fully documented in: |
296 | http://sourcery.mentor.com/public/cxx-abi/exceptions.pdf | |
297 | Here is a shorter presentation, with some specific comments for Ada. | |
298 | ||
982f26e4 AC |
299 | call_site [] |
300 | ------------------------------------------------------------------- | |
301 | * region-start | region-length | landing-pad | first-action-index * | |
302 | ------------------------------------------------------------------- | |
303 | ||
304 | Identify possible actions to be taken and where to resume control | |
305 | for that when an exception propagates through a pc inside the region | |
306 | delimited by start and length. | |
307 | ||
308 | A null landing-pad indicates that nothing is to be done. | |
309 | ||
310 | Otherwise, first-action-index provides an entry into the action[] | |
311 | table which heads a list of possible actions to be taken (see below). | |
312 | ||
313 | If it is determined that indeed an action should be taken, that | |
314 | is, if one action filter matches the exception being propagated, | |
d4aef883 | 315 | then control should be transferred to landing-pad. |
982f26e4 AC |
316 | |
317 | A null first-action-index indicates that there are only cleanups | |
318 | to run there. | |
319 | ||
320 | action [] | |
321 | ------------------------------- | |
322 | * action-filter | next-action * | |
323 | ------------------------------- | |
324 | ||
325 | This table contains lists (called action chains) of possible actions | |
326 | associated with call-site entries described in the call-site [] table. | |
31821c0f AC |
327 | There is at most one action list per call-site entry. It is SLEB128 |
328 | encoded. | |
982f26e4 AC |
329 | |
330 | A null action-filter indicates a cleanup. | |
331 | ||
332 | Non null action-filters provide an index into the ttypes [] table | |
333 | (see below), from which information may be retrieved to check if it | |
334 | matches the exception being propagated. | |
335 | ||
a2c1791d AC |
336 | * action-filter > 0: |
337 | means there is a regular handler to be run The value is also passed | |
338 | to the landing pad to dispatch the exception. | |
339 | ||
340 | * action-filter < 0: | |
341 | means there is a some "exception_specification" data to retrieve, | |
342 | which is only relevant for C++ and should never show up for Ada. | |
343 | (Exception specification specifies which exceptions can be thrown | |
344 | by a function. Such filter is emitted around the body of C++ | |
345 | functions defined like: | |
346 | void foo ([...]) throw (A, B) { [...] } | |
347 | These can be viewed as negativ filter: the landing pad is branched | |
348 | to for exceptions that doesn't match the filter and usually aborts | |
349 | the program). | |
350 | ||
351 | * next-action | |
352 | points to the next entry in the list using a relative byte offset. 0 | |
353 | indicates there is no other entry. | |
982f26e4 AC |
354 | |
355 | ttypes [] | |
356 | --------------- | |
357 | * ttype-value * | |
358 | --------------- | |
359 | ||
a2c1791d AC |
360 | This table is an array of addresses. |
361 | ||
31821c0f | 362 | A null value indicates a catch-all handler. (Not used by Ada) |
982f26e4 AC |
363 | |
364 | Non null values are used to match the exception being propagated: | |
365 | In C++ this is a pointer to some rtti data, while in Ada this is an | |
31821c0f | 366 | exception id (with a fake id for others). |
982f26e4 AC |
367 | |
368 | For C++, this table is actually also used to store "exception | |
369 | specification" data. The differentiation between the two kinds | |
370 | of entries is made by the sign of the associated action filter, | |
371 | which translates into positive or negative offsets from the | |
372 | so called base of the table: | |
373 | ||
374 | Exception Specification data is stored at positive offsets from | |
375 | the ttypes table base, which Exception Type data is stored at | |
376 | negative offsets: | |
377 | ||
378 | --------------------------------------------------------------------------- | |
379 | ||
380 | Here is a quick summary of the tables organization: | |
381 | ||
382 | +-- Unwind_Context (pc, ...) | |
383 | | | |
384 | |(pc) | |
385 | | | |
386 | | CALL-SITE[] | |
387 | | | |
388 | | +=============================================================+ | |
389 | | | region-start + length | landing-pad | first-action-index | | |
390 | | +=============================================================+ | |
391 | +-> | pc range 0 => no-action 0 => cleanups only | | |
392 | | !0 => jump @ N --+ | | |
393 | +====================================================== | ====+ | |
394 | | | |
395 | | | |
396 | ACTION [] | | |
397 | | | |
398 | +==========================================================+ | | |
399 | | action-filter | next-action | | | |
400 | +==========================================================+ | | |
401 | | 0 => cleanup | | | |
402 | | >0 => ttype index for handler ------+ 0 => end of chain | <-+ | |
403 | | <0 => ttype index for spec data | | | |
404 | +==================================== | ===================+ | |
405 | | | |
406 | | | |
407 | TTYPES [] | | |
408 | | Offset negated from | |
409 | +=====================+ | the actual base. | |
410 | | ttype-value | | | |
411 | +============+=====================+ | | |
31821c0f AC |
412 | | | ... | | |
413 | | ... | exception id | <---+ | |
414 | | | ... | | |
982f26e4 AC |
415 | | handlers +---------------------+ |
416 | | | ... | | |
417 | | ... | ... | | |
418 | | | ... | | |
419 | +============+=====================+ <<------ Table base | |
420 | | ... | ... | | |
421 | | specs | ... | (should not see negative filter | |
422 | | ... | ... | values for Ada). | |
423 | +============+=====================+ | |
424 | ||
425 | ||
426 | ============================ | |
427 | * Tables for the sjlj case * | |
428 | ============================ | |
429 | ||
430 | So called "function contexts" are pushed on a context stack by calls to | |
431 | _Unwind_SjLj_Register on function entry, and popped off at exit points by | |
432 | calls to _Unwind_SjLj_Unregister. The current call_site for a function is | |
433 | updated in the function context as the function's code runs along. | |
434 | ||
435 | The generic unwinding engine in _Unwind_RaiseException walks the function | |
436 | context stack and not the actual call chain. | |
437 | ||
438 | The ACTION and TTYPES tables remain unchanged, which allows to search them | |
276e95ca | 439 | during the propagation phase to determine whether or not the propagated |
982f26e4 AC |
440 | exception is handled somewhere. When it is, we only "jump" up once directly |
441 | to the context where the handler will be found. Besides, this allows "break | |
442 | exception unhandled" to work also | |
443 | ||
444 | The CALL-SITE table is setup differently, though: the pc attached to the | |
445 | unwind context is a direct index into the table, so the entries in this | |
446 | table do not hold region bounds any more. | |
447 | ||
448 | A special index (-1) is used to indicate that no action is possibly | |
449 | connected with the context at hand, so null landing pads cannot appear | |
450 | in the table. | |
451 | ||
452 | Additionally, landing pad values in the table do not represent code address | |
453 | to jump at, but so called "dispatch" indices used by a common landing pad | |
454 | for the function to switch to the appropriate post-landing-pad. | |
455 | ||
456 | +-- Unwind_Context (pc, ...) | |
457 | | | |
458 | | pc = call-site index | |
459 | | 0 => terminate (should not see this for Ada) | |
460 | | -1 => no-action | |
461 | | | |
462 | | CALL-SITE[] | |
463 | | | |
464 | | +=====================================+ | |
465 | | | landing-pad | first-action-index | | |
466 | | +=====================================+ | |
467 | +-> | 0 => cleanups only | | |
468 | | dispatch index N | | |
469 | +=====================================+ | |
470 | ||
471 | ||
472 | =================================== | |
473 | * Basic organization of this unit * | |
474 | =================================== | |
475 | ||
476 | The major point of this unit is to provide an exception propagation | |
bde8a146 | 477 | personality routine for Ada. This is __gnat_personality_v0. |
982f26e4 AC |
478 | |
479 | It is provided with a pointer to the propagated exception, an unwind | |
480 | context describing a location the propagation is going through, and a | |
481 | couple of other arguments including a description of the current | |
482 | propagation phase. | |
483 | ||
484 | It shall return to the generic propagation engine what is to be performed | |
485 | next, after possible context adjustments, depending on what it finds in the | |
486 | traversed context (a handler for the exception, a cleanup, nothing, ...), | |
487 | and on the propagation phase. | |
488 | ||
489 | A number of structures and subroutines are used for this purpose, as | |
490 | sketched below: | |
491 | ||
492 | o region_descriptor: General data associated with the context (base pc, | |
493 | call-site table, action table, ttypes table, ...) | |
494 | ||
495 | o action_descriptor: Data describing the action to be taken for the | |
496 | propagated exception in the provided context (kind of action: nothing, | |
497 | handler, cleanup; pointer to the action table entry, ...). | |
498 | ||
499 | raise | |
500 | | | |
501 | ... (a-except.adb) | |
502 | | | |
503 | Propagate_Exception (a-exexpr.adb) | |
504 | | | |
505 | | | |
506 | _Unwind_RaiseException (libgcc) | |
507 | | | |
508 | | (Ada frame) | |
509 | | | |
bde8a146 | 510 | +--> __gnat_personality_v0 (context, exception) |
982f26e4 | 511 | | |
8a0320ad | 512 | +--> get_region_description_for (context) |
982f26e4 | 513 | | |
2ed5b748 | 514 | +--> get_action_description_for (ip, exception, region) |
982f26e4 AC |
515 | | | |
516 | | +--> get_call_site_action_for (context, region) | |
517 | | (one version for each underlying scheme) | |
518 | | | |
519 | +--> setup_to_install (context) | |
520 | ||
521 | This unit is inspired from the C++ version found in eh_personality.cc, | |
522 | part of libstdc++-v3. | |
523 | ||
524 | */ | |
525 | ||
526 | ||
527 | /* This is an incomplete "proxy" of the structure of exception objects as | |
528 | built by the GNAT runtime library. Accesses to other fields than the common | |
529 | header are performed through subprogram calls to alleviate the need of an | |
530 | exact counterpart here and potential alignment/size issues for the common | |
531 | header. See a-exexpr.adb. */ | |
532 | ||
533 | typedef struct | |
534 | { | |
535 | _Unwind_Exception common; | |
536 | /* ABI header, maximally aligned. */ | |
537 | } _GNAT_Exception; | |
538 | ||
539 | /* The two constants below are specific ttype identifiers for special | |
540 | exception ids. Their type should match what a-exexpr exports. */ | |
541 | ||
542 | extern const int __gnat_others_value; | |
543 | #define GNAT_OTHERS ((_Unwind_Ptr) &__gnat_others_value) | |
544 | ||
545 | extern const int __gnat_all_others_value; | |
546 | #define GNAT_ALL_OTHERS ((_Unwind_Ptr) &__gnat_all_others_value) | |
547 | ||
21791d97 AC |
548 | extern const int __gnat_unhandled_others_value; |
549 | #define GNAT_UNHANDLED_OTHERS ((_Unwind_Ptr) &__gnat_unhandled_others_value) | |
550 | ||
982f26e4 AC |
551 | /* Describe the useful region data associated with an unwind context. */ |
552 | ||
553 | typedef struct | |
554 | { | |
555 | /* The base pc of the region. */ | |
556 | _Unwind_Ptr base; | |
557 | ||
558 | /* Pointer to the Language Specific Data for the region. */ | |
559 | _Unwind_Ptr lsda; | |
560 | ||
561 | /* Call-Site data associated with this region. */ | |
562 | unsigned char call_site_encoding; | |
563 | const unsigned char *call_site_table; | |
564 | ||
565 | /* The base to which are relative landing pad offsets inside the call-site | |
566 | entries . */ | |
567 | _Unwind_Ptr lp_base; | |
568 | ||
569 | /* Action-Table associated with this region. */ | |
570 | const unsigned char *action_table; | |
571 | ||
572 | /* Ttype data associated with this region. */ | |
573 | unsigned char ttype_encoding; | |
574 | const unsigned char *ttype_table; | |
575 | _Unwind_Ptr ttype_base; | |
576 | ||
577 | } region_descriptor; | |
578 | ||
b254da66 AC |
579 | /* Extract and adjust the IP (instruction pointer) from an exception |
580 | context. */ | |
581 | ||
582 | static _Unwind_Ptr | |
583 | get_ip_from_context (_Unwind_Context *uw_context) | |
982f26e4 | 584 | { |
df66d165 EB |
585 | int ip_before_insn = 0; |
586 | #ifdef HAVE_GETIPINFO | |
587 | _Unwind_Ptr ip = _Unwind_GetIPInfo (uw_context, &ip_before_insn); | |
588 | #else | |
589 | _Unwind_Ptr ip = _Unwind_GetIP (uw_context); | |
590 | #endif | |
b254da66 AC |
591 | /* Subtract 1 if necessary because GetIPInfo yields a call return address |
592 | in this case, while we are interested in information for the call point. | |
593 | This does not always yield the exact call instruction address but always | |
594 | brings the IP back within the corresponding region. */ | |
df66d165 EB |
595 | if (!ip_before_insn) |
596 | ip--; | |
982f26e4 | 597 | |
b254da66 AC |
598 | return ip; |
599 | } | |
600 | ||
601 | static void | |
2ed5b748 | 602 | db_region_for (region_descriptor *region, _Unwind_Ptr ip) |
b254da66 | 603 | { |
d7ffe14c | 604 | #ifndef inhibit_libc |
982f26e4 AC |
605 | if (! (db_accepted_codes () & DB_REGIONS)) |
606 | return; | |
607 | ||
799d0e05 | 608 | db (DB_REGIONS, "For ip @ %p => ", (void *)ip); |
982f26e4 AC |
609 | |
610 | if (region->lsda) | |
799d0e05 | 611 | db (DB_REGIONS, "lsda @ %p", (void *)region->lsda); |
982f26e4 AC |
612 | else |
613 | db (DB_REGIONS, "no lsda"); | |
614 | ||
615 | db (DB_REGIONS, "\n"); | |
d7ffe14c | 616 | #endif |
982f26e4 AC |
617 | } |
618 | ||
619 | /* Retrieve the ttype entry associated with FILTER in the REGION's | |
620 | ttype table. */ | |
621 | ||
799d0e05 | 622 | static _Unwind_Ptr |
982f26e4 AC |
623 | get_ttype_entry_for (region_descriptor *region, long filter) |
624 | { | |
625 | _Unwind_Ptr ttype_entry; | |
626 | ||
627 | filter *= size_of_encoded_value (region->ttype_encoding); | |
628 | read_encoded_value_with_base | |
629 | (region->ttype_encoding, region->ttype_base, | |
630 | region->ttype_table - filter, &ttype_entry); | |
631 | ||
632 | return ttype_entry; | |
633 | } | |
634 | ||
635 | /* Fill out the REGION descriptor for the provided UW_CONTEXT. */ | |
636 | ||
637 | static void | |
638 | get_region_description_for (_Unwind_Context *uw_context, | |
639 | region_descriptor *region) | |
640 | { | |
641 | const unsigned char * p; | |
0ab29e91 | 642 | _uleb128_t tmp; |
982f26e4 AC |
643 | unsigned char lpbase_encoding; |
644 | ||
645 | /* Get the base address of the lsda information. If the provided context | |
646 | is null or if there is no associated language specific data, there's | |
647 | nothing we can/should do. */ | |
648 | region->lsda | |
649 | = (_Unwind_Ptr) (uw_context | |
650 | ? _Unwind_GetLanguageSpecificData (uw_context) : 0); | |
651 | ||
652 | if (! region->lsda) | |
653 | return; | |
654 | ||
655 | /* Parse the lsda and fill the region descriptor. */ | |
799d0e05 | 656 | p = (const unsigned char *)region->lsda; |
982f26e4 AC |
657 | |
658 | region->base = _Unwind_GetRegionStart (uw_context); | |
659 | ||
660 | /* Find @LPStart, the base to which landing pad offsets are relative. */ | |
661 | lpbase_encoding = *p++; | |
662 | if (lpbase_encoding != DW_EH_PE_omit) | |
663 | p = read_encoded_value | |
664 | (uw_context, lpbase_encoding, p, ®ion->lp_base); | |
665 | else | |
666 | region->lp_base = region->base; | |
667 | ||
668 | /* Find @TType, the base of the handler and exception spec type data. */ | |
669 | region->ttype_encoding = *p++; | |
670 | if (region->ttype_encoding != DW_EH_PE_omit) | |
671 | { | |
672 | p = read_uleb128 (p, &tmp); | |
673 | region->ttype_table = p + tmp; | |
674 | } | |
675 | else | |
676 | region->ttype_table = 0; | |
677 | ||
678 | region->ttype_base | |
679 | = base_of_encoded_value (region->ttype_encoding, uw_context); | |
680 | ||
681 | /* Get the encoding and length of the call-site table; the action table | |
682 | immediately follows. */ | |
683 | region->call_site_encoding = *p++; | |
684 | region->call_site_table = read_uleb128 (p, &tmp); | |
685 | ||
686 | region->action_table = region->call_site_table + tmp; | |
687 | } | |
688 | ||
689 | ||
690 | /* Describe an action to be taken when propagating an exception up to | |
691 | some context. */ | |
692 | ||
2ed5b748 | 693 | enum action_kind |
982f26e4 AC |
694 | { |
695 | /* Found some call site base data, but need to analyze further | |
696 | before being able to decide. */ | |
697 | unknown, | |
698 | ||
699 | /* There is nothing relevant in the context at hand. */ | |
700 | nothing, | |
701 | ||
702 | /* There are only cleanups to run in this context. */ | |
703 | cleanup, | |
704 | ||
705 | /* There is a handler for the exception in this context. */ | |
2ed5b748 AC |
706 | handler, |
707 | ||
708 | /* There is a handler for the exception, but it is only for catching | |
709 | unhandled exceptions. */ | |
710 | unhandler | |
711 | }; | |
982f26e4 AC |
712 | |
713 | /* filter value for cleanup actions. */ | |
92db5dee | 714 | static const int cleanup_filter = 0; |
982f26e4 AC |
715 | |
716 | typedef struct | |
717 | { | |
718 | /* The kind of action to be taken. */ | |
2ed5b748 | 719 | enum action_kind kind; |
982f26e4 AC |
720 | |
721 | /* A pointer to the action record entry. */ | |
722 | const unsigned char *table_entry; | |
723 | ||
724 | /* Where we should jump to actually take an action (trigger a cleanup or an | |
725 | exception handler). */ | |
726 | _Unwind_Ptr landing_pad; | |
727 | ||
728 | /* If we have a handler matching our exception, these are the filter to | |
729 | trigger it and the corresponding id. */ | |
730 | _Unwind_Sword ttype_filter; | |
982f26e4 AC |
731 | |
732 | } action_descriptor; | |
733 | ||
734 | static void | |
2ed5b748 | 735 | db_action_for (action_descriptor *action, _Unwind_Ptr ip) |
982f26e4 | 736 | { |
d7ffe14c | 737 | #ifndef inhibit_libc |
799d0e05 | 738 | db (DB_ACTIONS, "For ip @ %p => ", (void *)ip); |
982f26e4 AC |
739 | |
740 | switch (action->kind) | |
741 | { | |
742 | case unknown: | |
799d0e05 AC |
743 | db (DB_ACTIONS, "lpad @ %p, record @ %p\n", |
744 | (void *) action->landing_pad, action->table_entry); | |
982f26e4 AC |
745 | break; |
746 | ||
747 | case nothing: | |
748 | db (DB_ACTIONS, "Nothing\n"); | |
749 | break; | |
750 | ||
751 | case cleanup: | |
752 | db (DB_ACTIONS, "Cleanup\n"); | |
753 | break; | |
754 | ||
755 | case handler: | |
799d0e05 | 756 | db (DB_ACTIONS, "Handler, filter = %d\n", (int) action->ttype_filter); |
982f26e4 AC |
757 | break; |
758 | ||
759 | default: | |
760 | db (DB_ACTIONS, "Err? Unexpected action kind !\n"); | |
761 | break; | |
762 | } | |
d7ffe14c | 763 | #endif |
982f26e4 AC |
764 | } |
765 | ||
982f26e4 | 766 | /* Search the call_site_table of REGION for an entry appropriate for the |
9299a27c AC |
767 | UW_CONTEXT's IP. If one is found, store the associated landing_pad |
768 | and action_table entry, and set the ACTION kind to unknown for further | |
769 | analysis. Otherwise, set the ACTION kind to nothing. | |
982f26e4 AC |
770 | |
771 | There are two variants of this routine, depending on the underlying | |
9299a27c | 772 | mechanism (DWARF/SJLJ), which account for differences in the tables. */ |
982f26e4 AC |
773 | |
774 | #ifdef __USING_SJLJ_EXCEPTIONS__ | |
775 | ||
776 | #define __builtin_eh_return_data_regno(x) x | |
777 | ||
778 | static void | |
2ed5b748 | 779 | get_call_site_action_for (_Unwind_Ptr call_site, |
982f26e4 AC |
780 | region_descriptor *region, |
781 | action_descriptor *action) | |
782 | { | |
982f26e4 | 783 | /* call_site is a direct index into the call-site table, with two special |
9299a27c AC |
784 | values : -1 for no-action and 0 for "terminate". The latter should never |
785 | show up for Ada. To test for the former, beware that _Unwind_Ptr might | |
786 | be unsigned. */ | |
982f26e4 AC |
787 | |
788 | if ((int)call_site < 0) | |
789 | { | |
790 | action->kind = nothing; | |
982f26e4 AC |
791 | } |
792 | else if (call_site == 0) | |
793 | { | |
794 | db (DB_ERR, "========> Err, null call_site for Ada/sjlj\n"); | |
795 | action->kind = nothing; | |
982f26e4 AC |
796 | } |
797 | else | |
798 | { | |
0ab29e91 | 799 | _uleb128_t cs_lp, cs_action; |
24cb156d | 800 | const unsigned char *p; |
982f26e4 AC |
801 | |
802 | /* Let the caller know there may be an action to take, but let it | |
803 | determine the kind. */ | |
804 | action->kind = unknown; | |
805 | ||
806 | /* We have a direct index into the call-site table, but this table is | |
9299a27c | 807 | made of leb128 values, the encoding length of which is variable. We |
982f26e4 AC |
808 | can't merely compute an offset from the index, then, but have to read |
809 | all the entries before the one of interest. */ | |
2ed5b748 AC |
810 | p = region->call_site_table; |
811 | do | |
812 | { | |
813 | p = read_uleb128 (p, &cs_lp); | |
814 | p = read_uleb128 (p, &cs_action); | |
815 | } | |
816 | while (--call_site); | |
982f26e4 | 817 | |
982f26e4 AC |
818 | action->landing_pad = cs_lp + 1; |
819 | ||
820 | if (cs_action) | |
821 | action->table_entry = region->action_table + cs_action - 1; | |
822 | else | |
823 | action->table_entry = 0; | |
982f26e4 AC |
824 | } |
825 | } | |
826 | ||
9299a27c | 827 | #else /* !__USING_SJLJ_EXCEPTIONS__ */ |
982f26e4 AC |
828 | |
829 | static void | |
2ed5b748 | 830 | get_call_site_action_for (_Unwind_Ptr ip, |
982f26e4 AC |
831 | region_descriptor *region, |
832 | action_descriptor *action) | |
833 | { | |
9299a27c | 834 | const unsigned char *p = region->call_site_table; |
982f26e4 | 835 | |
9299a27c | 836 | /* Unless we are able to determine otherwise... */ |
982f26e4 AC |
837 | action->kind = nothing; |
838 | ||
839 | db (DB_CSITE, "\n"); | |
840 | ||
841 | while (p < region->action_table) | |
842 | { | |
843 | _Unwind_Ptr cs_start, cs_len, cs_lp; | |
0ab29e91 | 844 | _uleb128_t cs_action; |
982f26e4 AC |
845 | |
846 | /* Note that all call-site encodings are "absolute" displacements. */ | |
847 | p = read_encoded_value (0, region->call_site_encoding, p, &cs_start); | |
848 | p = read_encoded_value (0, region->call_site_encoding, p, &cs_len); | |
849 | p = read_encoded_value (0, region->call_site_encoding, p, &cs_lp); | |
850 | p = read_uleb128 (p, &cs_action); | |
851 | ||
852 | db (DB_CSITE, | |
799d0e05 | 853 | "c_site @ %p (+%p), len = %p, lpad @ %p (+%p)\n", |
6cbfce7e AC |
854 | (char *)region->base + cs_start, (void *)cs_start, (void *)cs_len, |
855 | (char *)region->lp_base + cs_lp, (void *)cs_lp); | |
982f26e4 | 856 | |
9299a27c | 857 | /* The table is sorted, so if we've passed the IP, stop. */ |
982f26e4 AC |
858 | if (ip < region->base + cs_start) |
859 | break; | |
860 | ||
861 | /* If we have a match, fill the ACTION fields accordingly. */ | |
862 | else if (ip < region->base + cs_start + cs_len) | |
863 | { | |
864 | /* Let the caller know there may be an action to take, but let it | |
865 | determine the kind. */ | |
866 | action->kind = unknown; | |
867 | ||
868 | if (cs_lp) | |
869 | action->landing_pad = region->lp_base + cs_lp; | |
870 | else | |
871 | action->landing_pad = 0; | |
872 | ||
873 | if (cs_action) | |
874 | action->table_entry = region->action_table + cs_action - 1; | |
875 | else | |
876 | action->table_entry = 0; | |
877 | ||
878 | db (DB_CSITE, "+++\n"); | |
879 | return; | |
880 | } | |
881 | } | |
882 | ||
883 | db (DB_CSITE, "---\n"); | |
884 | } | |
885 | ||
9299a27c | 886 | #endif /* __USING_SJLJ_EXCEPTIONS__ */ |
982f26e4 AC |
887 | |
888 | /* With CHOICE an exception choice representing an "exception - when" | |
889 | argument, and PROPAGATED_EXCEPTION a pointer to the currently propagated | |
276e95ca | 890 | occurrence, return true if the latter matches the former, that is, if |
982f26e4 | 891 | PROPAGATED_EXCEPTION is caught by the handling code controlled by CHOICE. |
f48a35ca | 892 | */ |
982f26e4 AC |
893 | |
894 | #define Is_Handled_By_Others __gnat_is_handled_by_others | |
895 | #define Language_For __gnat_language_for | |
e443f142 | 896 | #define Foreign_Data_For __gnat_foreign_data_for |
982f26e4 | 897 | #define EID_For __gnat_eid_for |
982f26e4 AC |
898 | |
899 | extern bool Is_Handled_By_Others (_Unwind_Ptr eid); | |
900 | extern char Language_For (_Unwind_Ptr eid); | |
901 | ||
e443f142 | 902 | extern void *Foreign_Data_For (_Unwind_Ptr eid); |
982f26e4 AC |
903 | |
904 | extern Exception_Id EID_For (_GNAT_Exception * e); | |
982f26e4 | 905 | |
e443f142 TG |
906 | #define Foreign_Exception system__exceptions__foreign_exception |
907 | extern struct Exception_Data Foreign_Exception; | |
908 | ||
51b0e05a AC |
909 | /* Return true iff the exception class of EXCEPT is EC. */ |
910 | ||
911 | static int | |
a997fff5 BE |
912 | exception_class_eq (const _GNAT_Exception *except, |
913 | const _Unwind_Exception_Class ec) | |
51b0e05a AC |
914 | { |
915 | #ifdef __ARM_EABI_UNWINDER__ | |
158d55fa | 916 | return memcmp (except->common.exception_class, ec, 8) == 0; |
51b0e05a AC |
917 | #else |
918 | return except->common.exception_class == ec; | |
919 | #endif | |
920 | } | |
921 | ||
800da977 AC |
922 | /* Return how CHOICE matches PROPAGATED_EXCEPTION. */ |
923 | ||
2ed5b748 | 924 | static enum action_kind |
51b0e05a | 925 | is_handled_by (_Unwind_Ptr choice, _GNAT_Exception *propagated_exception) |
982f26e4 | 926 | { |
e443f142 | 927 | /* All others choice match everything. */ |
2ed5b748 AC |
928 | if (choice == GNAT_ALL_OTHERS) |
929 | return handler; | |
930 | ||
e443f142 | 931 | /* GNAT exception occurrence. */ |
51b0e05a | 932 | if (exception_class_eq (propagated_exception, GNAT_EXCEPTION_CLASS)) |
5accd7b6 AC |
933 | { |
934 | /* Pointer to the GNAT exception data corresponding to the propagated | |
935 | occurrence. */ | |
936 | _Unwind_Ptr E = (_Unwind_Ptr) EID_For (propagated_exception); | |
937 | ||
2ed5b748 AC |
938 | if (choice == GNAT_UNHANDLED_OTHERS) |
939 | return unhandler; | |
940 | ||
941 | E = (_Unwind_Ptr) EID_For (propagated_exception); | |
942 | ||
5accd7b6 AC |
943 | /* Base matching rules: An exception data (id) matches itself, "when |
944 | all_others" matches anything and "when others" matches anything | |
945 | unless explicitly stated otherwise in the propagated occurrence. */ | |
2ed5b748 AC |
946 | if (choice == E || (choice == GNAT_OTHERS && Is_Handled_By_Others (E))) |
947 | return handler; | |
5accd7b6 | 948 | |
e443f142 TG |
949 | /* Otherwise, it doesn't match an Ada choice. */ |
950 | return nothing; | |
5accd7b6 | 951 | } |
e443f142 TG |
952 | |
953 | /* All others and others choice match any foreign exception. */ | |
954 | if (choice == GNAT_ALL_OTHERS | |
955 | || choice == GNAT_OTHERS | |
60aa5228 AC |
956 | #ifndef CERT |
957 | || choice == (_Unwind_Ptr) &Foreign_Exception | |
958 | #endif | |
959 | ) | |
e443f142 TG |
960 | return handler; |
961 | ||
60aa5228 | 962 | #ifndef CERT |
5644b7e8 | 963 | /* C++ exception occurrences. */ |
51b0e05a | 964 | if (exception_class_eq (propagated_exception, CXX_EXCEPTION_CLASS) |
5644b7e8 AC |
965 | && Language_For (choice) == 'C') |
966 | { | |
967 | void *choice_typeinfo = Foreign_Data_For (choice); | |
968 | void *except_typeinfo = | |
969 | (((struct __cxa_exception *) | |
800da977 AC |
970 | ((_Unwind_Exception *)propagated_exception + 1)) - 1) |
971 | ->exceptionType; | |
5644b7e8 AC |
972 | |
973 | /* Typeinfo are directly compared, which might not be correct if they | |
974 | aren't merged. ??? We should call the == operator if this module is | |
975 | compiled in C++. */ | |
976 | if (choice_typeinfo == except_typeinfo) | |
977 | return handler; | |
978 | } | |
60aa5228 | 979 | #endif |
5644b7e8 | 980 | |
2ed5b748 | 981 | return nothing; |
982f26e4 AC |
982 | } |
983 | ||
984 | /* Fill out the ACTION to be taken from propagating UW_EXCEPTION up to | |
985 | UW_CONTEXT in REGION. */ | |
986 | ||
987 | static void | |
2ed5b748 | 988 | get_action_description_for (_Unwind_Ptr ip, |
982f26e4 | 989 | _Unwind_Exception *uw_exception, |
c199ccf7 | 990 | _Unwind_Action uw_phase, |
982f26e4 AC |
991 | region_descriptor *region, |
992 | action_descriptor *action) | |
993 | { | |
2ed5b748 | 994 | _GNAT_Exception *gnat_exception = (_GNAT_Exception *) uw_exception; |
982f26e4 AC |
995 | |
996 | /* Search the call site table first, which may get us a landing pad as well | |
997 | as the head of an action record list. */ | |
2ed5b748 AC |
998 | get_call_site_action_for (ip, region, action); |
999 | db_action_for (action, ip); | |
982f26e4 AC |
1000 | |
1001 | /* If there is not even a call_site entry, we are done. */ | |
1002 | if (action->kind == nothing) | |
1003 | return; | |
1004 | ||
1005 | /* Otherwise, check what we have at the place of the call site. */ | |
1006 | ||
1007 | /* No landing pad => no cleanups or handlers. */ | |
1008 | if (action->landing_pad == 0) | |
1009 | { | |
1010 | action->kind = nothing; | |
1011 | return; | |
1012 | } | |
1013 | ||
1014 | /* Landing pad + null table entry => only cleanups. */ | |
1015 | else if (action->table_entry == 0) | |
1016 | { | |
1017 | action->kind = cleanup; | |
1018 | action->ttype_filter = cleanup_filter; | |
1019 | /* The filter initialization is not strictly necessary, as cleanup-only | |
1020 | landing pads don't look at the filter value. It is there to ensure | |
1021 | we don't pass random values and so trigger potential confusion when | |
1022 | installing the context later on. */ | |
1023 | return; | |
1024 | } | |
1025 | ||
1026 | /* Landing pad + Table entry => handlers + possible cleanups. */ | |
1027 | else | |
1028 | { | |
1029 | const unsigned char * p = action->table_entry; | |
0ab29e91 | 1030 | _sleb128_t ar_filter, ar_disp; |
982f26e4 AC |
1031 | |
1032 | action->kind = nothing; | |
1033 | ||
1034 | while (1) | |
1035 | { | |
1036 | p = read_sleb128 (p, &ar_filter); | |
1037 | read_sleb128 (p, &ar_disp); | |
1038 | /* Don't assign p here, as it will be incremented by ar_disp | |
1039 | below. */ | |
1040 | ||
1041 | /* Null filters are for cleanups. */ | |
1042 | if (ar_filter == cleanup_filter) | |
1043 | { | |
1044 | action->kind = cleanup; | |
1045 | action->ttype_filter = cleanup_filter; | |
1046 | /* The filter initialization is required here, to ensure | |
1047 | the target landing pad branches to the cleanup code if | |
1048 | we happen not to find a matching handler. */ | |
1049 | } | |
1050 | ||
1051 | /* Positive filters are for regular handlers. */ | |
1052 | else if (ar_filter > 0) | |
1053 | { | |
c199ccf7 AC |
1054 | /* Do not catch an exception if the _UA_FORCE_UNWIND flag is |
1055 | passed (to follow the ABI). */ | |
1056 | if (!(uw_phase & _UA_FORCE_UNWIND)) | |
1057 | { | |
24cb156d AC |
1058 | enum action_kind act; |
1059 | ||
c199ccf7 AC |
1060 | /* See if the filter we have is for an exception which |
1061 | matches the one we are propagating. */ | |
800da977 AC |
1062 | _Unwind_Ptr choice = |
1063 | get_ttype_entry_for (region, ar_filter); | |
c199ccf7 | 1064 | |
24cb156d AC |
1065 | act = is_handled_by (choice, gnat_exception); |
1066 | if (act != nothing) | |
c199ccf7 | 1067 | { |
24cb156d | 1068 | action->kind = act; |
c199ccf7 | 1069 | action->ttype_filter = ar_filter; |
c199ccf7 AC |
1070 | return; |
1071 | } | |
1072 | } | |
982f26e4 AC |
1073 | } |
1074 | ||
1075 | /* Negative filter values are for C++ exception specifications. | |
1076 | Should not be there for Ada :/ */ | |
1077 | else | |
1078 | db (DB_ERR, "========> Err, filter < 0 for Ada/dwarf\n"); | |
1079 | ||
1080 | if (ar_disp == 0) | |
1081 | return; | |
1082 | ||
1083 | p += ar_disp; | |
1084 | } | |
1085 | } | |
1086 | } | |
1087 | ||
1088 | /* Setup in UW_CONTEXT the eh return target IP and data registers, which will | |
1089 | be restored with the others and retrieved by the landing pad once the jump | |
1090 | occurred. */ | |
1091 | ||
1092 | static void | |
1093 | setup_to_install (_Unwind_Context *uw_context, | |
1094 | _Unwind_Exception *uw_exception, | |
1095 | _Unwind_Ptr uw_landing_pad, | |
1096 | int uw_filter) | |
1097 | { | |
982f26e4 AC |
1098 | /* 1/ exception object pointer, which might be provided back to |
1099 | _Unwind_Resume (and thus to this personality routine) if we are jumping | |
1100 | to a cleanup. */ | |
1101 | _Unwind_SetGR (uw_context, __builtin_eh_return_data_regno (0), | |
1102 | (_Unwind_Word)uw_exception); | |
1103 | ||
1104 | /* 2/ handler switch value register, which will also be used by the target | |
1105 | landing pad to decide what action it shall take. */ | |
1106 | _Unwind_SetGR (uw_context, __builtin_eh_return_data_regno (1), | |
1107 | (_Unwind_Word)uw_filter); | |
1108 | ||
1109 | /* Setup the address we should jump at to reach the code where there is the | |
1110 | "something" we found. */ | |
1111 | _Unwind_SetIP (uw_context, uw_landing_pad); | |
982f26e4 AC |
1112 | } |
1113 | ||
1114 | /* The following is defined from a-except.adb. Its purpose is to enable | |
1115 | automatic backtraces upon exception raise, as provided through the | |
1116 | GNAT.Traceback facilities. */ | |
5df1266a AC |
1117 | extern void __gnat_notify_handled_exception (struct Exception_Occurrence *); |
1118 | extern void __gnat_notify_unhandled_exception (struct Exception_Occurrence *); | |
982f26e4 AC |
1119 | |
1120 | /* Below is the eh personality routine per se. We currently assume that only | |
1121 | GNU-Ada exceptions are met. */ | |
1122 | ||
51b0e05a AC |
1123 | /* By default, the personality routine is public. */ |
1124 | #define PERSONALITY_STORAGE | |
1125 | ||
3355aa3e | 1126 | #ifdef __USING_SJLJ_EXCEPTIONS__ |
bde8a146 | 1127 | #define PERSONALITY_FUNCTION __gnat_personality_sj0 |
4a8043c4 | 1128 | #elif defined (__SEH__) |
758ad973 | 1129 | #define PERSONALITY_FUNCTION __gnat_personality_imp |
51b0e05a AC |
1130 | /* The public personality routine for seh is __gnat_personality_seh0, defined |
1131 | below using the SEH convention. This is a wrapper around the GNU routine, | |
1132 | which is static. */ | |
1133 | #undef PERSONALITY_STORAGE | |
1134 | #define PERSONALITY_STORAGE static | |
3355aa3e | 1135 | #else |
bde8a146 | 1136 | #define PERSONALITY_FUNCTION __gnat_personality_v0 |
3355aa3e OH |
1137 | #endif |
1138 | ||
0f7e4fe2 RR |
1139 | #if defined (__ARM_EABI_UNWINDER__) \ |
1140 | && (defined (IN_RTS) || GCC_VERSION > 9000) | |
1141 | #define TARGET_ATTRIBUTE __attribute__((target ("general-regs-only"))) | |
1142 | #else | |
1143 | #define TARGET_ATTRIBUTE | |
1144 | #endif | |
1145 | ||
51b0e05a | 1146 | /* Code executed to continue unwinding. With the ARM unwinder, the |
800da977 | 1147 | personality routine must unwind one frame (per EHABI 7.3 4.). */ |
51b0e05a AC |
1148 | |
1149 | static _Unwind_Reason_Code | |
0f7e4fe2 | 1150 | TARGET_ATTRIBUTE |
a905304c AC |
1151 | continue_unwind (struct _Unwind_Exception* ue_header ATTRIBUTE_UNUSED, |
1152 | struct _Unwind_Context* uw_context ATTRIBUTE_UNUSED) | |
51b0e05a AC |
1153 | { |
1154 | #ifdef __ARM_EABI_UNWINDER__ | |
1155 | if (__gnu_unwind_frame (ue_header, uw_context) != _URC_OK) | |
1156 | return _URC_FAILURE; | |
1157 | #endif | |
1158 | return _URC_CONTINUE_UNWIND; | |
1159 | } | |
1160 | ||
1161 | /* Common code for the body of GNAT personality routine. This code is shared | |
1162 | between all unwinders. */ | |
1163 | ||
1164 | static _Unwind_Reason_Code | |
0f7e4fe2 | 1165 | TARGET_ATTRIBUTE |
51b0e05a AC |
1166 | personality_body (_Unwind_Action uw_phases, |
1167 | _Unwind_Exception *uw_exception, | |
1168 | _Unwind_Context *uw_context) | |
1169 | { | |
1170 | region_descriptor region; | |
1171 | action_descriptor action; | |
1172 | _Unwind_Ptr ip; | |
1173 | ||
1174 | /* Debug traces. */ | |
1175 | db_indent (DB_INDENT_RESET); | |
1176 | db_phases (uw_phases); | |
1177 | db_indent (DB_INDENT_INCREASE); | |
1178 | ||
1179 | /* Get the region description for the context we were provided with. This | |
1180 | will tell us if there is some lsda, call_site, action and/or ttype data | |
1181 | for the associated ip. */ | |
1182 | get_region_description_for (uw_context, ®ion); | |
1183 | ||
1184 | /* No LSDA => no handlers or cleanups => we shall unwind further up. */ | |
1185 | if (! region.lsda) | |
1186 | return continue_unwind (uw_exception, uw_context); | |
1187 | ||
1188 | /* Get the instruction pointer. */ | |
1189 | ip = get_ip_from_context (uw_context); | |
1190 | db_region_for (®ion, ip); | |
1191 | ||
1192 | /* Search the call-site and action-record tables for the action associated | |
1193 | with this IP. */ | |
1194 | get_action_description_for (ip, uw_exception, uw_phases, ®ion, &action); | |
1195 | db_action_for (&action, ip); | |
1196 | ||
1197 | /* Whatever the phase, if there is nothing relevant in this frame, | |
1198 | unwinding should just go on. */ | |
1199 | if (action.kind == nothing) | |
1200 | return continue_unwind (uw_exception, uw_context); | |
1201 | ||
1202 | /* If we found something in search phase, we should return a code indicating | |
1203 | what to do next depending on what we found. If we only have cleanups | |
1204 | around, we shall try to unwind further up to find a handler, otherwise, | |
1205 | tell we have a handler, which will trigger the second phase. */ | |
1206 | if (uw_phases & _UA_SEARCH_PHASE) | |
1207 | { | |
1208 | if (action.kind == cleanup) | |
1209 | { | |
1210 | return continue_unwind (uw_exception, uw_context); | |
1211 | } | |
1212 | else | |
1213 | { | |
006eeaa8 AO |
1214 | #ifdef __ARM_EABI_UNWINDER__ |
1215 | /* Though we do not use this field ourselves, initializing | |
1216 | it is required by the ARM EH ABI before a personality | |
1217 | function in phase1 returns _URC_HANDLER_FOUND, so that | |
1218 | any personality function can use it in phase2 to test | |
1219 | whether the handler frame was reached. */ | |
1220 | uw_exception->barrier_cache.sp | |
1221 | = _Unwind_GetGR (uw_context, UNWIND_STACK_REG); | |
1222 | #endif | |
1223 | ||
60aa5228 | 1224 | #ifndef CERT |
51b0e05a | 1225 | /* Trigger the appropriate notification routines before the second |
557b744a OH |
1226 | phase starts, when the stack is still intact. First install what |
1227 | needs to be installed in the current exception buffer and fetch | |
1228 | the Ada occurrence pointer to use. */ | |
1229 | ||
1230 | struct Exception_Occurrence *excep | |
1231 | = __gnat_setup_current_excep (uw_exception, uw_phases); | |
1232 | ||
51b0e05a AC |
1233 | if (action.kind == unhandler) |
1234 | __gnat_notify_unhandled_exception (excep); | |
1235 | else | |
1236 | __gnat_notify_handled_exception (excep); | |
60aa5228 | 1237 | #endif |
51b0e05a AC |
1238 | |
1239 | return _URC_HANDLER_FOUND; | |
1240 | } | |
1241 | } | |
1242 | ||
1243 | /* We found something in cleanup/handler phase, which might be the handler | |
1244 | or a cleanup for a handled occurrence, or a cleanup for an unhandled | |
1245 | occurrence (we are in a FORCED_UNWIND phase in this case). Install the | |
1246 | context to get there. */ | |
1247 | ||
1248 | setup_to_install | |
1249 | (uw_context, uw_exception, action.landing_pad, action.ttype_filter); | |
1250 | ||
60aa5228 | 1251 | #ifndef CERT |
557b744a OH |
1252 | /* Write current exception so that it can be retrieved from Ada. It was |
1253 | already done during phase 1, but one or several exceptions may have been | |
1254 | raised in cleanup handlers in between. */ | |
1255 | __gnat_setup_current_excep (uw_exception, uw_phases); | |
60aa5228 | 1256 | #endif |
51b0e05a AC |
1257 | |
1258 | return _URC_INSTALL_CONTEXT; | |
1259 | } | |
1260 | ||
1261 | #ifndef __ARM_EABI_UNWINDER__ | |
2e603994 OH |
1262 | typedef int version_arg_t; |
1263 | typedef _Unwind_Action phases_arg_t; | |
2e603994 | 1264 | |
51b0e05a | 1265 | PERSONALITY_STORAGE _Unwind_Reason_Code |
2438d7a6 KT |
1266 | PERSONALITY_FUNCTION (version_arg_t, phases_arg_t, |
1267 | _Unwind_Exception_Class, _Unwind_Exception *, | |
1268 | _Unwind_Context *); | |
1269 | ||
51b0e05a | 1270 | PERSONALITY_STORAGE _Unwind_Reason_Code |
3355aa3e OH |
1271 | PERSONALITY_FUNCTION (version_arg_t version_arg, |
1272 | phases_arg_t phases_arg, | |
799d0e05 AC |
1273 | _Unwind_Exception_Class uw_exception_class |
1274 | ATTRIBUTE_UNUSED, | |
3355aa3e OH |
1275 | _Unwind_Exception *uw_exception, |
1276 | _Unwind_Context *uw_context) | |
982f26e4 | 1277 | { |
2e603994 OH |
1278 | /* Fetch the version and phases args with their nominal ABI types for later |
1279 | use. This is a noop everywhere except on ia64-vms when called from the | |
1280 | Condition Handling Facility. */ | |
1281 | int uw_version = (int) version_arg; | |
1282 | _Unwind_Action uw_phases = (_Unwind_Action) phases_arg; | |
982f26e4 | 1283 | |
f48a35ca | 1284 | /* Check that we're called from the ABI context we expect. */ |
982f26e4 | 1285 | if (uw_version != 1) |
f48a35ca | 1286 | return _URC_FATAL_PHASE1_ERROR; |
982f26e4 | 1287 | |
51b0e05a AC |
1288 | return personality_body (uw_phases, uw_exception, uw_context); |
1289 | } | |
982f26e4 | 1290 | |
51b0e05a | 1291 | #else /* __ARM_EABI_UNWINDER__ */ |
982f26e4 | 1292 | |
51b0e05a AC |
1293 | PERSONALITY_STORAGE _Unwind_Reason_Code |
1294 | PERSONALITY_FUNCTION (_Unwind_State state, | |
1295 | struct _Unwind_Exception* ue_header, | |
1296 | struct _Unwind_Context* uw_context); | |
982f26e4 | 1297 | |
51b0e05a | 1298 | PERSONALITY_STORAGE _Unwind_Reason_Code |
0f7e4fe2 | 1299 | TARGET_ATTRIBUTE |
51b0e05a AC |
1300 | PERSONALITY_FUNCTION (_Unwind_State state, |
1301 | struct _Unwind_Exception* uw_exception, | |
1302 | struct _Unwind_Context* uw_context) | |
1303 | { | |
1304 | _Unwind_Action uw_phases; | |
982f26e4 | 1305 | |
51b0e05a | 1306 | switch (state & _US_ACTION_MASK) |
982f26e4 | 1307 | { |
51b0e05a AC |
1308 | case _US_VIRTUAL_UNWIND_FRAME: |
1309 | /* Phase 1. */ | |
1310 | uw_phases = _UA_SEARCH_PHASE; | |
1311 | break; | |
1312 | ||
1313 | case _US_UNWIND_FRAME_STARTING: | |
800da977 | 1314 | /* Phase 2, to call a cleanup. */ |
51b0e05a | 1315 | uw_phases = _UA_CLEANUP_PHASE; |
800da977 AC |
1316 | #if 0 |
1317 | /* ??? We don't use UA_HANDLER_FRAME (except to debug). Futhermore, | |
1318 | barrier_cache.sp isn't yet set. */ | |
51b0e05a AC |
1319 | if (!(state & _US_FORCE_UNWIND) |
1320 | && (uw_exception->barrier_cache.sp | |
1321 | == _Unwind_GetGR (uw_context, UNWIND_STACK_REG))) | |
1322 | uw_phases |= _UA_HANDLER_FRAME; | |
800da977 | 1323 | #endif |
51b0e05a AC |
1324 | break; |
1325 | ||
1326 | case _US_UNWIND_FRAME_RESUME: | |
800da977 AC |
1327 | /* Phase 2, called at the return of a cleanup. In the GNU |
1328 | implementation, there is nothing left to do, so we simply go on. */ | |
51b0e05a AC |
1329 | return continue_unwind (uw_exception, uw_context); |
1330 | ||
1331 | default: | |
1332 | return _URC_FAILURE; | |
982f26e4 | 1333 | } |
51b0e05a | 1334 | uw_phases |= (state & _US_FORCE_UNWIND); |
982f26e4 | 1335 | |
51b0e05a AC |
1336 | /* The dwarf unwinder assumes the context structure holds things like the |
1337 | function and LSDA pointers. The ARM implementation caches these in | |
1338 | the exception header (UCB). To avoid rewriting everything we make a | |
1339 | virtual scratch register point at the UCB. This is a GNU specific | |
1340 | requirement. */ | |
1341 | _Unwind_SetGR (uw_context, UNWIND_POINTER_REG, (_Unwind_Ptr) uw_exception); | |
982f26e4 | 1342 | |
51b0e05a | 1343 | return personality_body (uw_phases, uw_exception, uw_context); |
982f26e4 | 1344 | } |
51b0e05a | 1345 | #endif /* __ARM_EABI_UNWINDER__ */ |
982f26e4 | 1346 | |
2ed5b748 AC |
1347 | /* Callback routine called by Unwind_ForcedUnwind to execute all the cleanup |
1348 | before exiting the task. */ | |
1349 | ||
60aa5228 | 1350 | #ifndef CERT |
a6f0cb16 | 1351 | _Unwind_Reason_Code |
2ed5b748 | 1352 | __gnat_cleanupunwind_handler (int version ATTRIBUTE_UNUSED, |
a6f0cb16 | 1353 | _Unwind_Action phases, |
2ed5b748 | 1354 | _Unwind_Exception_Class eclass ATTRIBUTE_UNUSED, |
a6f0cb16 | 1355 | struct _Unwind_Exception *exception, |
2ed5b748 AC |
1356 | struct _Unwind_Context *context ATTRIBUTE_UNUSED, |
1357 | void *arg ATTRIBUTE_UNUSED) | |
a6f0cb16 AC |
1358 | { |
1359 | /* Terminate when the end of the stack is reached. */ | |
1360 | if ((phases & _UA_END_OF_STACK) != 0 | |
c1107fa3 | 1361 | #if defined (__ia64__) && defined (__hpux__) && defined (USE_LIBUNWIND_EXCEPTIONS) |
a6f0cb16 | 1362 | /* Strictely follow the ia64 ABI: when end of stack is reached, |
a2c1791d AC |
1363 | the callback will be called with a NULL stack pointer. |
1364 | No need for that when using libgcc unwinder. */ | |
1365 | || _Unwind_GetGR (context, 12) == 0 | |
a6f0cb16 AC |
1366 | #endif |
1367 | ) | |
1368 | __gnat_unhandled_except_handler (exception); | |
1369 | ||
1370 | /* We know there is at least one cleanup further up. Return so that it | |
1371 | is searched and entered, after which Unwind_Resume will be called | |
1372 | and this hook will gain control again. */ | |
1373 | return _URC_NO_REASON; | |
1374 | } | |
60aa5228 | 1375 | #endif |
a6f0cb16 | 1376 | |
982f26e4 AC |
1377 | /* Define the consistently named wrappers imported by Propagate_Exception. */ |
1378 | ||
982f26e4 AC |
1379 | _Unwind_Reason_Code |
1380 | __gnat_Unwind_RaiseException (_Unwind_Exception *e) | |
1381 | { | |
2ed5b748 | 1382 | #ifdef __USING_SJLJ_EXCEPTIONS__ |
982f26e4 | 1383 | return _Unwind_SjLj_RaiseException (e); |
2ed5b748 | 1384 | #else |
982f26e4 | 1385 | return _Unwind_RaiseException (e); |
2ed5b748 | 1386 | #endif |
982f26e4 AC |
1387 | } |
1388 | ||
1389 | _Unwind_Reason_Code | |
a905304c | 1390 | __gnat_Unwind_ForcedUnwind (_Unwind_Exception *e ATTRIBUTE_UNUSED, |
6cbfce7e | 1391 | _Unwind_Stop_Fn handler ATTRIBUTE_UNUSED, |
a905304c | 1392 | void *argument ATTRIBUTE_UNUSED) |
982f26e4 | 1393 | { |
2ed5b748 | 1394 | #ifdef __USING_SJLJ_EXCEPTIONS__ |
a9bbfbd0 AC |
1395 | |
1396 | # if defined (__APPLE__) && defined (__arm__) | |
a905304c | 1397 | /* There is not ForcedUnwind routine in arm-darwin system library. */ |
a9bbfbd0 AC |
1398 | return _URC_FATAL_PHASE1_ERROR; |
1399 | # else | |
2ed5b748 | 1400 | return _Unwind_SjLj_ForcedUnwind (e, handler, argument); |
a9bbfbd0 AC |
1401 | # endif |
1402 | ||
2ed5b748 | 1403 | #else |
982f26e4 | 1404 | return _Unwind_ForcedUnwind (e, handler, argument); |
2ed5b748 | 1405 | #endif |
982f26e4 AC |
1406 | } |
1407 | ||
4a8043c4 | 1408 | #if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__) |
b3f532ce AC |
1409 | |
1410 | #define STATUS_USER_DEFINED (1U << 29) | |
e187fa72 AC |
1411 | |
1412 | /* From unwind-seh.c. */ | |
1413 | #define GCC_MAGIC (('G' << 16) | ('C' << 8) | 'C') | |
1414 | #define GCC_EXCEPTION(TYPE) \ | |
1415 | (STATUS_USER_DEFINED | ((TYPE) << 24) | GCC_MAGIC) | |
1416 | #define STATUS_GCC_THROW GCC_EXCEPTION (0) | |
1417 | ||
e187fa72 AC |
1418 | struct Exception_Data * |
1419 | __gnat_map_SEH (EXCEPTION_RECORD* ExceptionRecord, const char **msg); | |
1420 | ||
1421 | struct _Unwind_Exception * | |
1422 | __gnat_create_machine_occurrence_from_signal_handler (Exception_Id, | |
1423 | const char *); | |
1424 | ||
d9819bbd AC |
1425 | /* Unwind opcodes. */ |
1426 | #define UWOP_PUSH_NONVOL 0 | |
1427 | #define UWOP_ALLOC_LARGE 1 | |
1428 | #define UWOP_ALLOC_SMALL 2 | |
1429 | #define UWOP_SET_FPREG 3 | |
1430 | #define UWOP_SAVE_NONVOL 4 | |
1431 | #define UWOP_SAVE_NONVOL_FAR 5 | |
1432 | #define UWOP_SAVE_XMM128 8 | |
1433 | #define UWOP_SAVE_XMM128_FAR 9 | |
1434 | #define UWOP_PUSH_MACHFRAME 10 | |
1435 | ||
1436 | /* Modify the IP value saved in the machine frame. This is really a kludge, | |
1437 | that will be removed if we could propagate the Windows exception (and not | |
1438 | the GCC one). | |
45c6d784 | 1439 | |
d9819bbd | 1440 | What is very wrong is that the Windows unwinder will try to decode the |
45c6d784 | 1441 | instruction at IP, which isn't valid anymore after the adjustment. */ |
d9819bbd AC |
1442 | |
1443 | static void | |
1444 | __gnat_adjust_context (unsigned char *unw, ULONG64 rsp) | |
1445 | { | |
1446 | unsigned int len; | |
1447 | ||
45c6d784 EB |
1448 | /* Version 1 or 2. */ |
1449 | if (unw[0] != 1 && unw[0] != 2) | |
1450 | return; | |
1451 | /* No flags, no prologue. */ | |
1452 | if (unw[1] != 0) | |
d9819bbd AC |
1453 | return; |
1454 | len = unw[2]; | |
45c6d784 | 1455 | /* No frame. */ |
d9819bbd AC |
1456 | if (unw[3] != 0) |
1457 | return; | |
45c6d784 EB |
1458 | /* ??? Skip the first 2 undocumented opcodes for version 2. */ |
1459 | if (unw[0] == 2) | |
1460 | unw += 8; | |
1461 | else | |
1462 | unw += 4; | |
d9819bbd AC |
1463 | while (len > 0) |
1464 | { | |
d6cd5d34 | 1465 | /* Offset in prologue = 0. */ |
d9819bbd AC |
1466 | if (unw[0] != 0) |
1467 | return; | |
1468 | switch (unw[1] & 0xf) | |
1469 | { | |
1470 | case UWOP_ALLOC_LARGE: | |
1471 | /* Expect < 512KB. */ | |
1472 | if ((unw[1] & 0xf0) != 0) | |
1473 | return; | |
1474 | rsp += *(unsigned short *)(unw + 2) * 8; | |
1475 | len--; | |
1476 | unw += 2; | |
1477 | break; | |
1478 | case UWOP_SAVE_NONVOL: | |
1479 | case UWOP_SAVE_XMM128: | |
1480 | len--; | |
1481 | unw += 2; | |
1482 | break; | |
1483 | case UWOP_PUSH_MACHFRAME: | |
1484 | { | |
1485 | ULONG64 *rip; | |
1486 | rip = (ULONG64 *)rsp; | |
1487 | if ((unw[1] & 0xf0) == 0x10) | |
1488 | rip++; | |
1489 | /* Adjust rip. */ | |
1490 | (*rip)++; | |
1491 | } | |
1492 | return; | |
1493 | default: | |
1494 | /* Unexpected. */ | |
1495 | return; | |
1496 | } | |
1497 | unw += 2; | |
1498 | len--; | |
1499 | } | |
1500 | } | |
1501 | ||
758ad973 AC |
1502 | EXCEPTION_DISPOSITION |
1503 | __gnat_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame, | |
1504 | PCONTEXT ms_orig_context, | |
1505 | PDISPATCHER_CONTEXT ms_disp) | |
1506 | { | |
45c6d784 | 1507 | /* Possibly transform run-time errors into Ada exceptions. */ |
b3f532ce | 1508 | if (!(ms_exc->ExceptionCode & STATUS_USER_DEFINED)) |
d9819bbd | 1509 | { |
e187fa72 AC |
1510 | struct Exception_Data *exception; |
1511 | const char *msg; | |
d9819bbd | 1512 | ULONG64 excpip = (ULONG64) ms_exc->ExceptionAddress; |
e187fa72 | 1513 | |
d9819bbd AC |
1514 | if (excpip != 0 |
1515 | && excpip >= (ms_disp->ImageBase | |
1516 | + ms_disp->FunctionEntry->BeginAddress) | |
1517 | && excpip < (ms_disp->ImageBase | |
1518 | + ms_disp->FunctionEntry->EndAddress)) | |
1519 | { | |
1520 | /* This is a fault in this function. We need to adjust the return | |
45c6d784 EB |
1521 | address before raising the GCC exception. In order to do that, |
1522 | we need to locate the machine frame that has been pushed onto | |
1523 | the stack in response to the hardware exception, so we will do | |
1524 | a private unwinding from here, i.e. the frame of the personality | |
1525 | routine, up to the frame immediately following the frame of this | |
1526 | function. This frame corresponds to a dummy prologue which is | |
1527 | never actually executed but instead appears before the real entry | |
1528 | point of an interrupt routine and exists only to provide a place | |
1529 | to simulate the push of a machine frame. */ | |
d9819bbd AC |
1530 | CONTEXT context; |
1531 | PRUNTIME_FUNCTION mf_func = NULL; | |
1532 | ULONG64 mf_imagebase; | |
5df1266a | 1533 | ULONG64 mf_rsp = 0; |
d9819bbd | 1534 | |
45c6d784 | 1535 | /* Get the current context. */ |
d9819bbd AC |
1536 | RtlCaptureContext (&context); |
1537 | ||
1538 | while (1) | |
1539 | { | |
1540 | PRUNTIME_FUNCTION RuntimeFunction; | |
1541 | ULONG64 ImageBase; | |
1542 | VOID *HandlerData; | |
1543 | ULONG64 EstablisherFrame; | |
1544 | ||
1545 | /* Get function metadata. */ | |
45c6d784 EB |
1546 | RuntimeFunction |
1547 | = RtlLookupFunctionEntry (context.Rip, &ImageBase, | |
1548 | ms_disp->HistoryTable); | |
1549 | ||
1550 | /* Stop once we reached the frame of this function. */ | |
d9819bbd AC |
1551 | if (RuntimeFunction == ms_disp->FunctionEntry) |
1552 | break; | |
45c6d784 | 1553 | |
d9819bbd AC |
1554 | mf_func = RuntimeFunction; |
1555 | mf_imagebase = ImageBase; | |
1556 | mf_rsp = context.Rsp; | |
1557 | ||
45c6d784 | 1558 | if (RuntimeFunction) |
d9819bbd AC |
1559 | { |
1560 | /* Unwind. */ | |
1561 | RtlVirtualUnwind (0, ImageBase, context.Rip, RuntimeFunction, | |
1562 | &context, &HandlerData, &EstablisherFrame, | |
1563 | NULL); | |
1564 | } | |
45c6d784 EB |
1565 | else |
1566 | { | |
1567 | /* In case of failure, assume this is a leaf function. */ | |
1568 | context.Rip = *(ULONG64 *) context.Rsp; | |
1569 | context.Rsp += 8; | |
1570 | } | |
d9819bbd AC |
1571 | |
1572 | /* 0 means bottom of the stack. */ | |
1573 | if (context.Rip == 0) | |
1574 | { | |
1575 | mf_func = NULL; | |
1576 | break; | |
1577 | } | |
1578 | } | |
45c6d784 EB |
1579 | |
1580 | /* If we have found the machine frame, adjust the return address. */ | |
d9819bbd AC |
1581 | if (mf_func != NULL) |
1582 | __gnat_adjust_context | |
1583 | ((unsigned char *)(mf_imagebase + mf_func->UnwindData), mf_rsp); | |
1584 | } | |
e187fa72 AC |
1585 | |
1586 | exception = __gnat_map_SEH (ms_exc, &msg); | |
1587 | if (exception != NULL) | |
1588 | { | |
45c6d784 | 1589 | /* Directly convert the system exception into a GCC one. |
e187fa72 | 1590 | |
e187fa72 AC |
1591 | This is really breaking the API, but is necessary for stack size |
1592 | reasons: the normal way is to call Raise_From_Signal_Handler, | |
45c6d784 EB |
1593 | which builds the exception and calls _Unwind_RaiseException, |
1594 | which unwinds the stack and will call this personality routine. | |
1595 | But the Windows unwinder needs about 2KB of stack. */ | |
1596 | struct _Unwind_Exception *exc | |
1597 | = __gnat_create_machine_occurrence_from_signal_handler (exception, | |
1598 | msg); | |
e187fa72 AC |
1599 | memset (exc->private_, 0, sizeof (exc->private_)); |
1600 | ms_exc->ExceptionCode = STATUS_GCC_THROW; | |
1601 | ms_exc->NumberParameters = 1; | |
1602 | ms_exc->ExceptionInformation[0] = (ULONG_PTR)exc; | |
1603 | } | |
1604 | ||
d9819bbd | 1605 | } |
b3f532ce | 1606 | |
45c6d784 EB |
1607 | return |
1608 | _GCC_specific_handler (ms_exc, this_frame, ms_orig_context, ms_disp, | |
1609 | __gnat_personality_imp); | |
758ad973 | 1610 | } |
45c6d784 | 1611 | |
4cd30bf7 AC |
1612 | /* Define __gnat_personality_v0 for convenience */ |
1613 | ||
1614 | PERSONALITY_STORAGE _Unwind_Reason_Code | |
1615 | __gnat_personality_v0 (version_arg_t version_arg, | |
1616 | phases_arg_t phases_arg, | |
1617 | _Unwind_Exception_Class uw_exception_class, | |
1618 | _Unwind_Exception *uw_exception, | |
1619 | _Unwind_Context *uw_context) | |
1620 | { | |
1621 | return PERSONALITY_FUNCTION | |
1622 | (version_arg, phases_arg, uw_exception_class, uw_exception, uw_context); | |
1623 | } | |
1624 | ||
758ad973 | 1625 | #endif /* SEH */ |
161c5cc5 AC |
1626 | |
1627 | #if !defined (__USING_SJLJ_EXCEPTIONS__) | |
1628 | /* Size of the _Unwind_Exception structure. This is used by g-cppexc to get | |
1629 | the offset to the C++ object. */ | |
1630 | ||
1631 | const int __gnat_unwind_exception_size = sizeof (_Unwind_Exception); | |
1632 | #endif | |
6cbfce7e AC |
1633 | |
1634 | #ifdef __cplusplus | |
1635 | } | |
1636 | #endif |