raise-gcc.c (__gnat_eh_personality): Tweak the signature and add special code on...
authorOlivier Hainque <hainque@adacore.com>
Wed, 6 Jun 2007 10:45:25 +0000 (12:45 +0200)
committerArnaud Charlet <charlet@gcc.gnu.org>
Wed, 6 Jun 2007 10:45:25 +0000 (12:45 +0200)
2007-04-20  Olivier Hainque  <hainque@adacore.com>

* raise-gcc.c (__gnat_eh_personality): Tweak the signature and add
special code on ia64-vms to handle major incompatibilities between the
GCC unwinding ABI and the VMS Condition Handling Facility, both calling
this routine with a very different set of arguments and expectations on
the return value.

From-SVN: r125455

gcc/ada/raise-gcc.c

index b7af4c54925b3df6ca1c5dd3846b22892073e2ba..e6879f7a8268ba75d03bd9607d61cd6763e2b9e1 100644 (file)
@@ -6,7 +6,7 @@
  *                                                                          *
  *                          C Implementation File                           *
  *                                                                          *
- *             Copyright (C) 1992-2005, Free Software Foundation, Inc.      *
+ *             Copyright (C) 1992-2007, 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- *
@@ -1004,20 +1004,77 @@ 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.  */
 
+/* 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,
+__gnat_eh_personality (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);