mirror of git://gcc.gnu.org/git/gcc.git
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 <rupp@gnat.com> From-SVN: r150612
This commit is contained in:
parent
b714133e38
commit
221cf9abf3
|
@ -1,3 +1,32 @@
|
|||
2009-08-09 Olivier Hainque <hainque@adacore.com>
|
||||
Douglas B Rupp <rupp@gnat.com>
|
||||
|
||||
* 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 <botcazou@adacore.com>
|
||||
Douglas B Rupp <rupp@gnat.com>
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
# along with GCC; see the file COPYING3. If not see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* 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 <vms/chfdef.h>
|
||||
#include <vms/pdscdef.h>
|
||||
#include <vms/ssdef.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
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 <pdscdef.h>
|
||||
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/>. */
|
||||
|
||||
#define MD_FALLBACK_FRAME_STATE_FOR alpha_fallback_frame_state
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <vms/pdscdef.h>
|
||||
#include <vms/libicb.h>
|
||||
#include <vms/chfctxdef.h>
|
||||
#include <vms/chfdef.h>
|
||||
|
||||
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;
|
||||
|
||||
if (pv && ((long) pv & 0x7) == 0) /* low bits 0 means address */
|
||||
pv = *(PDSCDEF **) pv;
|
||||
/* 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.
|
||||
|
||||
if (pv && ((pv->pdsc$w_flags & 0xf) == PDSC$K_KIND_FP_STACK))
|
||||
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)
|
||||
{
|
||||
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<<i & pv->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;
|
||||
char * eh_debug_env = getenv ("EH_DEBUG");
|
||||
eh_debug = eh_debug_env ? atoi (eh_debug_env) : 0;
|
||||
}
|
||||
else if (pv && ((pv->pdsc$w_flags & 0xf) == PDSC$K_KIND_FP_REGISTER))
|
||||
|
||||
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))
|
||||
{
|
||||
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;
|
||||
/* 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. */
|
||||
|
||||
return _URC_NO_REASON;
|
||||
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);
|
||||
|
||||
new_cfa = (ADDR) icb.libicb$q_ireg[30];
|
||||
}
|
||||
return _URC_END_OF_STACK;
|
||||
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;
|
||||
|
||||
/* Regular unwind first, accounting for the register saves performed by
|
||||
the procedure designated by PV. */
|
||||
|
||||
switch (pkind)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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))
|
||||
{
|
||||
/* 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_NO_REASON;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue