FSF GCC merge 02/23/03
[official-gcc.git] / gcc / ada / raise.c
blob087448a4d5043dddd8dc45d71637f7f70007979c
1 /****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * R A I S E *
6 * *
7 * C Implementation File *
8 * *
9 * *
10 * Copyright (C) 1992-2002, Free Software Foundation, Inc. *
11 * *
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. *
22 * *
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. *
28 * *
29 * GNAT was originally developed by the GNAT team at New York University. *
30 * Extensive contributions were provided by Ada Core Technologies Inc. *
31 * *
32 ****************************************************************************/
34 /* Routines to support runtime exception handling */
36 #ifdef IN_RTS
37 #include "tconfig.h"
38 #include "tsystem.h"
39 #include <sys/stat.h>
40 typedef char bool;
41 # define true 1
42 # define false 0
43 #else
44 #include "config.h"
45 #include "system.h"
46 #endif
48 #include "adaint.h"
49 #include "raise.h"
51 /* We have not yet figured out how to import this directly */
53 void
54 _gnat_builtin_longjmp (ptr, flag)
55 void *ptr;
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. */
67 void
68 __gnat_unhandled_terminate ()
70 /* Special termination handling for VMS */
72 #ifdef VMS
74 long prvhnd;
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);
80 __gnat_os_exit (1);
83 /* Termination handling for all other systems. */
85 #elif !defined (__RT__)
86 __gnat_os_exit (1);
87 #endif
90 /* Below is the code related to the integration of the GCC mechanism for
91 exception handling. */
93 #include "unwind.h"
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 ? */
105 #include "dwarf2.h"
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
115 _Unwind_Ptr Start;
116 _Unwind_Ptr LPStart;
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;
132 _Unwind_Ptr tmp;
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);
141 else
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;
151 else
152 info->TType = 0;
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;
160 return p;
163 static const _Unwind_Ptr
164 get_ttype_entry (context, info, i)
165 _Unwind_Context *context;
166 lsda_header_info *info;
167 long i;
169 _Unwind_Ptr ptr;
171 i *= size_of_encoded_value (info->ttype_encoding);
172 read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr);
174 return 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;
184 _Unwind_Ptr id;
185 char handled_by_others;
186 char has_cleanup;
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
204 #define DB_MATCH 0x8
205 #define DB_SAW 0x10
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)
213 #undef AEHP_DB_SPECS
215 #ifdef AEHP_DB_SPECS
216 static int db_specs = AEHP_DB_SPECS;
217 #else
218 static int db_specs = 0;
219 #endif
221 #define START_DB(what) do { if (what & db_specs) {
222 #define END_DB(what) } \
223 } while (0);
225 /* The "action" stuff below is also there for debugging purposes only. */
227 typedef struct
229 _Unwind_Action action;
230 char * description;
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" },
238 { -1, 0}};
240 static void
241 decode_actions (actions)
242 _Unwind_Action actions;
244 int i;
246 action_description_t *a = action_descriptions;
248 printf ("\n");
249 for (; a->description != 0; a++)
250 if (actions & a->action)
251 printf ("%s ", a->description);
253 printf (" : ");
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. */
263 _Unwind_Reason_Code
264 __gnat_eh_personality (version, actions, exception_class, ue_header, context)
265 int version;
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
273 found_nothing,
274 found_terminate,
275 found_cleanup,
276 found_handler
277 } found_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;
287 if (version != 1)
288 return _URC_FATAL_PHASE1_ERROR;
290 START_DB (DB_PHASES);
291 decode_actions (actions);
292 END_DB (DB_PHASES);
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);
299 END_DB (DB_SEARCH);
300 START_DB (DB_FOUND);
301 printf (" => FOUND nothing\n");
302 END_DB (DB_FOUND);
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");
311 else
312 printf (" :\n");
313 END_DB (DB_PHASES);
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);
325 END_DB (DB_SEARCH);
326 START_DB (DB_FOUND);
327 printf (" => FOUND nothing\n");
328 END_DB (DB_FOUND);
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;
336 landing_pad = 0;
337 action_record = 0;
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)
357 if (cs_lp)
358 landing_pad = info.LPStart + cs_lp;
359 if (cs_action)
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);
367 END_DB (DB_SEARCH);
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.
373 found_type =
374 (actions & _UA_FORCE_UNWIND ? found_nothing : found_terminate);
376 ??? Does this have a mapping in Ada semantics ? */
378 found_type = found_nothing;
379 goto do_something;
381 found_something:
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);
391 END_DB (DB_SEARCH);
393 else if (action_record == 0)
395 START_DB (DB_SEARCH);
396 printf (" Null Action Record for ip = %p <===\n", ip);
397 END_DB (DB_SEARCH);
399 else
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);
407 END_DB (DB_SEARCH);
409 START_DB (DB_MATCH);
410 printf (" => Search for exception matching id %p\n",
411 gnat_exception->id);
412 END_DB (DB_MATCH);
414 /* Otherwise we have a catch handler or exception specification. */
416 while (1)
418 _Unwind_Word tmp;
420 p = action_record;
421 p = read_sleb128 (p, &tmp); ar_filter = tmp;
422 read_sleb128 (p, &tmp); ar_disp = tmp;
424 START_DB (DB_MATCH);
425 printf ("ar_filter %d\n", ar_filter);
426 END_DB (DB_MATCH);
428 if (ar_filter == 0)
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);
435 END_DB (DB_SEARCH);
437 else if (ar_filter > 0)
439 _Unwind_Ptr lp_id = get_ttype_entry (context, &info, ar_filter);
441 START_DB (DB_MATCH);
442 printf ("catch_type ");
444 switch (lp_id)
446 case GNAT_ALL_OTHERS_ID:
447 printf ("GNAT_ALL_OTHERS_ID\n");
448 break;
450 case GNAT_OTHERS_ID:
451 printf ("GNAT_OTHERS_ID\n");
452 break;
454 default:
455 printf ("%p\n", lp_id);
456 break;
459 END_DB (DB_MATCH);
461 if (lp_id == GNAT_ALL_OTHERS_ID)
463 START_DB (DB_SAW);
464 printf (" => SAW cleanup\n");
465 END_DB (DB_SAW);
467 cleanup_filter = ar_filter;
468 gnat_exception->has_cleanup = true;
471 hit_others_handler
472 = (lp_id == GNAT_OTHERS_ID
473 && gnat_exception->handled_by_others);
475 if (hit_others_handler || lp_id == gnat_exception->id)
477 START_DB (DB_SAW);
478 printf (" => SAW handler\n");
479 END_DB (DB_SAW);
481 handler_filter = ar_filter;
484 else
485 /* Negative filter values are for C++ exception specifications.
486 Should not be there for Ada :/ */
489 if (actions & _UA_SEARCH_PHASE)
491 if (handler_filter)
493 found_type = found_handler;
494 handler_switch_value = handler_filter;
495 break;
498 if (cleanup_filter)
499 found_type = found_cleanup;
502 if (actions & _UA_CLEANUP_PHASE)
504 if (handler_filter)
506 found_type = found_handler;
507 handler_switch_value = handler_filter;
508 break;
511 if (cleanup_filter)
513 found_type = found_cleanup;
514 handler_switch_value = cleanup_filter;
515 break;
519 if (ar_disp == 0)
520 break;
522 action_record = p + ar_disp;
526 do_something:
527 if (found_type == found_nothing)
529 START_DB (DB_FOUND);
530 printf (" => FOUND nothing\n");
531 END_DB (DB_FOUND);
533 return _URC_CONTINUE_UNWIND;
536 if (actions & _UA_SEARCH_PHASE)
538 START_DB (DB_FOUND);
539 printf (" => Computing return for SEARCH\n");
540 END_DB (DB_FOUND);
542 if (found_type == found_cleanup
543 && !gnat_exception->select_cleanups)
545 START_DB (DB_FOUND);
546 printf (" => FOUND cleanup\n");
547 END_DB (DB_FOUND);
549 return _URC_CONTINUE_UNWIND;
552 START_DB (DB_FOUND);
553 printf (" => FOUND handler\n");
554 END_DB (DB_FOUND);
556 return _URC_HANDLER_FOUND;
559 install_context:
561 START_DB (DB_INSTALL);
562 printf (" => INSTALLING context for filter %d\n",
563 handler_switch_value);
564 END_DB (DB_INSTALL);
566 if (found_type == found_terminate)
568 /* Should not have this for Ada ? */
569 START_DB (DB_INSTALL);
570 printf (" => FOUND terminate <===\n");
571 END_DB (DB_INSTALL);
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,
580 true);
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. */
608 _Unwind_Reason_Code
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. */
615 abort ();
618 #endif