OSDN Git Service

gcc
[pf3gnuchains/gcc-fork.git] / gcc / ada / raise-gcc.c
index 3100af3..b30145a 100644 (file)
@@ -6,24 +6,23 @@
  *                                                                          *
  *                          C Implementation File                           *
  *                                                                          *
- *             Copyright (C) 1992-2005, Free Software Foundation, Inc.      *
+ *             Copyright (C) 1992-2009, Free Software Foundation, Inc.      *
  *                                                                          *
  * GNAT is free software;  you can  redistribute it  and/or modify it under *
  * terms of the  GNU General Public License as published  by the Free Soft- *
- * ware  Foundation;  either version 2,  or (at your option) any later ver- *
+ * ware  Foundation;  either version 3,  or (at your option) any later ver- *
  * sion.  GNAT is distributed in the hope that it will be useful, but WITH- *
  * OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY *
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License *
- * for  more details.  You should have  received  a copy of the GNU General *
- * Public License  distributed with GNAT;  see file COPYING.  If not, write *
- * to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, *
- * Boston, MA 02110-1301, USA.                                              *
+ * or FITNESS FOR A PARTICULAR PURPOSE.                                     *
  *                                                                          *
- * As a  special  exception,  if you  link  this file  with other  files to *
- * produce an executable,  this file does not by itself cause the resulting *
- * executable to be covered by the GNU General Public License. This except- *
- * ion does not  however invalidate  any other reasons  why the  executable *
- * file might be covered by the  GNU Public License.                        *
+ * As a special exception under Section 7 of GPL version 3, you are granted *
+ * additional permissions described in the GCC Runtime Library Exception,   *
+ * version 3.1, as published by the Free Software Foundation.               *
+ *                                                                          *
+ * You should have received a copy of the GNU General Public License and    *
+ * a copy of the GCC Runtime Library Exception along with this program;     *
+ * see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    *
+ * <http://www.gnu.org/licenses/>.                                          *
  *                                                                          *
  * GNAT was originally developed  by the GNAT team at  New York University. *
  * Extensive contributions were provided by Ada Core Technologies Inc.      *
@@ -35,6 +34,7 @@
 
 #ifdef IN_RTS
 #include "tconfig.h"
+#include "tsystem.h"
 /* In the top-of-tree GCC, tconfig does not include tm.h, but in GCC 3.2
    it does.  To avoid branching raise.c just for that purpose, we kludge by
    looking for a symbol always defined by tm.h and if it's not defined,
@@ -43,7 +43,6 @@
 #include "coretypes.h"
 #include "tm.h"
 #endif
-#include "tsystem.h"
 #include <sys/stat.h>
 #include <stdarg.h>
 typedef char bool;
@@ -97,7 +96,7 @@ __gnat_Unwind_ForcedUnwind (_Unwind_Exception *, void *, void *);
 
 #ifdef IN_RTS   /* For eh personality routine */
 
-#include "dwarf2.h"
+#include "elf/dwarf2.h"
 #include "unwind-dw2-fde.h"
 #include "unwind-pe.h"
 
@@ -362,7 +361,7 @@ db_phases (int phases)
    context stack and not the actual call chain.
 
    The ACTION and TTYPES tables remain unchanged, which allows to search them
-   during the propagation phase to determine wether or not the propagated
+   during the propagation phase to determine whether or not the propagated
    exception is handled somewhere. When it is, we only "jump" up once directly
    to the context where the handler will be found. Besides, this allows "break
    exception unhandled" to work also
@@ -540,7 +539,7 @@ get_region_description_for (_Unwind_Context *uw_context,
                             region_descriptor *region)
 {
   const unsigned char * p;
-  _Unwind_Word tmp;
+  _uleb128_t tmp;
   unsigned char lpbase_encoding;
 
   /* Get the base address of the lsda information. If the provided context
@@ -663,16 +662,21 @@ db_action_for (action_descriptor *action, _Unwind_Context *uw_context)
   return;
 }
 
-
 /* Search the call_site_table of REGION for an entry appropriate for the
-   UW_CONTEXT's ip. If one is found, store the associated landing_pad and
-   action_table entry, and set the ACTION kind to unknown for further
-   analysis. Otherwise, set the ACTION kind to nothing.
+   UW_CONTEXT's IP.  If one is found, store the associated landing_pad
+   and action_table entry, and set the ACTION kind to unknown for further
+   analysis.  Otherwise, set the ACTION kind to nothing.
 
    There are two variants of this routine, depending on the underlying
-   mechanism (dwarf/sjlj), which account for differences in the tables
-   organization.
-*/
+   mechanism (DWARF/SJLJ), which account for differences in the tables.  */
+
+#ifdef __APPLE__
+/* On MacOS X, versions older than 10.5 don't export _Unwind_GetIPInfo.  */
+#undef HAVE_GETIPINFO
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
+#define HAVE_GETIPINFO 1
+#endif
+#endif
 
 #ifdef __USING_SJLJ_EXCEPTIONS__
 
@@ -683,14 +687,21 @@ get_call_site_action_for (_Unwind_Context *uw_context,
                           region_descriptor *region,
                           action_descriptor *action)
 {
-  _Unwind_Ptr call_site
-    = _Unwind_GetIP (uw_context) - 1;
-  /* Subtract 1 because GetIP returns the actual call_site value + 1.  */
+  int ip_before_insn = 0;
+#ifdef HAVE_GETIPINFO
+  _Unwind_Ptr call_site = _Unwind_GetIPInfo (uw_context, &ip_before_insn);
+#else
+  _Unwind_Ptr call_site = _Unwind_GetIP (uw_context);
+#endif
+  /* Subtract 1 if necessary because GetIPInfo returns the actual call site
+     value + 1 in this case.  */
+  if (!ip_before_insn)
+    call_site--;
 
   /* call_site is a direct index into the call-site table, with two special
-     values : -1 for no-action and 0 for "terminate". The latter should never
-     show up for Ada. To test for the former, beware that _Unwind_Ptr might be
-     unsigned.  */
+     values : -1 for no-action and 0 for "terminate".  The latter should never
+     show up for Ada.  To test for the former, beware that _Unwind_Ptr might
+     be unsigned.  */
 
   if ((int)call_site < 0)
     {
@@ -705,25 +716,24 @@ get_call_site_action_for (_Unwind_Context *uw_context,
     }
   else
     {
-      _Unwind_Word cs_lp, cs_action;
+      _uleb128_t cs_lp, cs_action;
 
       /* Let the caller know there may be an action to take, but let it
         determine the kind.  */
       action->kind = unknown;
 
       /* We have a direct index into the call-site table, but this table is
-        made of leb128 values, the encoding length of which is variable. We
+        made of leb128 values, the encoding length of which is variable.  We
         can't merely compute an offset from the index, then, but have to read
         all the entries before the one of interest.  */
 
-      const unsigned char * p = region->call_site_table;
+      const unsigned char *p = region->call_site_table;
 
       do {
        p = read_uleb128 (p, &cs_lp);
        p = read_uleb128 (p, &cs_action);
       } while (--call_site);
 
-
       action->landing_pad = cs_lp + 1;
 
       if (cs_action)
@@ -735,29 +745,28 @@ get_call_site_action_for (_Unwind_Context *uw_context,
     }
 }
 
-#else
-/* ! __USING_SJLJ_EXCEPTIONS__ */
+#else /* !__USING_SJLJ_EXCEPTIONS__  */
 
 static void
 get_call_site_action_for (_Unwind_Context *uw_context,
                           region_descriptor *region,
                           action_descriptor *action)
 {
-  _Unwind_Ptr ip
-    = _Unwind_GetIP (uw_context) - 1;
-  /* Subtract 1 because GetIP yields a call return address while we are
-     interested in information for the call point. This does not always yield
-     the exact call instruction address but always brings the ip back within
-     the corresponding region.
-
-     ??? When unwinding up from a signal handler triggered by a trap on some
-     instruction, we usually have the faulting instruction address here and
-     subtracting 1 might get us into the wrong region.  */
-
-  const unsigned char * p
-    = region->call_site_table;
-
-  /* Unless we are able to determine otherwise ... */
+  const unsigned char *p = region->call_site_table;
+  int ip_before_insn = 0;
+#ifdef HAVE_GETIPINFO
+  _Unwind_Ptr ip = _Unwind_GetIPInfo (uw_context, &ip_before_insn);
+#else
+  _Unwind_Ptr ip = _Unwind_GetIP (uw_context);
+#endif
+  /* Subtract 1 if necessary because GetIPInfo yields a call return address
+     in this case, while we are interested in information for the call point.
+     This does not always yield the exact call instruction address but always
+     brings the IP back within the corresponding region.  */
+  if (!ip_before_insn)
+    ip--;
+
+  /* Unless we are able to determine otherwise...  */
   action->kind = nothing;
 
   db (DB_CSITE, "\n");
@@ -765,7 +774,7 @@ get_call_site_action_for (_Unwind_Context *uw_context,
   while (p < region->action_table)
     {
       _Unwind_Ptr cs_start, cs_len, cs_lp;
-      _Unwind_Word cs_action;
+      _uleb128_t cs_action;
 
       /* Note that all call-site encodings are "absolute" displacements.  */
       p = read_encoded_value (0, region->call_site_encoding, p, &cs_start);
@@ -778,7 +787,7 @@ get_call_site_action_for (_Unwind_Context *uw_context,
          region->base+cs_start, cs_start, cs_len,
          region->lp_base+cs_lp, cs_lp);
 
-      /* The table is sorted, so if we've passed the ip, stop.  */
+      /* The table is sorted, so if we've passed the IP, stop.  */
       if (ip < region->base + cs_start)
        break;
 
@@ -807,11 +816,11 @@ get_call_site_action_for (_Unwind_Context *uw_context,
   db (DB_CSITE, "---\n");
 }
 
-#endif
+#endif /* __USING_SJLJ_EXCEPTIONS__  */
 
 /* With CHOICE an exception choice representing an "exception - when"
    argument, and PROPAGATED_EXCEPTION a pointer to the currently propagated
-   occurrence, return true iif the latter matches the former, that is, if
+   occurrence, return true if the latter matches the former, that is, if
    PROPAGATED_EXCEPTION is caught by the handling code controlled by CHOICE.
    This takes care of the special Non_Ada_Error case on VMS.  */
 
@@ -913,7 +922,7 @@ get_action_description_for (_Unwind_Context *uw_context,
     {
       const unsigned char * p = action->table_entry;
 
-      _Unwind_Sword ar_filter, ar_disp;
+      _sleb128_t ar_filter, ar_disp;
 
       action->kind = nothing;
 
@@ -1004,20 +1013,83 @@ extern void __gnat_notify_unhandled_exception (void);
 /* Below is the eh personality routine per se. We currently assume that only
    GNU-Ada exceptions are met.  */
 
+#ifdef __USING_SJLJ_EXCEPTIONS__
+#define PERSONALITY_FUNCTION    __gnat_eh_personality_sj
+#else
+#define PERSONALITY_FUNCTION    __gnat_eh_personality
+#endif
+
+/* Major tweak for ia64-vms : the CHF propagation phase calls this personality
+   routine with sigargs/mechargs arguments and has very specific expectations
+   on possible return values.
+
+   We handle this with a number of specific tricks:
+
+   1. We tweak the personality routine prototype to have the "version" and
+      "phases" two first arguments be void * instead of int and _Unwind_Action
+      as nominally expected in the GCC context.
+
+      This allows us to access the full range of bits passed in every case and
+      has no impact on the callers side since each argument remains assigned
+      the same single 64bit slot.
+
+   2. We retrieve the corresponding int and _Unwind_Action values within the
+      routine for regular use with truncating conversions. This is a noop when
+      called from the libgcc unwinder.
+
+   3. We assume we're called by the VMS CHF when unexpected bits are set in
+      both those values. The incoming arguments are then real sigargs and
+      mechargs pointers, which we then redirect to __gnat_handle_vms_condition
+      for proper processing.
+*/
+#if defined (VMS) && defined (__IA64)
+typedef void * version_arg_t;
+typedef void * phases_arg_t;
+#else
+typedef int version_arg_t;
+typedef _Unwind_Action phases_arg_t;
+#endif
+
 _Unwind_Reason_Code
-__gnat_eh_personality (int uw_version,
-                       _Unwind_Action uw_phases,
-                       _Unwind_Exception_Class uw_exception_class,
-                       _Unwind_Exception *uw_exception,
-                       _Unwind_Context *uw_context)
+PERSONALITY_FUNCTION (version_arg_t version_arg,
+                      phases_arg_t phases_arg,
+                      _Unwind_Exception_Class uw_exception_class,
+                      _Unwind_Exception *uw_exception,
+                      _Unwind_Context *uw_context)
 {
+  /* Fetch the version and phases args with their nominal ABI types for later
+     use. This is a noop everywhere except on ia64-vms when called from the
+     Condition Handling Facility.  */
+  int uw_version = (int) version_arg;
+  _Unwind_Action uw_phases = (_Unwind_Action) phases_arg;
+
   _GNAT_Exception * gnat_exception = (_GNAT_Exception *) uw_exception;
 
   region_descriptor region;
   action_descriptor action;
 
+  /* Check that we're called from the ABI context we expect, with a major
+     possible variation on VMS for IA64.  */
   if (uw_version != 1)
-    return _URC_FATAL_PHASE1_ERROR;
+    {
+      #if defined (VMS) && defined (__IA64)
+
+      /* Assume we're called with sigargs/mechargs arguments if really
+        unexpected bits are set in our first two formals.  Redirect to the
+        GNAT condition handling code in this case.  */
+
+      extern long __gnat_handle_vms_condition (void *, void *);
+
+      unsigned int version_unexpected_bits_mask = 0xffffff00U;
+      unsigned int phases_unexpected_bits_mask  = 0xffffff00U;
+
+      if ((unsigned int)uw_version & version_unexpected_bits_mask
+         && (unsigned int)uw_phases & phases_unexpected_bits_mask)
+       return __gnat_handle_vms_condition (version_arg, phases_arg);
+      #endif
+
+      return _URC_FATAL_PHASE1_ERROR;
+    }
 
   db_indent (DB_INDENT_RESET);
   db_phases (uw_phases);
@@ -1072,7 +1144,7 @@ __gnat_eh_personality (int uw_version,
   /* If we are going to install a cleanup context, decrement the cleanup
      count.  This is required in a FORCED_UNWINDing phase (for an unhandled
      exception), as this is used from the forced unwinding handler in
-     Ada.Exceptions.Exception_Propagation to decide wether unwinding should
+     Ada.Exceptions.Exception_Propagation to decide whether unwinding should
      proceed further or Unhandled_Exception_Terminate should be called.  */
   if (action.kind == cleanup)
     Adjust_N_Cleanups_For (gnat_exception, -1);