fde-vms.c: New file.
authorDouglas B Rupp <rupp@gnat.com>
Fri, 14 Aug 2009 20:56:31 +0000 (20:56 +0000)
committerDouglas Rupp <rupp@gcc.gnu.org>
Fri, 14 Aug 2009 20:56:31 +0000 (20:56 +0000)
2009-08-14  Douglas B Rupp  <rupp@gnat.com>

* config/ia64/fde-vms.c: New file.
* config/ia64/fde-glibc.c (_Unwind_FindTableEntry): Add dummy arg.
* config/ia64/unwind-ia64.c (UNW_ accessors): Move to unwind-ia64.h
(MD_UNW_COMPATIBLE_PERSONALITY_P): Provide default.
(uw_frame_state_for): Only register a personality routine if it is
known to be compatible with our expectations.
(_Unwind_FindEnclosingFunction, uw_frame_state_for):
Declare unw_table_entry stack variable and
mod all calls to _Unwind_FindTableEntry to add arg.
* config/ia64/unwind-ia64.h (UNW_ accessors): Move here.
(_Unwind_FindTableEntry): Add arg to prototype.

From-SVN: r150778

gcc/ChangeLog
gcc/config/ia64/fde-glibc.c
gcc/config/ia64/fde-vms.c [new file with mode: 0644]
gcc/config/ia64/unwind-ia64.c
gcc/config/ia64/unwind-ia64.h

index d2f328e..48e9663 100644 (file)
@@ -1,3 +1,17 @@
+2009-08-14  Douglas B Rupp  <rupp@gnat.com>
+
+       * config/ia64/fde-vms.c: New file.
+       * config/ia64/fde-glibc.c (_Unwind_FindTableEntry): Add dummy arg.
+       * config/ia64/unwind-ia64.c (UNW_ accessors): Move to unwind-ia64.h
+       (MD_UNW_COMPATIBLE_PERSONALITY_P): Provide default.
+       (uw_frame_state_for): Only register a personality routine if it is
+       known to be compatible with our expectations.
+       (_Unwind_FindEnclosingFunction, uw_frame_state_for):
+       Declare unw_table_entry stack variable and
+       mod all calls to _Unwind_FindTableEntry to add arg.
+       * config/ia64/unwind-ia64.h (UNW_ accessors): Move here.
+       (_Unwind_FindTableEntry): Add arg to prototype.
+
 2009-08-14  Eric Botcazou  <ebotcazou@adacore.com>
 
        * config/ia64/unwind-ia64.c (struct _Unwind_Context): Add new
index 540beab..12760b9 100644 (file)
@@ -145,7 +145,8 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
 
 struct unw_table_entry *
 _Unwind_FindTableEntry (void *pc, unsigned long *segment_base,
-                        unsigned long *gp)
+                        unsigned long *gp,
+                        struct unw_table_entry *ent ATTRIBUTE_UNUSED)
 {
   struct unw_ia64_callback_data data;
 
diff --git a/gcc/config/ia64/fde-vms.c b/gcc/config/ia64/fde-vms.c
new file mode 100644 (file)
index 0000000..b310f0d
--- /dev/null
@@ -0,0 +1,157 @@
+/* Copyright (C) 2004, 2009 Free Software Foundation, Inc.
+   Contributed by Douglas B Rupp <rupp@gnat.com>
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   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/>.  */
+
+/* Locate the FDE entry for a given address, using VMS Starlet routines
+   to avoid register/deregister calls at DSO load/unload.  */
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "coretypes.h"
+#include "tm.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "unwind-ia64.h"
+
+#define __int64 long
+#include <vms/ossddef.h>
+#ifndef SS$_NORMAL
+#define SS$_NORMAL 1
+#endif
+
+typedef struct
+{
+  unsigned long start_offset;
+  unsigned long end_offset;
+  unsigned long info_offset;
+  unsigned long gp_value;
+}  vms_unw_table_entry;
+
+typedef unsigned long long uqword;
+
+/* ENTRY is the unwind table entry found for a PC part of call chain we're
+   unwinding through.  Return whether we should force the generic unwinder
+   to resort to "fallback" processing.  */
+   
+static int
+force_fallback_processing_for (void * pc, vms_unw_table_entry * entry)
+{
+  static int eh_debug = -1;
+
+  uqword * unw_info_block = (uqword *)entry->info_offset;
+  uqword header = *unw_info_block;
+
+  /* We need to force fallback processing in two cases:
+
+     1/ The exception dispatch frame, since only our fallback
+        processing knows how to properly unwind through it, and
+
+     2/ A bottom of stack frame, since only our fallback processing
+        will ensure we don't try to unwind further past it, which
+        would get us into unknown territory and likely cause a severe
+        crash along the way.
+
+     The two cases are indicated by non-default values for specific
+     bits in the OS Specific Data (OSSD) General Information block
+     associated with such frames.  */
+
+  ossddef * ossd;
+
+  if (eh_debug == -1)
+    {
+      char * EH_DEBUG = getenv ("EH_DEBUG");
+      eh_debug = EH_DEBUG ? atoi (EH_DEBUG) : 0;
+    }
+
+  if (eh_debug)
+    {
+      printf ("pc @ 0x%p, block @ 0x%p, header = 0x%016llx\n",
+             pc, unw_info_block, header);
+      printf ("mode = %d, length = %ld, handler = %d\n",
+             (int)UNW_IVMS_MODE (header), UNW_LENGTH (header),
+             UNW_FLAG_EHANDLER (header) || UNW_FLAG_EHANDLER (header));
+    }
+
+  /* An OSSD block is there for IVMS_MODE == 3 only.  */
+  if (UNW_IVMS_MODE (header) != 3)
+    return 0;
+
+  /* The OSSD block is found past the header, unwind descriptor area
+     and condition handler pointer, if any.  */  
+  ossd = (ossddef *)
+    /* Beware: uqword pointer arithmetic below.  */
+    (unw_info_block
+     + 1
+     + UNW_LENGTH (header)
+     + (UNW_FLAG_EHANDLER (header) || UNW_FLAG_EHANDLER (header)));
+
+  /* "A General Information segment may be omitted if all of its fields
+      would have their default values.  If a General Information segment
+      is present, it must be the first in the OSSD area."  So ...  */
+  
+  if (eh_debug)
+    printf ("ossd @ 0x%p\n", ossd);
+      
+  if (eh_debug && ossd->ossd$v_type == OSSD$K_GENERAL_INFO)
+    printf ("exc_frame = %d - bot_frame = %d - base_frame = %d\n",
+           ossd->ossd$v_exception_frame, 
+           ossd->ossd$v_bottom_of_stack,
+           ossd->ossd$v_base_frame);
+                               
+  return
+    ossd->ossd$v_type == OSSD$K_GENERAL_INFO
+    && (ossd->ossd$v_exception_frame
+       || ossd->ossd$v_bottom_of_stack || ossd->ossd$v_base_frame);
+}
+
+/* Return a pointer to the unwind table entry for the function
+   containing PC, 0 if we cannot find an entry or if the one we find
+   calls for fallback processing.  */
+
+struct unw_table_entry *
+_Unwind_FindTableEntry (void *pc, unsigned long *segment_base,
+                        unsigned long *gp, struct unw_table_entry *ent)
+{
+  vms_unw_table_entry vueblock;
+
+  if (SYS$GET_UNWIND_ENTRY_INFO (pc, &vueblock, 0) != SS$_NORMAL)
+    return 0;
+
+  /* If there is no unwind information, use fallback.  */
+  if (vueblock.info_offset == 0)
+    return 0;
+
+  /* If we need to force fallback processing, just pretend there is
+     no entry.  */
+  if (force_fallback_processing_for (pc, &vueblock))
+    return 0;
+
+  *segment_base = 0; /* ??? Fixme. ??? */
+  *gp = vueblock.gp_value;
+  ent->start_offset = vueblock.start_offset;
+  ent->end_offset = vueblock.end_offset;
+  ent->info_offset = vueblock.info_offset;
+
+  return ent;
+}
index 8e62f32..3425858 100644 (file)
 
 #ifndef __USING_SJLJ_EXCEPTIONS__
 
-#define UNW_VER(x)             ((x) >> 48)
-#define UNW_FLAG_MASK          0x0000ffff00000000
-#define UNW_FLAG_OSMASK                0x0000f00000000000
-#define UNW_FLAG_EHANDLER(x)   ((x) & 0x0000000100000000L)
-#define UNW_FLAG_UHANDLER(x)   ((x) & 0x0000000200000000L)
-#define UNW_LENGTH(x)          ((x) & 0x00000000ffffffffL)
+
+/* By default, assume personality routine interface compatibility with
+   our expectations.  */
+#ifndef MD_UNW_COMPATIBLE_PERSONALITY_P
+#define MD_UNW_COMPATIBLE_PERSONALITY_P(HEADER) 1
+#endif
 
 enum unw_application_register
 {
@@ -442,7 +442,13 @@ decode_abreg (unsigned char abreg, int memory)
 {
   switch (abreg)
     {
+#if TARGET_ABI_OPEN_VMS
+    /* OpenVMS Calling Standard specifies R3 - R31.  */
+    case 0x03 ... 0x1f: return UNW_REG_R2 + (abreg - 0x02);
+#else
+    /* Standard Intel ABI specifies GR 4 - 7.  */
     case 0x04 ... 0x07: return UNW_REG_R4 + (abreg - 0x04);
+#endif
     case 0x22 ... 0x25: return UNW_REG_F2 + (abreg - 0x22);
     case 0x30 ... 0x3f: return UNW_REG_F16 + (abreg - 0x30);
     case 0x41 ... 0x45: return UNW_REG_B1 + (abreg - 0x41);
@@ -1733,14 +1739,14 @@ _Unwind_GetRegionStart (struct _Unwind_Context *context)
 void *
 _Unwind_FindEnclosingFunction (void *pc)
 {
-  struct unw_table_entry *ent;
+  struct unw_table_entry *entp, ent;
   unsigned long segment_base, gp;
 
-  ent = _Unwind_FindTableEntry (pc, &segment_base, &gp);
-  if (ent == NULL)
+  entp = _Unwind_FindTableEntry (pc, &segment_base, &gp, &ent);
+  if (entp == NULL)
     return NULL;
   else
-    return (void *)(segment_base + ent->start_offset);
+    return (void *)(segment_base + entp->start_offset);
 }
 
 /* Get the value of the CFA as saved in CONTEXT.  In GCC/Dwarf2 parlance,
@@ -1768,7 +1774,7 @@ _Unwind_GetBSP (struct _Unwind_Context *context)
 static _Unwind_Reason_Code
 uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
 {
-  struct unw_table_entry *ent;
+  struct unw_table_entry *entp, ent;
   unsigned long *unw, header, length;
   unsigned char *insn, *insn_end;
   unsigned long segment_base;
@@ -1779,9 +1785,9 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
     r->when = UNW_WHEN_NEVER;
   context->lsda = 0;
 
-  ent = _Unwind_FindTableEntry ((void *) context->rp,
-                               &segment_base, &context->gp);
-  if (ent == NULL)
+  entp = _Unwind_FindTableEntry ((void *) context->rp,
+                               &segment_base, &context->gp, &ent);
+  if (entp == NULL)
     {
       /* Couldn't find unwind info for this function.  Try an
         os-specific fallback mechanism.  This will necessarily
@@ -1806,17 +1812,34 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
       return _URC_END_OF_STACK;
     }
 
-  context->region_start = ent->start_offset + segment_base;
+  context->region_start = entp->start_offset + segment_base;
   fs->when_target = ((context->rp & -16) - context->region_start) / 16 * 3
                    + (context->rp & 15);
 
-  unw = (unsigned long *) (ent->info_offset + segment_base);
+  unw = (unsigned long *) (entp->info_offset + segment_base);
   header = *unw;
   length = UNW_LENGTH (header);
 
-  /* ??? Perhaps check UNW_VER / UNW_FLAG_OSMASK.  */
+  /* Some operating systems use the personality routine slot in way not
+     compatible with what we expect.  For instance, OpenVMS uses this slot to
+     designate "condition handlers" with very different arguments than what we
+     would be providing.  Such cases are typically identified from OS specific
+     bits in the unwind information block header, and checked by the target
+     MD_UNW_COMPATIBLE_PERSONALITY_P macro. 
+
+     We just pretend there is no personality from our standpoint in such
+     situations, and expect GCC not to set the identifying bits itself so that
+     compatible personalities for GCC compiled code are called.
+
+     Of course, this raises the question of what combinations of native/GCC
+     calls can be expected to behave properly exception handling-wise.  We are
+     not to provide a magic answer here, merely to prevent crashes assuming
+     users know what they are doing.
+
+     ??? Perhaps check UNW_VER / UNW_FLAG_OSMASK as well.  */
 
-  if (UNW_FLAG_EHANDLER (header) | UNW_FLAG_UHANDLER (header))
+  if (MD_UNW_COMPATIBLE_PERSONALITY_P (header)
+      && (UNW_FLAG_EHANDLER (header) | UNW_FLAG_UHANDLER (header)))
     {
       fs->personality =
        *(_Unwind_Personality_Fn *) (unw[length + 1] + context->gp);
index f383214..b98f048 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2000, 2001, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2000, 2001, 2007, 2009 Free Software Foundation, Inc.
    Contributed by Andrew MacLeod  <amacleod@cygnus.com>
                   Andrew Haley  <aph@cygnus.com>
 
@@ -25,7 +25,19 @@ struct unw_table_entry
   unsigned long info_offset;
 };
 
+/* Accessors to fields of an unwind info block header.  In this common file to
+   be visible from all the units involved in a target implementation.  */
+   
+#ifndef __USING_SJLJ_EXCEPTIONS__
+#define UNW_VER(x)             ((x) >> 48)
+#define UNW_FLAG_MASK          0x0000ffff00000000
+#define UNW_FLAG_OSMASK                0x0000f00000000000
+#define UNW_FLAG_EHANDLER(x)   ((x) & 0x0000000100000000L)
+#define UNW_FLAG_UHANDLER(x)   ((x) & 0x0000000200000000L)
+#define UNW_LENGTH(x)          ((x) & 0x00000000ffffffffL)
+#endif
+
 extern struct unw_table_entry *
 _Unwind_FindTableEntry (void *pc, unsigned long *segment_base,
-                       unsigned long *gp)
+                       unsigned long *gp, struct unw_table_entry *ent)
                        __attribute__ ((__visibility__ ("hidden")));