From 221cf9abf3a9f446a4ab9bcf7534f81ef0d1d4e6 Mon Sep 17 00:00:00 2001 From: Olivier Hainque Date: Mon, 10 Aug 2009 04:38:02 +0000 Subject: [PATCH] alpha.c (struct machine_function): New flag for VMS, uses_condition_handler. * config/alpha/alpha.c (struct machine_function): New flag for VMS, uses_condition_handler. (alpha_expand_builtin_establish_vms_condition_handler): New expander. (alpha_expand_builtin_revert_vms_condition_handler): New expander. (enum alpha_builtin): New ALPHA_BUILTIN_REVERT_VMS_CONDITION_HANDLER and ALPHA_BUILTIN_ESTABLISH_VMS_CONDITION_HANDLER values. (code_for_builtin): New insn codes for the new alpha_builtins. (alpha_init_builtins): Register the new functions as BUILT_IN_MD. (alpha_sa_size): Account for uses_condition_handler. (alpha_expand_prologue): Likewise. (alpha_start_function): Likewise. (alpha_expand_epilogue): Likewise. * config/alpha/alpha-protos.h: Prototype the new alpha.c builtin establish/revert expanders. * config/alpha/alpha.h (DWARF_FRAME_REGNUM): Define. * config/alpha/alpha.md (builtin_establish_vms_condition_handler): New expander, resorting to the alpha.c associated function. (builtin_revert_vms_condition_handler): Likewise. * config/alpha/vms-gcc_shell_handler.c: New file. Implements __gcc_shell_handler, the static VMS condition handler used as an indirection wrapper to the current dynamically established handler. * config/alpha/vms-unwind.h: Complete rewrite. * config/alpha/t-vms (LIB2FUNCS_EXTRA): Add vms-gcc_shell_handler.c * config/alpha/vms.h (MD_UNWIND_SUPPORT): Co-Authored-By: Douglas B Rupp From-SVN: r150612 --- gcc/ChangeLog | 29 +++ gcc/config/alpha/alpha-protos.h | 3 + gcc/config/alpha/alpha.c | 105 +++++++++- gcc/config/alpha/alpha.h | 6 + gcc/config/alpha/alpha.md | 18 ++ gcc/config/alpha/t-vms | 2 + gcc/config/alpha/vms-gcc_shell_handler.c | 124 ++++++++++++ gcc/config/alpha/vms-unwind.h | 332 +++++++++++++++++++++++++------ gcc/config/alpha/vms.h | 6 + 9 files changed, 563 insertions(+), 62 deletions(-) create mode 100644 gcc/config/alpha/vms-gcc_shell_handler.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7028cbd..f9f6ac7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,32 @@ +2009-08-09 Olivier Hainque + Douglas B Rupp + + * config/alpha/alpha.c (struct machine_function): New flag for VMS, + uses_condition_handler. + (alpha_expand_builtin_establish_vms_condition_handler): New expander. + (alpha_expand_builtin_revert_vms_condition_handler): New expander. + (enum alpha_builtin): New ALPHA_BUILTIN_REVERT_VMS_CONDITION_HANDLER + and ALPHA_BUILTIN_ESTABLISH_VMS_CONDITION_HANDLER values. + (code_for_builtin): New insn codes for the new alpha_builtins. + (alpha_init_builtins): Register the new functions as BUILT_IN_MD. + (alpha_sa_size): Account for uses_condition_handler. + (alpha_expand_prologue): Likewise. + (alpha_start_function): Likewise. + (alpha_expand_epilogue): Likewise. + * config/alpha/alpha-protos.h: Prototype the new alpha.c builtin + establish/revert expanders. + * config/alpha/alpha.h (DWARF_FRAME_REGNUM): Define. + * config/alpha/alpha.md (builtin_establish_vms_condition_handler): + New expander, resorting to the alpha.c associated function. + (builtin_revert_vms_condition_handler): Likewise. + * config/alpha/vms-gcc_shell_handler.c: New file. Implements + __gcc_shell_handler, the static VMS condition handler used as + an indirection wrapper to the current dynamically established + handler. + * config/alpha/vms-unwind.h: Complete rewrite. + * config/alpha/t-vms (LIB2FUNCS_EXTRA): Add vms-gcc_shell_handler.c + * config/alpha/vms.h (MD_UNWIND_SUPPORT): + 2009-08-09 Eric Botcazou Douglas B Rupp diff --git a/gcc/config/alpha/alpha-protos.h b/gcc/config/alpha/alpha-protos.h index 80c1e4f..244ff71 100644 --- a/gcc/config/alpha/alpha-protos.h +++ b/gcc/config/alpha/alpha-protos.h @@ -67,6 +67,9 @@ extern rtx alpha_expand_zap_mask (HOST_WIDE_INT); extern void alpha_expand_builtin_vector_binop (rtx (*)(rtx, rtx, rtx), enum machine_mode, rtx, rtx, rtx); +extern void alpha_expand_builtin_establish_vms_condition_handler (rtx, rtx); +extern void alpha_expand_builtin_revert_vms_condition_handler (rtx); + extern rtx alpha_return_addr (int, rtx); extern rtx alpha_gp_save_rtx (void); extern void print_operand (FILE *, rtx, int); diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index 42cb7a9..3857909 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -4779,6 +4779,9 @@ struct GTY(()) machine_function /* For TARGET_LD_BUGGY_LDGP. */ struct rtx_def *gp_save_rtx; + + /* For VMS condition handlers. */ + bool uses_condition_handler; }; /* How to allocate a 'struct machine_function'. */ @@ -4790,6 +4793,63 @@ alpha_init_machine_status (void) ggc_alloc_cleared (sizeof (struct machine_function))); } +/* Support for frame based VMS condition handlers. */ + +/* A VMS condition handler may be established for a function with a call to + __builtin_establish_vms_condition_handler, and cancelled with a call to + __builtin_revert_vms_condition_handler. + + The VMS Condition Handling Facility knows about the existence of a handler + from the procedure descriptor .handler field. As the VMS native compilers, + we store the user specified handler's address at a fixed location in the + stack frame and point the procedure descriptor at a common wrapper which + fetches the real handler's address and issues an indirect call. + + The indirection wrapper is "__gcc_shell_handler", provided by libgcc. + + We force the procedure kind to PT_STACK, and the fixed frame location is + fp+8, just before the register save area. We use the handler_data field in + the procedure descriptor to state the fp offset at which the installed + handler address can be found. */ + +#define VMS_COND_HANDLER_FP_OFFSET 8 + +/* Expand code to store the currently installed user VMS condition handler + into TARGET and install HANDLER as the new condition handler. */ + +void +alpha_expand_builtin_establish_vms_condition_handler (rtx target, rtx handler) +{ + rtx handler_slot_address + = plus_constant (hard_frame_pointer_rtx, VMS_COND_HANDLER_FP_OFFSET); + + rtx handler_slot + = gen_rtx_MEM (DImode, handler_slot_address); + + emit_move_insn (target, handler_slot); + emit_move_insn (handler_slot, handler); + + /* Notify the start/prologue/epilogue emitters that the condition handler + slot is needed. In addition to reserving the slot space, this will force + the procedure kind to PT_STACK so ensure that the hard_frame_pointer_rtx + use above is correct. */ + cfun->machine->uses_condition_handler = true; +} + +/* Expand code to store the current VMS condition handler into TARGET and + nullify it. */ + +void +alpha_expand_builtin_revert_vms_condition_handler (rtx target) +{ + /* We implement this by establishing a null condition handler, with the tiny + side effect of setting uses_condition_handler. This is a little bit + pessimistic if no actual builtin_establish call is ever issued, which is + not a real problem and expected never to happen anyway. */ + + alpha_expand_builtin_establish_vms_condition_handler (target, const0_rtx); +} + /* Functions to save and restore alpha_return_addr_rtx. */ /* Start the ball rolling with RETURN_ADDR_RTX. */ @@ -6380,6 +6440,8 @@ enum alpha_builtin ALPHA_BUILTIN_RPCC, ALPHA_BUILTIN_THREAD_POINTER, ALPHA_BUILTIN_SET_THREAD_POINTER, + ALPHA_BUILTIN_ESTABLISH_VMS_CONDITION_HANDLER, + ALPHA_BUILTIN_REVERT_VMS_CONDITION_HANDLER, /* TARGET_MAX */ ALPHA_BUILTIN_MINUB8, @@ -6435,6 +6497,8 @@ static enum insn_code const code_for_builtin[ALPHA_BUILTIN_max] = { CODE_FOR_builtin_rpcc, CODE_FOR_load_tp, CODE_FOR_set_tp, + CODE_FOR_builtin_establish_vms_condition_handler, + CODE_FOR_builtin_revert_vms_condition_handler, /* TARGET_MAX */ CODE_FOR_builtin_minub8, @@ -6580,6 +6644,21 @@ alpha_init_builtins (void) NULL, NULL); TREE_NOTHROW (decl) = 1; + if (TARGET_ABI_OPEN_VMS) + { + ftype = build_function_type_list (ptr_type_node, ptr_type_node, + NULL_TREE); + add_builtin_function ("__builtin_establish_vms_condition_handler", ftype, + ALPHA_BUILTIN_ESTABLISH_VMS_CONDITION_HANDLER, + BUILT_IN_MD, NULL, NULL_TREE); + + ftype = build_function_type_list (ptr_type_node, void_type_node, + NULL_TREE); + add_builtin_function ("__builtin_revert_vms_condition_handler", ftype, + ALPHA_BUILTIN_REVERT_VMS_CONDITION_HANDLER, + BUILT_IN_MD, NULL, NULL_TREE); + } + alpha_v8qi_u = build_vector_type (unsigned_intQI_type_node, 8); alpha_v8qi_s = build_vector_type (intQI_type_node, 8); alpha_v4hi_u = build_vector_type (unsigned_intHI_type_node, 4); @@ -7309,7 +7388,10 @@ alpha_sa_size (void) if (! fixed_regs[i] && call_used_regs[i] && ! df_regs_ever_live_p (i)) vms_save_fp_regno = i; - if (vms_save_fp_regno == -1 && alpha_procedure_type == PT_REGISTER) + /* A VMS condition handler requires a stack procedure in our + implementation. (not required by the calling standard). */ + if ((vms_save_fp_regno == -1 && alpha_procedure_type == PT_REGISTER) + || cfun->machine->uses_condition_handler) vms_base_regno = REG_PV, alpha_procedure_type = PT_STACK; else if (alpha_procedure_type == PT_NULL) vms_base_regno = REG_PV; @@ -7318,9 +7400,10 @@ alpha_sa_size (void) vms_unwind_regno = (vms_base_regno == REG_PV ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); - /* If this is a stack procedure, allow space for saving FP and RA. */ + /* If this is a stack procedure, allow space for saving FP, RA and + a condition handler slot if needed. */ if (alpha_procedure_type == PT_STACK) - sa_size += 2; + sa_size += 2 + cfun->machine->uses_condition_handler; } else { @@ -7572,7 +7655,7 @@ alpha_expand_prologue (void) + crtl->args.pretend_args_size)); if (TARGET_ABI_OPEN_VMS) - reg_offset = 8; + reg_offset = 8 + 8 * cfun->machine->uses_condition_handler; else reg_offset = ALPHA_ROUND (crtl->outgoing_args_size); @@ -7910,7 +7993,7 @@ alpha_start_function (FILE *file, const char *fnname, + crtl->args.pretend_args_size)); if (TARGET_ABI_OPEN_VMS) - reg_offset = 8; + reg_offset = 8 + 8 * cfun->machine->uses_condition_handler; else reg_offset = ALPHA_ROUND (crtl->outgoing_args_size); @@ -8049,6 +8132,16 @@ alpha_start_function (FILE *file, const char *fnname, } #if TARGET_ABI_OPEN_VMS + /* If a user condition handler has been installed at some point, emit + the procedure descriptor bits to point the Condition Handling Facility + at the indirection wrapper, and state the fp offset at which the user + handler may be found. */ + if (cfun->machine->uses_condition_handler) + { + fprintf (file, "\t.handler __gcc_shell_handler\n"); + fprintf (file, "\t.handler_data %d\n", VMS_COND_HANDLER_FP_OFFSET); + } + /* Ifdef'ed cause link_section are only available then. */ switch_to_section (readonly_data_section); fprintf (file, "\t.align 3\n"); @@ -8120,7 +8213,7 @@ alpha_expand_epilogue (void) if (TARGET_ABI_OPEN_VMS) { if (alpha_procedure_type == PT_STACK) - reg_offset = 8; + reg_offset = 8 + 8 * cfun->machine->uses_condition_handler; else reg_offset = 0; } diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h index 5b74fe1..cd8c11e 100644 --- a/gcc/config/alpha/alpha.h +++ b/gcc/config/alpha/alpha.h @@ -882,6 +882,12 @@ do { \ #define RETURN_ADDR_RTX alpha_return_addr +/* Provide a definition of DWARF_FRAME_REGNUM here so that fallback unwinders + can use DWARF_ALT_FRAME_RETURN_COLUMN defined below. This is just the same + as the default definition in dwarf2out.c. */ +#undef DWARF_FRAME_REGNUM +#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG) + /* Before the prologue, RA lives in $26. */ #define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, 26) #define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (26) diff --git a/gcc/config/alpha/alpha.md b/gcc/config/alpha/alpha.md index fe475c2..935cc94 100644 --- a/gcc/config/alpha/alpha.md +++ b/gcc/config/alpha/alpha.md @@ -4976,6 +4976,24 @@ return "call_pal 0x9f"; } [(set_attr "type" "callpal")]) + +;; Special builtins for establishing and reverting VMS condition handlers. + +(define_expand "builtin_establish_vms_condition_handler" + [(set (reg:DI 0) (match_operand:DI 0 "register_operand" "")) + (use (match_operand:DI 1 "address_operand" ""))] + "TARGET_ABI_OPEN_VMS" +{ + alpha_expand_builtin_establish_vms_condition_handler (operands[0], + operands[1]); +}) + +(define_expand "builtin_revert_vms_condition_handler" + [(set (reg:DI 0) (match_operand:DI 0 "register_operand" ""))] + "TARGET_ABI_OPEN_VMS" +{ + alpha_expand_builtin_revert_vms_condition_handler (operands[0]); +}) ;; Finally, we have the basic data motion insns. The byte and word insns ;; are done via define_expand. Start with the floating-point insns, since diff --git a/gcc/config/alpha/t-vms b/gcc/config/alpha/t-vms index e110512..410e219 100644 --- a/gcc/config/alpha/t-vms +++ b/gcc/config/alpha/t-vms @@ -17,6 +17,8 @@ # along with GCC; see the file COPYING3. If not see # . +LIB2FUNCS_EXTRA = $(srcdir)/config/alpha/vms-gcc_shell_handler.c + EXTRA_PARTS = vms-dwarf2.o vms-dwarf2eh.o $(VMS_EXTRA_PARTS) \ crtbegin.o crtbeginS.o crtend.o crtendS.o diff --git a/gcc/config/alpha/vms-gcc_shell_handler.c b/gcc/config/alpha/vms-gcc_shell_handler.c new file mode 100644 index 0000000..67d0fe7 --- /dev/null +++ b/gcc/config/alpha/vms-gcc_shell_handler.c @@ -0,0 +1,124 @@ +/* Static condition handler for Alpha/VMS. + Copyright (C) 2005-2009 + Free Software Foundation, Inc. + + 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 + . */ + +/* This file implements __gcc_shell_handler, the static VMS condition handler + used as the indirection wrapper around user level handlers installed with + establish_vms_condition_handler GCC builtin. + + [ABI] in comments refers to the "HP OpenVMS calling standard" document + dated January 2005. */ + +#include +#include +#include + +typedef void * ADDR; +typedef unsigned long long REG; + +#define REG_AT(addr) (*(REG *)(addr)) + +/* Compute pointer to procedure descriptor (Procedure Value) from Frame + Pointer FP, according to the rules in [ABI-3.5.1 Current Procedure]. */ +#define PV_FOR(FP) \ + (((FP) != 0) \ + ? (((REG_AT (FP) & 0x7) == 0) ? *(PDSCDEF **)(FP) : (PDSCDEF *)(FP)) : 0) + +long +__gcc_shell_handler (struct chf$signal_array *sig_arr, + struct chf$mech_array *mech_arr); + +/* Helper for __gcc_shell_handler. Fetch the pointer to procedure currently + registered as the VMS condition handler for the live function with a frame + pointer FP. */ + +static ADDR +get_dyn_handler_pointer (REG fp) +{ + /* From the frame pointer we find the procedure descriptor, and fetch + the handler_data field from there. This field contains the offset + from FP at which the address of the currently installed handler is + to be found. */ + + PDSCDEF * pd = PV_FOR (fp); + /* Procedure descriptor pointer for the live subprogram with FP as the frame + pointer, and to which _gcc_shell_handler is attached as a condition + handler. */ + + REG handler_slot_offset; + /* Offset from FP at which the address of the currently established real + condition handler is to be found. This offset is available from the + handler_data field of the procedure descriptor. */ + + REG handler_data_offset; + /* The handler_data field position in the procedure descriptor, which + depends on the kind of procedure at hand. */ + + switch (pd->pdsc$w_flags & 0xf) + { + case PDSC$K_KIND_FP_STACK: /* [3.4.2 PD for stack frame procedures] */ + handler_data_offset = 40; + break; + + case PDSC$K_KIND_FP_REGISTER: /* [3.4.5 PD for reg frame procedures] */ + handler_data_offset = 32; + break; + + default: + handler_data_offset = 0; + break; + } + + /* If we couldn't determine the handler_data field position, give up. */ + if (handler_data_offset == 0) + return 0; + + /* Otherwise, fetch the fp offset at which the real handler address is to be + found, then fetch and return the latter in turn. */ + + handler_slot_offset = REG_AT ((REG)pd + handler_data_offset); + + return (ADDR) REG_AT (fp + handler_slot_offset); +} + +/* The static VMS condition handler for GCC code. Fetch the address of the + currently established condition handler, then resignal if there is none or + call the handler with the VMS condition arguments. */ + +long +__gcc_shell_handler (struct chf$signal_array *sig_arr, + struct chf$mech_array *mech_arr) +{ + long ret; + long (*user_handler) (struct chf$signal_array *, struct chf$mech_array *); + + user_handler = get_dyn_handler_pointer (mech_arr->chf$q_mch_frame); + if (!user_handler) + ret = SS$_RESIGNAL; + else + ret = user_handler (sig_arr, mech_arr); + + return ret; +} + diff --git a/gcc/config/alpha/vms-unwind.h b/gcc/config/alpha/vms-unwind.h index 78c7744..09b2f8f 100644 --- a/gcc/config/alpha/vms-unwind.h +++ b/gcc/config/alpha/vms-unwind.h @@ -1,71 +1,291 @@ -/* DWARF2 EH unwinding support for Alpha VMS. - Copyright (C) 2004, 2007 Free Software Foundation, Inc. +/* Fallback frame unwinding for Alpha/VMS. + Copyright (C) 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2009 + Free Software Foundation, Inc. -This file is part of GCC. + 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 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. + 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. -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ + 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. -#include + 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 + . */ -#define MD_FALLBACK_FRAME_STATE_FOR alpha_fallback_frame_state +#include +#include +#include +#include +#include +#include -static _Unwind_Reason_Code -alpha_fallback_frame_state (struct _Unwind_Context *context, - _Unwind_FrameState *fs) +#define MD_FALLBACK_FRAME_STATE_FOR alpha_vms_fallback_frame_state + +typedef void * ADDR; +typedef unsigned long long REG; +typedef PDSCDEF * PV; + +#define REG_AT(addr) (*(REG *)(addr)) +#define ADDR_AT(addr) (*(ADDR *)(addr)) + +/* Compute pointer to procedure descriptor (Procedure Value) from Frame + Pointer FP, according to the rules in [ABI-3.5.1 Current Procedure]. */ +#define PV_FOR(FP) \ + (((FP) != 0) \ + ? (((REG_AT (FP) & 0x7) == 0) ? *(PDSCDEF **)(FP) : (PDSCDEF *)(FP)) : 0) + +extern int SYS$GL_CALL_HANDL; +/* This is actually defined as a "long", but in system code where longs + are always 4bytes while GCC longs might be 8bytes. */ + +#define UPDATE_FS_FOR_CFA_GR(FS, GRN, LOC, CFA) \ +do { \ +(FS)->regs.reg[GRN].how = REG_SAVED_OFFSET; \ +(FS)->regs.reg[GRN].loc.offset = (_Unwind_Sword) ((REG) (LOC) - (REG) (CFA)); \ +} while (0); + +#define GIVEUP_ON_FAILURE(STATUS) \ + { if ((((STATUS) & 1) != 1)) return _URC_END_OF_STACK; } +#define DENOTES_EXC_DISPATCHER(PV) ((PV) == (ADDR) (REG) SYS$GL_CALL_HANDL) + +#define RA_COLUMN (DWARF_ALT_FRAME_RETURN_COLUMN) + +static int +alpha_vms_fallback_frame_state (struct _Unwind_Context *context, + _Unwind_FrameState *fs) { - PDSCDEF *pv = *((PDSCDEF **) context->reg [29]); + static int eh_debug = -1; + + /* Our goal is to update FS to reflect the state one step up CONTEXT, that + is: the CFA, return address and *saved* registers locations associated + with the function designated by CONTEXT->ra. We are called when the + libgcc unwinder has not found any dwarf FDE for this address, which + typically happens when trying to propagate a language exception through a + signal global vector or frame based handler. + + The CONTEXT->reg[] entries reflect the state/location of register saves + so designate values live at the CONTEXT->ra point. Of precious value to + us here is the frame pointer (r29), which gets us a procedure value. */ + + PV pv = (context->reg[29] != 0) ? PV_FOR (ADDR_AT (context->reg[29])) : 0; + + int pkind = pv ? pv->pdsc$w_flags & 0xf : 0; + /* VMS procedure kind, as indicated by the procedure descriptor. We only + know how to deal with FP_STACK or FP_REGISTER here. */ + + ADDR new_cfa = 0; + /* CFA we will establish for the caller, computed in different ways, + e.g. depending whether we cross an exception dispatcher frame. */ + + CHFCTX *chfctx = 0; + /* Pointer to the VMS CHF context associated with an exception dispatcher + frame, if we happen to come across one. */ + + int i,j; + + if (eh_debug == -1) + { + char * eh_debug_env = getenv ("EH_DEBUG"); + eh_debug = eh_debug_env ? atoi (eh_debug_env) : 0; + } + + if (eh_debug) + printf ("MD_FALLBACK running ...\n"); + + /* We only know how to deal with stack or reg frame procedures, so give + up if we're handed anything else. */ + if (pkind != PDSC$K_KIND_FP_STACK && pkind != PDSC$K_KIND_FP_REGISTER) + return _URC_END_OF_STACK; + + if (eh_debug) + printf ("FALLBACK: CTX FP = 0x%p, PV = 0x%p, EN = 0x%llx, RA = 0x%p\n", + ADDR_AT (context->reg[29]), pv, pv->pdsc$q_entry, context->ra); + + fs->retaddr_column = RA_COLUMN; + + /* If PV designates a VMS exception vector or condition handler, we need to + do as if the caller was the signaling point and estabish the state of the + intermediate VMS code (CFA, RA and saved register locations) as if it was + a single regular function. This requires special processing. + + The datastructures available from an condition dispatcher frame (signal + context) do not contain the values of most callee-saved registers, so + whathever PV designates, we need to account for the registers it saves. + + Besides, we need to express all the locations with respect to a + consistent CFA value, so we compute this first. */ + + if (DENOTES_EXC_DISPATCHER (pv)) + { + /* The CFA to establish is the signaling point's stack pointer. We + compute it using the system invocation context unwinding services and + save the CHF context data pointer along the way for later uses. */ + + INVO_CONTEXT_BLK icb; + int status, invo_handle; + + if (eh_debug) + printf ("FALLBACK: SYS$HANDLER\n"); + + icb.libicb$q_ireg [29] = REG_AT (context->reg[29]); + icb.libicb$q_ireg [30] = 0; + invo_handle = LIB$GET_INVO_HANDLE (&icb); + + status = LIB$GET_INVO_CONTEXT (invo_handle, &icb); + GIVEUP_ON_FAILURE (status); + + chfctx = (CHFCTX *) icb.libicb$ph_chfctx_addr; + + status = LIB$GET_PREV_INVO_CONTEXT (&icb); + GIVEUP_ON_FAILURE (status); - if (pv && ((long) pv & 0x7) == 0) /* low bits 0 means address */ - pv = *(PDSCDEF **) pv; + new_cfa = (ADDR) icb.libicb$q_ireg[30]; + } + else + { + /* The CFA to establish is the SP value on entry of the procedure + designated by PV, which we compute as the corresponding frame base + register value + frame size. Note that the frame base may differ + from CONTEXT->cfa, typically if the caller has performed dynamic + stack allocations. */ + + int base_reg = pv->pdsc$w_flags & PDSC$M_BASE_REG_IS_FP ? 29 : 30; + ADDR base_addr = ADDR_AT (context->reg[base_reg]); + + new_cfa = base_addr + pv->pdsc$l_size; + } + + /* State to compute the caller's CFA by adding an offset to the current + one in CONTEXT. */ + fs->regs.cfa_how = CFA_REG_OFFSET; + fs->regs.cfa_reg = __builtin_dwarf_sp_column (); + fs->regs.cfa_offset = new_cfa - context->cfa; - if (pv && ((pv->pdsc$w_flags & 0xf) == PDSC$K_KIND_FP_STACK)) + /* Regular unwind first, accounting for the register saves performed by + the procedure designated by PV. */ + + switch (pkind) { - int i, j; - - fs->regs.cfa_offset = pv->pdsc$l_size; - fs->regs.cfa_reg = pv->pdsc$w_flags & PDSC$M_BASE_REG_IS_FP ? 29 : 30; - fs->retaddr_column = 26; - fs->regs.cfa_how = CFA_REG_OFFSET; - fs->regs.reg[27].loc.offset = -pv->pdsc$l_size; - fs->regs.reg[27].how = REG_SAVED_OFFSET; - fs->regs.reg[26].loc.offset - = -(pv->pdsc$l_size - pv->pdsc$w_rsa_offset); - fs->regs.reg[26].how = REG_SAVED_OFFSET; - - for (i = 0, j = 0; i < 32; i++) - if (1<pdsc$l_ireg_mask) - { - fs->regs.reg[i].loc.offset - = -(pv->pdsc$l_size - pv->pdsc$w_rsa_offset - 8 * ++j); - fs->regs.reg[i].how = REG_SAVED_OFFSET; - } - - return _URC_NO_REASON; + case PDSC$K_KIND_FP_STACK: + { + /* The saved registers are all located in the Register Save Area, + except for the procedure value register (R27) found at the frame + base address. */ + + int base_reg = pv->pdsc$w_flags & PDSC$M_BASE_REG_IS_FP ? 29 : 30; + ADDR base_addr = ADDR_AT (context->reg[base_reg]); + ADDR rsa_addr = base_addr + pv->pdsc$w_rsa_offset; + + if (eh_debug) + printf ("FALLBACK: STACK frame procedure\n"); + + UPDATE_FS_FOR_CFA_GR (fs, 27, base_addr, new_cfa); + + /* The first RSA entry is for the return address register, R26. */ + + UPDATE_FS_FOR_CFA_GR (fs, 26, rsa_addr, new_cfa); + UPDATE_FS_FOR_CFA_GR (fs, RA_COLUMN, rsa_addr, new_cfa); + + /* The following entries are for registers marked as saved according + to ireg_mask. */ + for (i = 0, j = 0; i < 32; i++) + if ((1 << i) & pv->pdsc$l_ireg_mask) + UPDATE_FS_FOR_CFA_GR (fs, i, rsa_addr + 8 * ++j, new_cfa); + + /* ??? floating point registers ? */ + + break; + } + + case PDSC$K_KIND_FP_REGISTER: + { + if (eh_debug) + printf ("FALLBACK: REGISTER frame procedure\n"); + + fs->regs.reg[RA_COLUMN].how = REG_SAVED_REG; + fs->regs.reg[RA_COLUMN].loc.reg = pv->pdsc$b_save_ra; + + fs->regs.reg[29].how = REG_SAVED_REG; + fs->regs.reg[29].loc.reg = pv->pdsc$b_save_fp; + + break; + } + + default: + /* Should never reach here. */ + return _URC_END_OF_STACK; } - else if (pv && ((pv->pdsc$w_flags & 0xf) == PDSC$K_KIND_FP_REGISTER)) + + /* If PV designates an exception dispatcher, we have to adjust the return + address column to get at the signal occurrence point, and account for + for what the CHF context contains. */ + + if (DENOTES_EXC_DISPATCHER (pv)) { - fs->regs.cfa_offset = pv->pdsc$l_size; - fs->regs.cfa_reg = pv->pdsc$w_flags & PDSC$M_BASE_REG_IS_FP ? 29 : 30; - fs->retaddr_column = 26; - fs->regs.cfa_how = CFA_REG_OFFSET; - fs->regs.reg[26].loc.reg = pv->pdsc$b_save_ra; - fs->regs.reg[26].how = REG_SAVED_REG; - fs->regs.reg[29].loc.reg = pv->pdsc$b_save_fp; - fs->regs.reg[29].how = REG_SAVED_REG; - - return _URC_NO_REASON; + /* The PC of the instruction causing the condition is available from the + signal argument vector. Extra saved register values are available + from the mechargs array. */ + + CHF$SIGNAL_ARRAY *sigargs + = (CHF$SIGNAL_ARRAY *) chfctx->chfctx$q_sigarglst; + + CHF$MECH_ARRAY *mechargs + = (CHF$MECH_ARRAY *) chfctx->chfctx$q_mcharglst; + + ADDR condpc_addr + = &((int *)(&sigargs->chf$l_sig_name)) [sigargs->chf$is_sig_args-2]; + + ADDR rei_frame_addr = (void *) mechargs->chf$q_mch_esf_addr; + + /* Adjust the return address location. */ + + UPDATE_FS_FOR_CFA_GR (fs, RA_COLUMN, condpc_addr, new_cfa); + + /* The frame pointer at the condition point is available from the + chf context directly. */ + + UPDATE_FS_FOR_CFA_GR (fs, 29, &chfctx->chfctx$q_expt_fp, new_cfa); + + /* Registers available from the mechargs array. */ + + UPDATE_FS_FOR_CFA_GR (fs, 0, &mechargs->chf$q_mch_savr0, new_cfa); + UPDATE_FS_FOR_CFA_GR (fs, 1, &mechargs->chf$q_mch_savr1, new_cfa); + + UPDATE_FS_FOR_CFA_GR (fs, 16, &mechargs->chf$q_mch_savr16, new_cfa); + UPDATE_FS_FOR_CFA_GR (fs, 17, &mechargs->chf$q_mch_savr17, new_cfa); + UPDATE_FS_FOR_CFA_GR (fs, 18, &mechargs->chf$q_mch_savr18, new_cfa); + UPDATE_FS_FOR_CFA_GR (fs, 19, &mechargs->chf$q_mch_savr19, new_cfa); + UPDATE_FS_FOR_CFA_GR (fs, 20, &mechargs->chf$q_mch_savr20, new_cfa); + UPDATE_FS_FOR_CFA_GR (fs, 21, &mechargs->chf$q_mch_savr21, new_cfa); + UPDATE_FS_FOR_CFA_GR (fs, 22, &mechargs->chf$q_mch_savr22, new_cfa); + UPDATE_FS_FOR_CFA_GR (fs, 23, &mechargs->chf$q_mch_savr23, new_cfa); + UPDATE_FS_FOR_CFA_GR (fs, 24, &mechargs->chf$q_mch_savr24, new_cfa); + UPDATE_FS_FOR_CFA_GR (fs, 25, &mechargs->chf$q_mch_savr25, new_cfa); + UPDATE_FS_FOR_CFA_GR (fs, 26, &mechargs->chf$q_mch_savr26, new_cfa); + UPDATE_FS_FOR_CFA_GR (fs, 27, &mechargs->chf$q_mch_savr27, new_cfa); + UPDATE_FS_FOR_CFA_GR (fs, 28, &mechargs->chf$q_mch_savr28, new_cfa); + + /* Registers R2 to R7 are available from the rei frame pointer. */ + + for (i = 2; i <= 7; i ++) + UPDATE_FS_FOR_CFA_GR (fs, i, rei_frame_addr+(i - 2)*8, new_cfa); + + /* ??? floating point registers ? */ } - return _URC_END_OF_STACK; + + return _URC_NO_REASON; } + + + diff --git a/gcc/config/alpha/vms.h b/gcc/config/alpha/vms.h index ff5e5d2..7b149f1 100644 --- a/gcc/config/alpha/vms.h +++ b/gcc/config/alpha/vms.h @@ -287,7 +287,13 @@ do { \ #define LINK_EH_SPEC "vms-dwarf2eh.o%s " #define LINK_GCC_C_SEQUENCE_SPEC "%G" +#ifdef IN_LIBGCC2 +/* Get the definition for MD_FALLBACK_FRAME_STATE_FOR from a separate + file. This avoids having to recompile the world instead of libgcc only + when changes to this macro are exercised. */ + #define MD_UNWIND_SUPPORT "config/alpha/vms-unwind.h" +#endif /* This is how to output an assembler line that says to advance the location counter -- 2.7.4