diff options
Diffstat (limited to 'libgcc/config/ia64/fde-vms.c')
-rw-r--r-- | libgcc/config/ia64/fde-vms.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/libgcc/config/ia64/fde-vms.c b/libgcc/config/ia64/fde-vms.c new file mode 100644 index 00000000000..c9ac5d28076 --- /dev/null +++ b/libgcc/config/ia64/fde-vms.c @@ -0,0 +1,158 @@ +/* Copyright (C) 2004, 2009, 2011 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 "md-unwind-support.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; +} |