This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] VMS specific signal handling for IA64


NOTE: http://gcc.gnu.org/ml/gcc-patches/2005-11/msg00597.html
must be applied first. VMS exhibits the same problem.

--Douglas B Rupp
AdaCore
2009-07-29  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.

--- /dev/null	2005-11-30 16:42:54.000000000 -0800
+++ gcc/config/ia64/fde-vms.c	2009-07-15 18:51:28.000000000 -0700
@@ -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;
+}
--- gcc/config/ia64/fde-glibc.c	2009-04-09 08:00:19.000000000 -0700
+++ gcc/config/ia64/fde-glibc.c	2009-07-14 16:35:39.000000000 -0700
@@ -145,7 +145,8 @@ _Unwind_IteratePhdrCallback (struct dl_p
 
 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;
 
--- gcc/config/ia64/unwind-ia64.c	2009-07-16 13:51:27.145529853 -0700
+++ gcc/config/ia64/unwind-ia64.c	2009-07-14 16:35:39.000000000 -0700
@@ -41,12 +41,12 @@
 
 #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 m
 {
   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_C
 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 *
 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_Conte
     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_Conte
       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);
--- gcc/config/ia64/unwind-ia64.h	2007-08-02 18:43:46.000000000 -0700
+++ gcc/config/ia64/unwind-ia64.h	2009-07-14 16:35:39.000000000 -0700
@@ -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")));

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]