From 4798630cb0aa99b3497a16b3e1a5ee0e12a1760b Mon Sep 17 00:00:00 2001 From: "P.J. Darcy" Date: Wed, 22 Sep 2004 13:57:40 +0000 Subject: [PATCH] s390-protos.h (s390_emit_tpf_eh_return): Add prototype. 2004-09-22 P.J. Darcy * config/s390/s390-protos.h (s390_emit_tpf_eh_return): Add prototype. * config/s390/s390.c (s390_emit_tpf_eh_return): New function. * config/s390/s390.h (TARGET_TPF): New macro. * config/s390/s390.md ("eh_return"): New expander. * config/s390/t-tpf (LIB2ADDEH): Use unwind-dw2-fde.c rather than unwind-dw2-fde-glibc.c. Add config/s390/tpf-eh.c. (LIB2ADDEHDEP): Remove unwind-dw2-fde.c. * config/s390/tpf.h (TARGET_TPF): Define to 1. (STACK_POINTER_OFFSET): Increase to 448. (TARGET_DEFAULT): Set -mtpf-trace on as default. (TPF_LOC_DIFF_OFFSET): New macro. (ASM_PREFERRED_EH_DATA_FORMAT): Redefine to always use absolute encoding. (__isPATrange): Add prototype. (MD_FALLBACK_FRAME_STATE_FOR): Define. * config/s390/tpf-eh.c: New file. From-SVN: r87857 --- gcc/ChangeLog | 19 ++++ gcc/config/s390/s390-protos.h | 1 + gcc/config/s390/s390.c | 20 ++++ gcc/config/s390/s390.h | 3 + gcc/config/s390/s390.md | 12 +++ gcc/config/s390/t-tpf | 9 +- gcc/config/s390/tpf-eh.c | 183 ++++++++++++++++++++++++++++++++++ gcc/config/s390/tpf.h | 85 +++++++++++++++- 8 files changed, 325 insertions(+), 7 deletions(-) create mode 100644 gcc/config/s390/tpf-eh.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 115f39bd7a4..1a95e0446a3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2004-09-22 P.J. Darcy + + * config/s390/s390-protos.h (s390_emit_tpf_eh_return): Add prototype. + * config/s390/s390.c (s390_emit_tpf_eh_return): New function. + * config/s390/s390.h (TARGET_TPF): New macro. + * config/s390/s390.md ("eh_return"): New expander. + * config/s390/t-tpf (LIB2ADDEH): Use unwind-dw2-fde.c rather than + unwind-dw2-fde-glibc.c. Add config/s390/tpf-eh.c. + (LIB2ADDEHDEP): Remove unwind-dw2-fde.c. + * config/s390/tpf.h (TARGET_TPF): Define to 1. + (STACK_POINTER_OFFSET): Increase to 448. + (TARGET_DEFAULT): Set -mtpf-trace on as default. + (TPF_LOC_DIFF_OFFSET): New macro. + (ASM_PREFERRED_EH_DATA_FORMAT): Redefine to always use absolute + encoding. + (__isPATrange): Add prototype. + (MD_FALLBACK_FRAME_STATE_FOR): Define. + * config/s390/tpf-eh.c: New file. + 2004-09-22 Diego Novillo * fold-const.c (fold): Avoid non INTEGER_TYPEs when widening diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h index 6f05d80d545..8b5a263d98b 100644 --- a/gcc/config/s390/s390-protos.h +++ b/gcc/config/s390/s390-protos.h @@ -95,6 +95,7 @@ extern rtx s390_gen_rtx_const_DI (int, int); extern void s390_output_dwarf_dtprel (FILE*, int, rtx); extern int s390_agen_dep_p (rtx, rtx); extern rtx s390_load_got (void); +extern void s390_emit_tpf_eh_return (rtx); #endif /* RTX_CODE */ diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index 124f4e54df9..5d838ef715c 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -8017,5 +8017,25 @@ s390_conditional_register_usage (void) } } +/* Corresponding function to eh_return expander. */ + +static GTY(()) rtx s390_tpf_eh_return_symbol; +void +s390_emit_tpf_eh_return (rtx target) +{ + rtx insn, reg; + + if (!s390_tpf_eh_return_symbol) + s390_tpf_eh_return_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tpf_eh_return"); + + reg = gen_rtx_REG (Pmode, 2); + + emit_move_insn (reg, target); + insn = s390_emit_call (s390_tpf_eh_return_symbol, NULL_RTX, reg, + gen_rtx_REG (Pmode, RETURN_REGNUM)); + use_reg (&CALL_INSN_FUNCTION_USAGE (insn), reg); + + emit_move_insn (EH_RETURN_HANDLER_RTX, reg); +} #include "gt-s390.h" diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h index f361ce4d374..5b083aadbe6 100644 --- a/gcc/config/s390/s390.h +++ b/gcc/config/s390/s390.h @@ -80,6 +80,9 @@ extern const char *s390_stack_guard_string; /* Run-time target specification. */ +/* This will be overridden by OS headers. */ +#define TARGET_TPF 0 + /* Target CPU builtins. */ #define TARGET_CPU_CPP_BUILTINS() \ do \ diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index 5ca28b5e5c2..8c65145f419 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -7504,3 +7504,15 @@ GEN_INT (0x7fffffff))); DONE; }) + +;; Instruction definition to expand eh_return macro to support +;; swapping in special linkage return addresses. + +(define_expand "eh_return" + [(use (match_operand 0 "register_operand" ""))] + "TARGET_TPF" +{ + s390_emit_tpf_eh_return (operands[0]); + DONE; +}) + diff --git a/gcc/config/s390/t-tpf b/gcc/config/s390/t-tpf index 2a3421c479d..76d2c23a8b0 100644 --- a/gcc/config/s390/t-tpf +++ b/gcc/config/s390/t-tpf @@ -7,7 +7,8 @@ TARGET_LIBGCC2_CFLAGS = -fPIC # the symbol versions that glibc used. SHLIB_MAPFILES += $(srcdir)/config/s390/libgcc-glibc.ver -# Use unwind-dw2-fde-glibc -LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde-glibc.c \ - $(srcdir)/unwind-sjlj.c $(srcdir)/gthr-gnat.c $(srcdir)/unwind-c.c -LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h unwind-dw2-fde.c +# Use unwind-dw2-fde and extra tpf-eh support routines. +LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde.c \ + $(srcdir)/unwind-sjlj.c $(srcdir)/gthr-gnat.c $(srcdir)/unwind-c.c \ + $(srcdir)/config/s390/tpf-eh.c +LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h diff --git a/gcc/config/s390/tpf-eh.c b/gcc/config/s390/tpf-eh.c new file mode 100644 index 00000000000..1ce01ab56ea --- /dev/null +++ b/gcc/config/s390/tpf-eh.c @@ -0,0 +1,183 @@ +/* Exception handling routines for TPF. + Copyright (C) 2004 Free Software Foundation, Inc. + Contributed by P.J. Darcy (darcypj@us.ibm.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 2, or (at your option) + any later version. + + In addition to the permissions in the GNU General Public License, the + Free Software Foundation gives you unlimited permission to link the + compiled version of this file into combinations with other programs, + and to distribute those combinations without any restriction coming + from the use of this file. (The General Public License restrictions + do apply in other respects; for example, they cover modification of + the file, and distribution when not linked into a combined + executable.) + + 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 COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#define __USE_GNU 1 +#define _GNU_SOURCE +#include +#undef __USE_GNU +#undef _GNU_SOURCE + +#define CURRENT_STACK_PTR() \ + ({ register unsigned long int *stack_ptr asm ("%r15"); stack_ptr; }) + +#define PREVIOUS_STACK_PTR() \ + ((unsigned long int *)(*(CURRENT_STACK_PTR()))) + +#define RA_OFFSET_FROM_START_OF_STACK_FRAME 112 +#define CURRENT_STACK_PTR_OFFSET 120 +#define TPFRA_OFFSET_FROM_START_OF_STACK_FRAME 168 +#define MIN_PATRANGE 0x10000 +#define MAX_PATRANGE 0x800000 +#define INVALID_RETURN 0 + +/* Function Name: __isPATrange + Parameters passed into it: address to check + Return Value: A 1 if address is in pat code "range", 0 if not + Description: This function simply checks to see if the address + passed to it is in the CP pat code range. */ + +unsigned int __isPATrange(void *addr) +{ + if (addr > (void *)MIN_PATRANGE && addr < (void *)MAX_PATRANGE) + return 1; + else + return 0; +} + +/* Function Name: __tpf_eh_return + Parameters passed into it: Destination address to jump to. + Return Value: Converted Destination address if a Pat Stub exists. + Description: This function swaps the uwinding return address + with the cp stub code. The original target return address is + then stored into the tpf return address field. The cp stub + code is searched for by climbing back up the stack and + comparing the tpf stored return address object address to + that of the targets object address. */ + +void *__tpf_eh_return (void *target) +{ + Dl_info targetcodeInfo, currentcodeInfo; + int retval; + void *current, *stackptr; + unsigned long int shifter; + + /* Get code info for target return's address. */ + retval = dladdr (target, &targetcodeInfo); + + /* Get the return address of the stack frame to be replaced by + the exception unwinder. So that the __cxa_throw return is + replaced by the target return. */ + current = (void *) *((unsigned long int *) + ((*((unsigned long int *)*(PREVIOUS_STACK_PTR()))) + + RA_OFFSET_FROM_START_OF_STACK_FRAME)); + + /* Ensure the code info is valid (for target). */ + if (retval != INVALID_RETURN) + { + /* Now check to see if the current RA is a PAT + stub return address. */ + if ( __isPATrange(current)) + { + /* It was! Then go into the TPF private stack area and fetch + the real address. */ + current = (void *) *((unsigned long int *) + ((unsigned long int)*((unsigned long int *) + *(PREVIOUS_STACK_PTR())) + +TPFRA_OFFSET_FROM_START_OF_STACK_FRAME)); + } + + /* Get code info for current return address. */ + retval = dladdr (current, ¤tcodeInfo); + + /* Ensure the code info is valid (for current frame). */ + if (retval != INVALID_RETURN) + { + /* Get the stack pointer of the stack frame to be replaced by + the exception unwinder. So that we can begin our climb + there. */ + stackptr = (void *) (*((unsigned long int *) + (*((unsigned long int *)(*(PREVIOUS_STACK_PTR())))))); + + /* Begin looping through stack frames. Stop if invalid + code information is retrieved or if a match between the + current stack frame iteration shared object's address + matches that of the target, calculated above. */ + while (retval != INVALID_RETURN + && targetcodeInfo.dli_fbase != currentcodeInfo.dli_fbase) + { + /* Get return address based on our stackptr iterator. */ + current = (void *) *((unsigned long int *) + (stackptr+RA_OFFSET_FROM_START_OF_STACK_FRAME)); + + /* Is it a Pat Stub? */ + if (__isPATrange (current)) + { + /* Yes it was, get real return address + in TPF stack area. */ + current = (void *) *((unsigned long int *) + (stackptr+TPFRA_OFFSET_FROM_START_OF_STACK_FRAME)); + } + + /* Get codeinfo on RA so that we can figure out + the module address. */ + retval = dladdr (current, ¤tcodeInfo); + + /* Check that codeinfo for current stack frame is valid. + Then compare the module address of current stack frame + to target stack frame to determine if we have the pat + stub address we want. */ + if (retval != INVALID_RETURN + && targetcodeInfo.dli_fbase == currentcodeInfo.dli_fbase) + { + /* Yes! They are in the same module. Now store the + real target address into the TPF stack area of + the target frame we are jumping to. */ + *((unsigned long int *)(*((unsigned long int *) + (*PREVIOUS_STACK_PTR() + CURRENT_STACK_PTR_OFFSET)) + + TPFRA_OFFSET_FROM_START_OF_STACK_FRAME)) + = (unsigned long int) target; + + /* Before returning the desired pat stub address to + the exception handling unwinder so that it can + actually do the "leap" shift out the low order + bit designated to determine if we are in 64BIT mode. + This is nececcary for CTOA stubs. + Otherwise we leap one byte past where we want to + go to in the TPF pat stub linkage code. */ + shifter = *((unsigned long int *) + (stackptr + RA_OFFSET_FROM_START_OF_STACK_FRAME)); + + shifter &= ~1ul; + + return (void *) shifter; + } + + /* Desired module pat stub not found ... + Bump stack frame iterator. */ + stackptr = (void *) *(unsigned long int *) stackptr; + } + } + } + + /* No pat stub found, could be a problem? Simply return unmodified + target address. */ + return target; +} + diff --git a/gcc/config/s390/tpf.h b/gcc/config/s390/tpf.h index ce984e64003..587d373d6b7 100644 --- a/gcc/config/s390/tpf.h +++ b/gcc/config/s390/tpf.h @@ -1,5 +1,5 @@ /* Definitions for target OS TPF for GNU compiler, for IBM S/390 hardware - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. Contributed by P.J. Darcy (darcypj@us.ibm.com), Hartmut Penner (hpenner@de.ibm.com), and Ulrich Weigand (uweigand@de.ibm.com). @@ -25,6 +25,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #define _TPF_H /* TPF wants the following macros defined/undefined as follows. */ +#undef TARGET_TPF +#define TARGET_TPF 1 #undef ASM_APP_ON #define ASM_APP_ON "#APP\n" #undef ASM_APP_OFF @@ -50,11 +52,20 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA /* TPF OS specific stack-pointer offset. */ #undef STACK_POINTER_OFFSET -#define STACK_POINTER_OFFSET 280 +#define STACK_POINTER_OFFSET 448 +/* TPF stack placeholder offset. */ +#undef TPF_LOC_DIFF_OFFSET +#define TPF_LOC_DIFF_OFFSET 168 /* When building for TPF, set a generic default target that is 64 bits. */ #undef TARGET_DEFAULT -#define TARGET_DEFAULT 0x33 +#define TARGET_DEFAULT 0xb3 + +/* Exception handling. */ + +/* Select a format to encode pointers in exception handling data. */ +#undef ASM_PREFERRED_EH_DATA_FORMAT +#define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) DW_EH_PE_absptr /* TPF OS specific compiler settings. */ #undef TARGET_OS_CPP_BUILTINS @@ -108,5 +119,73 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA %{rdynamic:-export-dynamic} \ %{!dynamic-linker:-dynamic-linker /lib/ld64.so}}}" +extern unsigned int __isPATrange (void *); + +/* Exceptions macro defined for TPF so that functions without + dwarf frame information can be used with exceptions. */ +#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS) \ + do \ + { \ + unsigned long int regs_; \ + unsigned long int new_cfa_; \ + int i_; \ + \ + if ((CONTEXT)->cfa == NULL) \ + goto SUCCESS; \ + \ + /* Are we going through special linkage code? */ \ + if (__isPATrange((CONTEXT)->ra)) \ + { \ + /* No stack frame. */ \ + (FS)->cfa_how = CFA_REG_OFFSET; \ + (FS)->cfa_reg = 15; \ + (FS)->cfa_offset = STACK_POINTER_OFFSET; \ + \ + /* All registers remain unchanged ... */ \ + for (i_ = 0; i_ < 32; i_++) \ + { \ + (FS)->regs.reg[i_].how = REG_SAVED_REG; \ + (FS)->regs.reg[i_].loc.reg = i_; \ + } \ + \ + /* ... except for %r14, which is stored at CFA-112 \ + and used as return address. */ \ + (FS)->regs.reg[14].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[14].loc.offset = \ + TPF_LOC_DIFF_OFFSET - STACK_POINTER_OFFSET; \ + (FS)->retaddr_column = 14; \ + \ + goto SUCCESS; \ + \ + } \ + \ + regs_ = *((unsigned long int *) \ + (((unsigned long int) (CONTEXT)->cfa) - STACK_POINTER_OFFSET)); \ + new_cfa_ = regs_ + STACK_POINTER_OFFSET; \ + (FS)->cfa_how = CFA_REG_OFFSET; \ + (FS)->cfa_reg = 15; \ + (FS)->cfa_offset = new_cfa_ - \ + (unsigned long int) (CONTEXT)->cfa + STACK_POINTER_OFFSET; \ + \ + for (i_ = 0; i_ < 16; i_++) \ + { \ + (FS)->regs.reg[i_].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[i_].loc.offset = \ + (regs_+(i_*8)) - new_cfa_; \ + } \ + \ + for (i_ = 0; i_ < 4; i_++) \ + { \ + (FS)->regs.reg[16+i_].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[16+i_].loc.offset = \ + (regs_+(16*8)+(i_*8)) - new_cfa_; \ + } \ + \ + (FS)->retaddr_column = 14; \ + \ + goto SUCCESS; \ + \ + } while (0) + #endif /* ! _TPF_H */ -- 2.30.2