1 /****************************************************************************
3 * GNAT COMPILER COMPONENTS *
7 * C Implementation File *
10 * Copyright (C) 1992-2002, Free Software Foundation, Inc. *
12 * GNAT is free software; you can redistribute it and/or modify it under *
13 * terms of the GNU General Public License as published by the Free Soft- *
14 * ware Foundation; either version 2, or (at your option) any later ver- *
15 * sion. GNAT is distributed in the hope that it will be useful, but WITH- *
16 * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
17 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
18 * for more details. You should have received a copy of the GNU General *
19 * Public License distributed with GNAT; see file COPYING. If not, write *
20 * to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, *
21 * MA 02111-1307, USA. *
23 * As a special exception, if you link this file with other files to *
24 * produce an executable, this file does not by itself cause the resulting *
25 * executable to be covered by the GNU General Public License. This except- *
26 * ion does not however invalidate any other reasons why the executable *
27 * file might be covered by the GNU Public License. *
29 * GNAT was originally developed by the GNAT team at New York University. *
30 * Extensive contributions were provided by Ada Core Technologies Inc. *
32 ****************************************************************************/
34 /* Routines to support runtime exception handling */
51 /* We have not yet figured out how to import this directly */
54 _gnat_builtin_longjmp (ptr
, flag
)
56 int flag ATTRIBUTE_UNUSED
;
58 __builtin_longjmp (ptr
, 1);
61 /* When an exception is raised for which no handler exists, the procedure
62 Ada.Exceptions.Unhandled_Exception is called, which performs the call to
63 adafinal to complete finalization, and then prints out the error messages
64 for the unhandled exception. The final step is to call this routine, which
65 performs any system dependent cleanup required. */
68 __gnat_unhandled_terminate ()
70 /* Special termination handling for VMS */
76 /* Remove the exception vector so it won't intercept any errors
77 in the call to exit, and go into and endless loop */
79 SYS$
SETEXV (1, 0, 3, &prvhnd
);
83 /* Termination handling for all other systems. */
85 #elif !defined (__RT__)
90 /* Below is the code related to the integration of the GCC mechanism for
91 exception handling. */
95 /* Exception Handling personality routine for Ada.
97 ??? It is currently inspired from the one for C++, needs cleanups and
98 additional comments. It also contains a big bunch of debugging code that
99 we shall get rid of at some point. */
101 #ifdef IN_RTS /* For eh personality routine */
103 /* ??? Does it make any sense to leave this for the compiler ? */
106 #include "unwind-dw2-fde.h"
107 #include "unwind-pe.h"
109 /* First define a set of useful structures and helper routines. */
111 typedef struct _Unwind_Context _Unwind_Context
;
113 struct lsda_header_info
117 _Unwind_Ptr ttype_base
;
118 const unsigned char *TType
;
119 const unsigned char *action_table
;
120 unsigned char ttype_encoding
;
121 unsigned char call_site_encoding
;
124 typedef struct lsda_header_info lsda_header_info
;
126 static const unsigned char *
127 parse_lsda_header (context
, p
, info
)
128 _Unwind_Context
*context
;
129 const unsigned char *p
;
130 lsda_header_info
*info
;
133 unsigned char lpstart_encoding
;
135 info
->Start
= (context
? _Unwind_GetRegionStart (context
) : 0);
137 /* Find @LPStart, the base to which landing pad offsets are relative. */
138 lpstart_encoding
= *p
++;
139 if (lpstart_encoding
!= DW_EH_PE_omit
)
140 p
= read_encoded_value (context
, lpstart_encoding
, p
, &info
->LPStart
);
142 info
->LPStart
= info
->Start
;
144 /* Find @TType, the base of the handler and exception spec type data. */
145 info
->ttype_encoding
= *p
++;
146 if (info
->ttype_encoding
!= DW_EH_PE_omit
)
148 p
= read_uleb128 (p
, &tmp
);
149 info
->TType
= p
+ tmp
;
154 /* The encoding and length of the call-site table; the action table
155 immediately follows. */
156 info
->call_site_encoding
= *p
++;
157 p
= read_uleb128 (p
, &tmp
);
158 info
->action_table
= p
+ tmp
;
163 static const _Unwind_Ptr
164 get_ttype_entry (context
, info
, i
)
165 _Unwind_Context
*context
;
166 lsda_header_info
*info
;
171 i
*= size_of_encoded_value (info
->ttype_encoding
);
172 read_encoded_value (context
, info
->ttype_encoding
, info
->TType
- i
, &ptr
);
177 /* This is the structure of exception objects as built by the GNAT runtime
178 library (a-except.adb). The layouts should exactly match, and the "common"
179 header is mandated by the exception handling ABI. */
181 struct _GNAT_Exception
183 struct _Unwind_Exception common
;
185 char handled_by_others
;
187 char select_cleanups
;
191 /* The two constants below are specific ttype identifiers for special
192 exception ids. Their value is currently hardcoded at the gigi level
193 (see N_Exception_Handler). */
195 #define GNAT_OTHERS_ID ((_Unwind_Ptr) 0x0)
196 #define GNAT_ALL_OTHERS_ID ((_Unwind_Ptr) 0x1)
199 /* The DB stuff below is there for debugging purposes only. */
201 #define DB_PHASES 0x1
202 #define DB_SEARCH 0x2
203 #define DB_ECLASS 0x4
206 #define DB_FOUND 0x20
207 #define DB_INSTALL 0x40
208 #define DB_CALLS 0x80
210 #define AEHP_DB_SPECS \
211 (DB_PHASES | DB_SEARCH | DB_SAW | DB_FOUND | DB_INSTALL | DB_CALLS | DB_MATCH)
216 static int db_specs
= AEHP_DB_SPECS
;
218 static int db_specs
= 0;
221 #define START_DB(what) do { if (what & db_specs) {
222 #define END_DB(what) } \
225 /* The "action" stuff below is also there for debugging purposes only. */
229 _Unwind_Action action
;
231 } action_description_t
;
233 static action_description_t action_descriptions
[]
234 = {{ _UA_SEARCH_PHASE
, "SEARCH_PHASE" },
235 { _UA_CLEANUP_PHASE
, "CLEANUP_PHASE" },
236 { _UA_HANDLER_FRAME
, "HANDLER_FRAME" },
237 { _UA_FORCE_UNWIND
, "FORCE_UNWIND" },
241 decode_actions (actions
)
242 _Unwind_Action actions
;
246 action_description_t
*a
= action_descriptions
;
249 for (; a
->description
!= 0; a
++)
250 if (actions
& a
->action
)
251 printf ("%s ", a
->description
);
256 /* The following is defined from a-except.adb. Its purpose is to enable
257 automatic backtraces upon exception raise, as provided through the
258 GNAT.Traceback facilities. */
259 extern void __gnat_notify_handled_exception
PARAMS ((void *, bool, bool));
261 /* Below is the eh personality routine per se. */
264 __gnat_eh_personality (version
, actions
, exception_class
, ue_header
, context
)
266 _Unwind_Action actions
;
267 _Unwind_Exception_Class exception_class
;
268 struct _Unwind_Exception
*ue_header
;
269 struct _Unwind_Context
*context
;
271 enum found_handler_type
278 lsda_header_info info
;
279 const unsigned char *language_specific_data
;
280 const unsigned char *action_record
;
281 const unsigned char *p
;
282 _Unwind_Ptr landing_pad
, ip
;
283 int handler_switch_value
;
284 bool hit_others_handler
;
285 struct _GNAT_Exception
*gnat_exception
;
288 return _URC_FATAL_PHASE1_ERROR
;
290 START_DB (DB_PHASES
);
291 decode_actions (actions
);
294 if (strcmp ((char *) &exception_class
, "GNU") != 0
295 || strcmp (((char *) &exception_class
) + 4, "Ada") != 0)
297 START_DB (DB_SEARCH
);
298 printf (" Exception Class doesn't match for ip = %p\n", ip
);
301 printf (" => FOUND nothing\n");
303 return _URC_CONTINUE_UNWIND
;
306 gnat_exception
= (struct _GNAT_Exception
*) ue_header
;
308 START_DB (DB_PHASES
);
309 if (gnat_exception
->select_cleanups
)
310 printf ("(select_cleanups) :\n");
315 language_specific_data
316 = (const unsigned char *) _Unwind_GetLanguageSpecificData (context
);
318 /* If no LSDA, then there are no handlers or cleanups. */
319 if (! language_specific_data
)
321 ip
= _Unwind_GetIP (context
) - 1;
323 START_DB (DB_SEARCH
);
324 printf (" No Language Specific Data for ip = %p\n", ip
);
327 printf (" => FOUND nothing\n");
329 return _URC_CONTINUE_UNWIND
;
332 /* Parse the LSDA header. */
333 p
= parse_lsda_header (context
, language_specific_data
, &info
);
334 info
.ttype_base
= base_of_encoded_value (info
.ttype_encoding
, context
);
335 ip
= _Unwind_GetIP (context
) - 1;
338 handler_switch_value
= 0;
340 /* Search the call-site table for the action associated with this IP. */
341 while (p
< info
.action_table
)
343 _Unwind_Ptr cs_start
, cs_len
, cs_lp
;
344 _Unwind_Word cs_action
;
346 /* Note that all call-site encodings are "absolute" displacements. */
347 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_start
);
348 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_len
);
349 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_lp
);
350 p
= read_uleb128 (p
, &cs_action
);
352 /* The table is sorted, so if we've passed the ip, stop. */
353 if (ip
< info
.Start
+ cs_start
)
354 p
= info
.action_table
;
355 else if (ip
< info
.Start
+ cs_start
+ cs_len
)
358 landing_pad
= info
.LPStart
+ cs_lp
;
360 action_record
= info
.action_table
+ cs_action
- 1;
361 goto found_something
;
365 START_DB (DB_SEARCH
);
366 printf (" No Action entry for ip = %p\n", ip
);
369 /* If ip is not present in the table, call terminate. This is for
370 a destructor inside a cleanup, or a library routine the compiler
371 was not expecting to throw.
374 (actions & _UA_FORCE_UNWIND ? found_nothing : found_terminate);
376 ??? Does this have a mapping in Ada semantics ? */
378 found_type
= found_nothing
;
383 found_type
= found_nothing
;
385 if (landing_pad
== 0)
387 /* If ip is present, and has a null landing pad, there are
388 no cleanups or handlers to be run. */
389 START_DB (DB_SEARCH
);
390 printf (" No Landing Pad for ip = %p\n", ip
);
393 else if (action_record
== 0)
395 START_DB (DB_SEARCH
);
396 printf (" Null Action Record for ip = %p <===\n", ip
);
401 signed long ar_filter
, ar_disp
;
402 signed long cleanup_filter
= 0;
403 signed long handler_filter
= 0;
405 START_DB (DB_SEARCH
);
406 printf (" Landing Pad + Action Record for ip = %p\n", ip
);
410 printf (" => Search for exception matching id %p\n",
414 /* Otherwise we have a catch handler or exception specification. */
421 p
= read_sleb128 (p
, &tmp
); ar_filter
= tmp
;
422 read_sleb128 (p
, &tmp
); ar_disp
= tmp
;
425 printf ("ar_filter %d\n", ar_filter
);
430 /* Zero filter values are cleanups. We should not be seeing
431 this for GNU-Ada though
432 saw_cleanup = true; */
433 START_DB (DB_SEARCH
);
434 printf (" Null Filter for ip = %p <===\n", ip
);
437 else if (ar_filter
> 0)
439 _Unwind_Ptr lp_id
= get_ttype_entry (context
, &info
, ar_filter
);
442 printf ("catch_type ");
446 case GNAT_ALL_OTHERS_ID
:
447 printf ("GNAT_ALL_OTHERS_ID\n");
451 printf ("GNAT_OTHERS_ID\n");
455 printf ("%p\n", lp_id
);
461 if (lp_id
== GNAT_ALL_OTHERS_ID
)
464 printf (" => SAW cleanup\n");
467 cleanup_filter
= ar_filter
;
468 gnat_exception
->has_cleanup
= true;
472 = (lp_id
== GNAT_OTHERS_ID
473 && gnat_exception
->handled_by_others
);
475 if (hit_others_handler
|| lp_id
== gnat_exception
->id
)
478 printf (" => SAW handler\n");
481 handler_filter
= ar_filter
;
485 /* Negative filter values are for C++ exception specifications.
486 Should not be there for Ada :/ */
489 if (actions
& _UA_SEARCH_PHASE
)
493 found_type
= found_handler
;
494 handler_switch_value
= handler_filter
;
499 found_type
= found_cleanup
;
502 if (actions
& _UA_CLEANUP_PHASE
)
506 found_type
= found_handler
;
507 handler_switch_value
= handler_filter
;
513 found_type
= found_cleanup
;
514 handler_switch_value
= cleanup_filter
;
522 action_record
= p
+ ar_disp
;
527 if (found_type
== found_nothing
)
530 printf (" => FOUND nothing\n");
533 return _URC_CONTINUE_UNWIND
;
536 if (actions
& _UA_SEARCH_PHASE
)
539 printf (" => Computing return for SEARCH\n");
542 if (found_type
== found_cleanup
543 && !gnat_exception
->select_cleanups
)
546 printf (" => FOUND cleanup\n");
549 return _URC_CONTINUE_UNWIND
;
553 printf (" => FOUND handler\n");
556 return _URC_HANDLER_FOUND
;
561 START_DB (DB_INSTALL
);
562 printf (" => INSTALLING context for filter %d\n",
563 handler_switch_value
);
566 if (found_type
== found_terminate
)
568 /* Should not have this for Ada ? */
569 START_DB (DB_INSTALL
);
570 printf (" => FOUND terminate <===\n");
575 /* Signal that we are going to enter a handler, which will typically
576 enable the debugger to take control and possibly output an automatic
577 backtrace. Note that we are supposed to provide the handler's entry
578 point here but we don't have it. */
579 __gnat_notify_handled_exception ((void *)landing_pad
, hit_others_handler
,
582 /* The GNU-Ada exception handlers know how to find the exception
583 occurrence without having to pass it as an argument so there
584 is no need to feed any specific register with this information.
586 This is why the two following lines are commented out. */
588 /* _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
589 (_Unwind_Ptr) &xh->unwindHeader); */
591 _Unwind_SetGR (context
, __builtin_eh_return_data_regno (1),
592 handler_switch_value
);
594 _Unwind_SetIP (context
, landing_pad
);
596 return _URC_INSTALL_CONTEXT
;
600 #else /* IN_RTS - For eh personality routine */
602 /* The calls to the GCC runtime interface for exception raising are currently
603 issued from a-except.adb, which is used by both the runtime library and
604 the compiler. As the compiler binary is not linked against the GCC runtime
605 library, we need a stub for this interface in the compiler case. */
609 _Unwind_RaiseException (e
)
610 struct _Unwind_Exception
*e ATTRIBUTE_UNUSED
;
612 /* Since we don't link the compiler with a host libgcc, we should not be
613 using the GCC eh mechanism for the compiler and so expect this function
614 never to be called. */