diff options
author | Douglas B Rupp <rupp@gnat.com> | 2009-08-14 20:56:31 +0000 |
---|---|---|
committer | Douglas Rupp <rupp@gcc.gnu.org> | 2009-08-14 20:56:31 +0000 |
commit | b874a90d6dda3e9e841025329f1468268bcaccdf (patch) | |
tree | 319444e3ded8f724a8045ece29a0ef9a4e3deb1d /gcc/config/ia64 | |
parent | ac77b88e5267498679463fb578fe89ba973977e2 (diff) | |
download | gcc-b874a90d6dda3e9e841025329f1468268bcaccdf.zip gcc-b874a90d6dda3e9e841025329f1468268bcaccdf.tar.gz gcc-b874a90d6dda3e9e841025329f1468268bcaccdf.tar.bz2 |
fde-vms.c: New file.
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
Diffstat (limited to 'gcc/config/ia64')
-rw-r--r-- | gcc/config/ia64/fde-glibc.c | 3 | ||||
-rw-r--r-- | gcc/config/ia64/fde-vms.c | 157 | ||||
-rw-r--r-- | gcc/config/ia64/unwind-ia64.c | 59 | ||||
-rw-r--r-- | gcc/config/ia64/unwind-ia64.h | 16 |
4 files changed, 214 insertions, 21 deletions
diff --git a/gcc/config/ia64/fde-glibc.c b/gcc/config/ia64/fde-glibc.c index 540beab..12760b9 100644 --- a/gcc/config/ia64/fde-glibc.c +++ b/gcc/config/ia64/fde-glibc.c @@ -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 index 0000000..b310f0d --- /dev/null +++ b/gcc/config/ia64/fde-vms.c @@ -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; +} diff --git a/gcc/config/ia64/unwind-ia64.c b/gcc/config/ia64/unwind-ia64.c index 8e62f32..3425858 100644 --- a/gcc/config/ia64/unwind-ia64.c +++ b/gcc/config/ia64/unwind-ia64.c @@ -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 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); diff --git a/gcc/config/ia64/unwind-ia64.h b/gcc/config/ia64/unwind-ia64.h index f383214..b98f048 100644 --- a/gcc/config/ia64/unwind-ia64.h +++ b/gcc/config/ia64/unwind-ia64.h @@ -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"))); |