+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
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;
--- /dev/null
+/* 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;
+}
#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
{
{
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);
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,
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;
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
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);
-/* 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>
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")));