OSDN Git Service

* 41intnam.ads, 42intnam.ads, 4aintnam.ads, 4cintnam.ads,
[pf3gnuchains/gcc-fork.git] / gcc / ada / raise.c
1 /****************************************************************************
2  *                                                                          *
3  *                         GNAT COMPILER COMPONENTS                         *
4  *                                                                          *
5  *                                R A I S E                                 *
6  *                                                                          *
7  *                          C Implementation File                           *
8  *                                                                          *
9  *                            $Revision$
10  *                                                                          *
11  *             Copyright (C) 1992-2002, Free Software Foundation, Inc.      *
12  *                                                                          *
13  * GNAT is free software;  you can  redistribute it  and/or modify it under *
14  * terms of the  GNU General Public License as published  by the Free Soft- *
15  * ware  Foundation;  either version 2,  or (at your option) any later ver- *
16  * sion.  GNAT is distributed in the hope that it will be useful, but WITH- *
17  * OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY *
18  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License *
19  * for  more details.  You should have  received  a copy of the GNU General *
20  * Public License  distributed with GNAT;  see file COPYING.  If not, write *
21  * to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, *
22  * MA 02111-1307, USA.                                                      *
23  *                                                                          *
24  * As a  special  exception,  if you  link  this file  with other  files to *
25  * produce an executable,  this file does not by itself cause the resulting *
26  * executable to be covered by the GNU General Public License. This except- *
27  * ion does not  however invalidate  any other reasons  why the  executable *
28  * file might be covered by the  GNU Public License.                        *
29  *                                                                          *
30  * GNAT was originally developed  by the GNAT team at  New York University. *
31  * It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). *
32  *                                                                          *
33  ****************************************************************************/
34
35 /* Routines to support runtime exception handling */
36
37 #ifdef IN_RTS
38 #include "tconfig.h"
39 #include "tsystem.h"
40 #include <sys/stat.h>
41 typedef char bool;
42 # define true 1
43 # define false 0
44 #else
45 #include "config.h"
46 #include "system.h"
47 #endif
48
49 #include "adaint.h"
50 #include "raise.h"
51
52 /*  We have not yet figured out how to import this directly */
53
54 void
55 _gnat_builtin_longjmp (ptr, flag)
56      void *ptr;
57      int flag ATTRIBUTE_UNUSED;
58 {
59    __builtin_longjmp (ptr, 1);
60 }
61
62 /* When an exception is raised for which no handler exists, the procedure
63    Ada.Exceptions.Unhandled_Exception is called, which performs the call to
64    adafinal to complete finalization, and then prints out the error messages
65    for the unhandled exception. The final step is to call this routine, which
66    performs any system dependent cleanup required.  */
67
68 void
69 __gnat_unhandled_terminate ()
70 {
71   /* Special termination handling for VMS */
72
73 #ifdef VMS
74     {
75       long prvhnd;
76
77       /* Remove the exception vector so it won't intercept any errors
78          in the call to exit, and go into and endless loop */
79
80       SYS$SETEXV (1, 0, 3, &prvhnd);
81       __gnat_os_exit (1);
82     }
83
84 /* Termination handling for all other systems. */
85
86 #elif !defined (__RT__)
87     __gnat_os_exit (1);
88 #endif
89 }
90
91 /* Below is the code related to the integration of the GCC mechanism for
92    exception handling.  */
93
94 #include "unwind.h"
95
96 /* Exception Handling personality routine for Ada.
97
98    ??? It is currently inspired from the one for C++, needs cleanups and
99    additional comments. It also contains a big bunch of debugging code that
100    we shall get rid of at some point.  */
101
102 #ifdef IN_RTS   /* For eh personality routine */
103
104 /* ??? Does it make any sense to leave this for the compiler ?   */
105
106 #include "dwarf2.h"
107 #include "unwind-dw2-fde.h"
108 #include "unwind-pe.h"
109
110 /* First define a set of useful structures and helper routines.  */
111
112 typedef struct _Unwind_Context _Unwind_Context;
113
114 struct lsda_header_info
115 {
116   _Unwind_Ptr Start;
117   _Unwind_Ptr LPStart;
118   _Unwind_Ptr ttype_base;
119   const unsigned char *TType;
120   const unsigned char *action_table;
121   unsigned char ttype_encoding;
122   unsigned char call_site_encoding;
123 };
124
125 typedef struct lsda_header_info lsda_header_info;
126
127 static const unsigned char *
128 parse_lsda_header (context, p, info)
129      _Unwind_Context *context;
130      const unsigned char *p;
131      lsda_header_info *info;
132 {
133   _Unwind_Ptr tmp;
134   unsigned char lpstart_encoding;
135
136   info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
137
138   /* Find @LPStart, the base to which landing pad offsets are relative.  */
139   lpstart_encoding = *p++;
140   if (lpstart_encoding != DW_EH_PE_omit)
141     p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
142   else
143     info->LPStart = info->Start;
144
145   /* Find @TType, the base of the handler and exception spec type data.  */
146   info->ttype_encoding = *p++;
147   if (info->ttype_encoding != DW_EH_PE_omit)
148     {
149       p = read_uleb128 (p, &tmp);
150       info->TType = p + tmp;
151     }
152   else
153     info->TType = 0;
154
155   /* The encoding and length of the call-site table; the action table
156      immediately follows.  */
157   info->call_site_encoding = *p++;
158   p = read_uleb128 (p, &tmp);
159   info->action_table = p + tmp;
160
161   return p;
162 }
163
164 static const _Unwind_Ptr
165 get_ttype_entry (context, info, i)
166      _Unwind_Context *context;
167      lsda_header_info *info;
168      long i;
169 {
170   _Unwind_Ptr ptr;
171
172   i *= size_of_encoded_value (info->ttype_encoding);
173   read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr);
174
175   return ptr;
176 }
177
178 /* This is the structure of exception objects as built by the GNAT runtime
179    library (a-except.adb). The layouts should exactly match, and the "common"
180    header is mandated by the exception handling ABI.  */
181
182 struct _GNAT_Exception
183 {
184   struct _Unwind_Exception common;
185   _Unwind_Ptr id;
186   char handled_by_others;
187   char has_cleanup;
188   char select_cleanups;
189 };
190
191
192 /* The two constants below are specific ttype identifiers for special
193    exception ids. Their value is currently hardcoded at the gigi level
194    (see N_Exception_Handler).  */
195
196 #define GNAT_OTHERS_ID      ((_Unwind_Ptr) 0x0)
197 #define GNAT_ALL_OTHERS_ID  ((_Unwind_Ptr) 0x1)
198
199
200 /* The DB stuff below is there for debugging purposes only.  */
201
202 #define DB_PHASES     0x1
203 #define DB_SEARCH     0x2
204 #define DB_ECLASS     0x4
205 #define DB_MATCH      0x8
206 #define DB_SAW        0x10
207 #define DB_FOUND      0x20
208 #define DB_INSTALL    0x40
209 #define DB_CALLS      0x80
210
211 #define AEHP_DB_SPECS \
212 (DB_PHASES | DB_SEARCH | DB_SAW | DB_FOUND | DB_INSTALL | DB_CALLS | DB_MATCH)
213
214 #undef AEHP_DB_SPECS
215
216 #ifdef AEHP_DB_SPECS
217 static int db_specs = AEHP_DB_SPECS;
218 #else
219 static int db_specs = 0;
220 #endif
221
222 #define START_DB(what) do { if (what & db_specs) {
223 #define END_DB(what)        } \
224                            } while (0);
225
226 /* The "action" stuff below is also there for debugging purposes only.  */
227
228 typedef struct
229 {
230   _Unwind_Action action;
231   char * description;
232 } action_description_t;
233
234 static action_description_t action_descriptions[]
235   = {{ _UA_SEARCH_PHASE,  "SEARCH_PHASE" },
236      { _UA_CLEANUP_PHASE, "CLEANUP_PHASE" },
237      { _UA_HANDLER_FRAME, "HANDLER_FRAME" },
238      { _UA_FORCE_UNWIND,  "FORCE_UNWIND" },
239      { -1, 0}};
240
241 static void
242 decode_actions (actions)
243      _Unwind_Action actions;
244 {
245   int i;
246
247   action_description_t *a = action_descriptions;
248
249   printf ("\n");
250   for (; a->description != 0; a++)
251     if (actions & a->action)
252       printf ("%s ", a->description);
253
254   printf (" : ");
255 }
256
257 /* The following is defined from a-except.adb. Its purpose is to enable
258    automatic backtraces upon exception raise, as provided through the 
259    GNAT.Traceback facilities.  */
260 extern void __gnat_notify_handled_exception PARAMS ((void *, bool, bool));
261
262 /* Below is the eh personality routine per se.  */
263
264 _Unwind_Reason_Code
265 __gnat_eh_personality (version, actions, exception_class, ue_header, context)
266      int version;
267      _Unwind_Action actions;
268      _Unwind_Exception_Class exception_class;
269      struct _Unwind_Exception *ue_header;
270      struct _Unwind_Context *context;
271 {
272   enum found_handler_type
273   {
274     found_nothing,
275     found_terminate,
276     found_cleanup,
277     found_handler
278   } found_type;
279   lsda_header_info info;
280   const unsigned char *language_specific_data;
281   const unsigned char *action_record;
282   const unsigned char *p;
283   _Unwind_Ptr landing_pad, ip;
284   int handler_switch_value;
285   bool hit_others_handler;
286   struct _GNAT_Exception *gnat_exception;
287
288   if (version != 1)
289     return _URC_FATAL_PHASE1_ERROR;
290
291   START_DB (DB_PHASES);
292   decode_actions (actions);
293   END_DB (DB_PHASES);
294
295   if (strcmp ((char *) &exception_class, "GNU") != 0
296       || strcmp (((char *) &exception_class) + 4, "Ada") != 0)
297     {
298       START_DB (DB_SEARCH);
299       printf ("              Exception Class doesn't match for ip = %p\n", ip);
300       END_DB (DB_SEARCH);
301       START_DB (DB_FOUND);
302       printf ("              => FOUND nothing\n");
303       END_DB (DB_FOUND);
304       return _URC_CONTINUE_UNWIND;
305     }
306
307   gnat_exception = (struct _GNAT_Exception *) ue_header;
308
309   START_DB (DB_PHASES);
310   if (gnat_exception->select_cleanups)
311     printf ("(select_cleanups) :\n");
312   else
313     printf (" :\n");
314   END_DB (DB_PHASES);
315
316   language_specific_data
317     = (const unsigned char *) _Unwind_GetLanguageSpecificData (context);
318
319   /* If no LSDA, then there are no handlers or cleanups.  */
320   if (! language_specific_data)
321     {
322       ip = _Unwind_GetIP (context) - 1;
323
324       START_DB (DB_SEARCH);
325       printf ("              No Language Specific Data for ip = %p\n", ip);
326       END_DB (DB_SEARCH);
327       START_DB (DB_FOUND);
328       printf ("              => FOUND nothing\n");
329       END_DB (DB_FOUND);
330       return _URC_CONTINUE_UNWIND;
331     }
332
333   /* Parse the LSDA header.  */
334   p = parse_lsda_header (context, language_specific_data, &info);
335   info.ttype_base = base_of_encoded_value (info.ttype_encoding, context);
336   ip = _Unwind_GetIP (context) - 1;
337   landing_pad = 0;
338   action_record = 0;
339   handler_switch_value = 0;
340
341   /* Search the call-site table for the action associated with this IP.  */
342   while (p < info.action_table)
343     {
344       _Unwind_Ptr cs_start, cs_len, cs_lp;
345       _Unwind_Word cs_action;
346
347       /* Note that all call-site encodings are "absolute" displacements.  */
348       p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
349       p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
350       p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
351       p = read_uleb128 (p, &cs_action);
352
353       /* The table is sorted, so if we've passed the ip, stop.  */
354       if (ip < info.Start + cs_start)
355         p = info.action_table;
356       else if (ip < info.Start + cs_start + cs_len)
357         {
358           if (cs_lp)
359             landing_pad = info.LPStart + cs_lp;
360           if (cs_action)
361             action_record = info.action_table + cs_action - 1;
362           goto found_something;
363         }
364     }
365
366   START_DB (DB_SEARCH);
367   printf ("              No Action entry for ip = %p\n", ip);
368   END_DB (DB_SEARCH);
369
370   /* If ip is not present in the table, call terminate.  This is for
371      a destructor inside a cleanup, or a library routine the compiler
372      was not expecting to throw.
373
374      found_type = 
375      (actions & _UA_FORCE_UNWIND ? found_nothing : found_terminate);
376
377      ??? Does this have a mapping in Ada semantics ?  */
378
379   found_type = found_nothing;
380   goto do_something;
381
382  found_something:
383
384   found_type = found_nothing;
385
386   if (landing_pad == 0)
387     {
388       /* If ip is present, and has a null landing pad, there are
389          no cleanups or handlers to be run.  */
390       START_DB (DB_SEARCH);
391       printf ("              No Landing Pad for ip = %p\n", ip);
392       END_DB (DB_SEARCH);
393     }
394   else if (action_record == 0)
395     {
396       START_DB (DB_SEARCH);
397       printf ("              Null Action Record for ip = %p <===\n", ip);
398       END_DB (DB_SEARCH);
399     }
400   else
401     {
402       signed long ar_filter, ar_disp;
403       signed long cleanup_filter = 0;
404       signed long handler_filter = 0;
405
406       START_DB (DB_SEARCH);
407       printf ("              Landing Pad + Action Record for ip = %p\n", ip);
408       END_DB (DB_SEARCH);
409
410       START_DB (DB_MATCH);
411       printf ("              => Search for exception matching id %p\n", 
412               gnat_exception->id);
413       END_DB (DB_MATCH);
414
415       /* Otherwise we have a catch handler or exception specification.  */
416
417       while (1)
418         {
419           _Unwind_Word tmp;
420
421           p = action_record;
422           p = read_sleb128 (p, &tmp); ar_filter = tmp;
423           read_sleb128 (p, &tmp); ar_disp = tmp;
424
425           START_DB (DB_MATCH);
426           printf ("ar_filter  %d\n", ar_filter);
427           END_DB (DB_MATCH);
428
429           if (ar_filter == 0)
430             {
431               /* Zero filter values are cleanups. We should not be seeing
432                  this for GNU-Ada though
433                  saw_cleanup = true;  */
434               START_DB (DB_SEARCH);
435               printf ("              Null Filter for ip = %p <===\n", ip);
436               END_DB (DB_SEARCH);
437             }
438           else if (ar_filter > 0)
439             {
440               _Unwind_Ptr lp_id = get_ttype_entry (context, &info, ar_filter);
441
442               START_DB (DB_MATCH);
443               printf ("catch_type ");
444
445               switch (lp_id)
446                 {
447                 case GNAT_ALL_OTHERS_ID:
448                   printf ("GNAT_ALL_OTHERS_ID\n");              
449                   break;
450
451                 case GNAT_OTHERS_ID:
452                   printf ("GNAT_OTHERS_ID\n");
453                   break;
454
455                 default:
456                   printf ("%p\n", lp_id);
457                   break;
458                 }
459
460               END_DB (DB_MATCH);
461
462               if (lp_id == GNAT_ALL_OTHERS_ID)
463                 {
464                   START_DB (DB_SAW);
465                   printf ("              => SAW cleanup\n");
466                   END_DB (DB_SAW);
467
468                   cleanup_filter = ar_filter;
469                   gnat_exception->has_cleanup = true;
470                 }
471
472               hit_others_handler
473                 = (lp_id == GNAT_OTHERS_ID
474                    && gnat_exception->handled_by_others);
475
476               if (hit_others_handler || lp_id == gnat_exception->id)
477                 {
478                   START_DB (DB_SAW);
479                   printf ("              => SAW handler\n");
480                   END_DB (DB_SAW);
481
482                   handler_filter = ar_filter;     
483                 }
484             }
485           else
486             /* Negative filter values are for C++ exception specifications.
487                Should not be there for Ada :/  */
488             ;
489
490           if (actions & _UA_SEARCH_PHASE)
491             {
492               if (handler_filter)
493                 {
494                   found_type = found_handler;
495                   handler_switch_value = handler_filter;
496                   break;
497                 }
498
499               if (cleanup_filter)
500                 found_type = found_cleanup;
501             }
502
503           if (actions & _UA_CLEANUP_PHASE)
504             {
505               if (handler_filter)
506                 {
507                   found_type = found_handler;
508                   handler_switch_value = handler_filter;
509                   break;
510                 }
511
512               if (cleanup_filter)
513                 {
514                   found_type = found_cleanup;
515                   handler_switch_value = cleanup_filter;
516                   break;
517                 }
518             }
519
520           if (ar_disp == 0)
521             break;
522
523           action_record = p + ar_disp;
524         }
525     }
526
527  do_something:
528   if (found_type == found_nothing)
529     {
530       START_DB (DB_FOUND);
531       printf ("              => FOUND nothing\n");
532       END_DB (DB_FOUND);
533
534       return _URC_CONTINUE_UNWIND;
535     }
536
537   if (actions & _UA_SEARCH_PHASE)
538     {
539       START_DB (DB_FOUND);
540       printf ("              => Computing return for SEARCH\n");
541       END_DB (DB_FOUND);
542
543       if (found_type == found_cleanup
544           && !gnat_exception->select_cleanups)
545         {
546           START_DB (DB_FOUND);
547           printf ("              => FOUND cleanup\n");
548           END_DB (DB_FOUND);
549
550           return _URC_CONTINUE_UNWIND;
551         }
552
553       START_DB (DB_FOUND);
554       printf ("              => FOUND handler\n");
555       END_DB (DB_FOUND);
556
557       return _URC_HANDLER_FOUND;
558     }
559
560  install_context:
561
562    START_DB (DB_INSTALL);
563    printf ("              => INSTALLING context for filter %d\n",
564            handler_switch_value);
565    END_DB (DB_INSTALL);
566
567    if (found_type == found_terminate)
568      {
569        /* Should not have this for Ada ?  */
570        START_DB (DB_INSTALL);
571        printf ("              => FOUND terminate <===\n");
572        END_DB (DB_INSTALL);
573      }
574
575
576    /* Signal that we are going to enter a handler, which will typically
577       enable the debugger to take control and possibly output an automatic
578       backtrace. Note that we are supposed to provide the handler's entry
579       point here but we don't have it.  */
580   __gnat_notify_handled_exception ((void *)landing_pad, hit_others_handler,
581                                    true);
582
583    /* The GNU-Ada exception handlers know how to find the exception
584       occurrence without having to pass it as an argument so there
585       is no need to feed any specific register with this information.
586
587       This is why the two following lines are commented out.  */
588
589    /* _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
590       (_Unwind_Ptr) &xh->unwindHeader);  */
591
592   _Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
593                  handler_switch_value);
594
595   _Unwind_SetIP (context, landing_pad);
596
597   return _URC_INSTALL_CONTEXT;
598 }
599
600
601 #else   /* IN_RTS - For eh personality routine   */
602
603 /* The calls to the GCC runtime interface for exception raising are currently
604    issued from a-except.adb, which is used by both the runtime library and
605    the compiler. As the compiler binary is not linked against the GCC runtime
606    library, we need a stub for this interface in the compiler case.  */
607
608
609 _Unwind_Reason_Code
610 _Unwind_RaiseException (e)
611      struct _Unwind_Exception *e ATTRIBUTE_UNUSED;
612 {
613   /* Since we don't link the compiler with a host libgcc, we should not be
614      using the GCC eh mechanism for the compiler and so expect this function
615      never to be called.  */
616   abort ();
617 }
618
619 #endif