Home | History | Annotate | Line # | Download | only in s390
tpf-unwind.h revision 1.1.1.1
      1  1.1  mrg /* DWARF2 EH unwinding support for TPF OS.
      2  1.1  mrg    Copyright (C) 2004-2013 Free Software Foundation, Inc.
      3  1.1  mrg    Contributed by P.J. Darcy (darcypj (at) us.ibm.com).
      4  1.1  mrg 
      5  1.1  mrg This file is part of GCC.
      6  1.1  mrg 
      7  1.1  mrg GCC is free software; you can redistribute it and/or modify it under
      8  1.1  mrg the terms of the GNU General Public License as published by the Free
      9  1.1  mrg Software Foundation; either version 3, or (at your option) any later
     10  1.1  mrg version.
     11  1.1  mrg 
     12  1.1  mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     13  1.1  mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  1.1  mrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  1.1  mrg for more details.
     16  1.1  mrg 
     17  1.1  mrg Under Section 7 of GPL version 3, you are granted additional
     18  1.1  mrg permissions described in the GCC Runtime Library Exception, version
     19  1.1  mrg 3.1, as published by the Free Software Foundation.
     20  1.1  mrg 
     21  1.1  mrg You should have received a copy of the GNU General Public License and
     22  1.1  mrg a copy of the GCC Runtime Library Exception along with this program;
     23  1.1  mrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     24  1.1  mrg <http://www.gnu.org/licenses/>.  */
     25  1.1  mrg 
     26  1.1  mrg #include <dlfcn.h>
     27  1.1  mrg 
     28  1.1  mrg /* Function Name: __isPATrange
     29  1.1  mrg    Parameters passed into it:  address to check
     30  1.1  mrg    Return Value: A 1 if address is in pat code "range", 0 if not
     31  1.1  mrg    Description: This function simply checks to see if the address
     32  1.1  mrg    passed to it is in the CP pat code range.  */
     33  1.1  mrg 
     34  1.1  mrg #define MIN_PATRANGE 0x10000
     35  1.1  mrg #define MAX_PATRANGE 0x800000
     36  1.1  mrg 
     37  1.1  mrg static inline unsigned int
     38  1.1  mrg __isPATrange (void *addr)
     39  1.1  mrg {
     40  1.1  mrg   if (addr > (void *)MIN_PATRANGE && addr < (void *)MAX_PATRANGE)
     41  1.1  mrg     return 1;
     42  1.1  mrg   else
     43  1.1  mrg     return 0;
     44  1.1  mrg }
     45  1.1  mrg 
     46  1.1  mrg /* TPF return address offset from start of stack frame.  */
     47  1.1  mrg #define TPFRA_OFFSET 168
     48  1.1  mrg 
     49  1.1  mrg /* Exceptions macro defined for TPF so that functions without
     50  1.1  mrg    dwarf frame information can be used with exceptions.  */
     51  1.1  mrg #define MD_FALLBACK_FRAME_STATE_FOR s390_fallback_frame_state
     52  1.1  mrg 
     53  1.1  mrg static _Unwind_Reason_Code
     54  1.1  mrg s390_fallback_frame_state (struct _Unwind_Context *context,
     55  1.1  mrg 			   _Unwind_FrameState *fs)
     56  1.1  mrg {
     57  1.1  mrg   unsigned long int regs;
     58  1.1  mrg   unsigned long int new_cfa;
     59  1.1  mrg   int i;
     60  1.1  mrg 
     61  1.1  mrg   regs = *((unsigned long int *)
     62  1.1  mrg         (((unsigned long int) context->cfa) - STACK_POINTER_OFFSET));
     63  1.1  mrg 
     64  1.1  mrg   /* Are we going through special linkage code?  */
     65  1.1  mrg   if (__isPATrange (context->ra))
     66  1.1  mrg     {
     67  1.1  mrg 
     68  1.1  mrg       /* Our return register isn't zero for end of stack, so
     69  1.1  mrg          check backward stackpointer to see if it is zero.  */
     70  1.1  mrg       if (regs == NULL)
     71  1.1  mrg          return _URC_END_OF_STACK;
     72  1.1  mrg 
     73  1.1  mrg       /* No stack frame.  */
     74  1.1  mrg       fs->regs.cfa_how = CFA_REG_OFFSET;
     75  1.1  mrg       fs->regs.cfa_reg = 15;
     76  1.1  mrg       fs->regs.cfa_offset = STACK_POINTER_OFFSET;
     77  1.1  mrg 
     78  1.1  mrg       /* All registers remain unchanged ...  */
     79  1.1  mrg       for (i = 0; i < 32; i++)
     80  1.1  mrg 	{
     81  1.1  mrg 	  fs->regs.reg[i].how = REG_SAVED_REG;
     82  1.1  mrg 	  fs->regs.reg[i].loc.reg = i;
     83  1.1  mrg 	}
     84  1.1  mrg 
     85  1.1  mrg       /* ... except for %r14, which is stored at CFA-112
     86  1.1  mrg 	 and used as return address.  */
     87  1.1  mrg       fs->regs.reg[14].how = REG_SAVED_OFFSET;
     88  1.1  mrg       fs->regs.reg[14].loc.offset = TPFRA_OFFSET - STACK_POINTER_OFFSET;
     89  1.1  mrg       fs->retaddr_column = 14;
     90  1.1  mrg 
     91  1.1  mrg       return _URC_NO_REASON;
     92  1.1  mrg     }
     93  1.1  mrg 
     94  1.1  mrg   regs = *((unsigned long int *)
     95  1.1  mrg         (((unsigned long int) context->cfa) - STACK_POINTER_OFFSET));
     96  1.1  mrg   new_cfa = regs + STACK_POINTER_OFFSET;
     97  1.1  mrg 
     98  1.1  mrg   fs->regs.cfa_how = CFA_REG_OFFSET;
     99  1.1  mrg   fs->regs.cfa_reg = 15;
    100  1.1  mrg   fs->regs.cfa_offset = new_cfa -
    101  1.1  mrg         (unsigned long int) context->cfa + STACK_POINTER_OFFSET;
    102  1.1  mrg 
    103  1.1  mrg   for (i = 0; i < 16; i++)
    104  1.1  mrg     {
    105  1.1  mrg       fs->regs.reg[i].how = REG_SAVED_OFFSET;
    106  1.1  mrg       fs->regs.reg[i].loc.offset = regs + i*8 - new_cfa;
    107  1.1  mrg     }
    108  1.1  mrg 
    109  1.1  mrg   for (i = 0; i < 4; i++)
    110  1.1  mrg     {
    111  1.1  mrg       fs->regs.reg[16 + i].how = REG_SAVED_OFFSET;
    112  1.1  mrg       fs->regs.reg[16 + i].loc.offset = regs + 16*8 + i*8 - new_cfa;
    113  1.1  mrg     }
    114  1.1  mrg 
    115  1.1  mrg   fs->retaddr_column = 14;
    116  1.1  mrg 
    117  1.1  mrg   return _URC_NO_REASON;
    118  1.1  mrg }
    119  1.1  mrg 
    120  1.1  mrg /* Function Name: __tpf_eh_return
    121  1.1  mrg    Parameters passed into it: Destination address to jump to.
    122  1.1  mrg    Return Value: Converted Destination address if a Pat Stub exists.
    123  1.1  mrg    Description: This function swaps the unwinding return address
    124  1.1  mrg       with the cp stub code.  The original target return address is
    125  1.1  mrg       then stored into the tpf return address field.  The cp stub
    126  1.1  mrg       code is searched for by climbing back up the stack and
    127  1.1  mrg       comparing the tpf stored return address object address to
    128  1.1  mrg       that of the targets object address.  */
    129  1.1  mrg 
    130  1.1  mrg #define CURRENT_STACK_PTR() \
    131  1.1  mrg   ({ register unsigned long int *stack_ptr asm ("%r15"); stack_ptr; })
    132  1.1  mrg 
    133  1.1  mrg #define PREVIOUS_STACK_PTR() \
    134  1.1  mrg   ((unsigned long int *)(*(CURRENT_STACK_PTR())))
    135  1.1  mrg 
    136  1.1  mrg #define RA_OFFSET 112
    137  1.1  mrg #define R15_OFFSET 120
    138  1.1  mrg #define TPFAREA_OFFSET 160
    139  1.1  mrg #define TPFAREA_SIZE STACK_POINTER_OFFSET-TPFAREA_OFFSET
    140  1.1  mrg #define INVALID_RETURN 0
    141  1.1  mrg 
    142  1.1  mrg void * __tpf_eh_return (void *target);
    143  1.1  mrg 
    144  1.1  mrg void *
    145  1.1  mrg __tpf_eh_return (void *target)
    146  1.1  mrg {
    147  1.1  mrg   Dl_info targetcodeInfo, currentcodeInfo;
    148  1.1  mrg   int retval;
    149  1.1  mrg   void *current, *stackptr, *destination_frame;
    150  1.1  mrg   unsigned long int shifter, is_a_stub;
    151  1.1  mrg 
    152  1.1  mrg   is_a_stub = 0;
    153  1.1  mrg 
    154  1.1  mrg   /* Get code info for target return's address.  */
    155  1.1  mrg   retval = dladdr (target, &targetcodeInfo);
    156  1.1  mrg 
    157  1.1  mrg   /* Ensure the code info is valid (for target).  */
    158  1.1  mrg   if (retval != INVALID_RETURN)
    159  1.1  mrg     {
    160  1.1  mrg 
    161  1.1  mrg       /* Get the stack pointer of the stack frame to be modified by
    162  1.1  mrg          the exception unwinder.  So that we can begin our climb
    163  1.1  mrg          there.  */
    164  1.1  mrg       stackptr = (void *) *((unsigned long int *) (*(PREVIOUS_STACK_PTR())));
    165  1.1  mrg 
    166  1.1  mrg       /* Begin looping through stack frames.  Stop if invalid
    167  1.1  mrg          code information is retrieved or if a match between the
    168  1.1  mrg          current stack frame iteration shared object's address
    169  1.1  mrg          matches that of the target, calculated above.  */
    170  1.1  mrg       do
    171  1.1  mrg         {
    172  1.1  mrg           /* Get return address based on our stackptr iterator.  */
    173  1.1  mrg           current = (void *) *((unsigned long int *)
    174  1.1  mrg                       (stackptr+RA_OFFSET));
    175  1.1  mrg 
    176  1.1  mrg           /* Is it a Pat Stub?  */
    177  1.1  mrg           if (__isPATrange (current))
    178  1.1  mrg             {
    179  1.1  mrg               /* Yes it was, get real return address
    180  1.1  mrg                  in TPF stack area.  */
    181  1.1  mrg               current = (void *) *((unsigned long int *)
    182  1.1  mrg                           (stackptr+TPFRA_OFFSET));
    183  1.1  mrg               is_a_stub = 1;
    184  1.1  mrg             }
    185  1.1  mrg 
    186  1.1  mrg           /* Get codeinfo on RA so that we can figure out
    187  1.1  mrg              the module address.  */
    188  1.1  mrg           retval = dladdr (current, &currentcodeInfo);
    189  1.1  mrg 
    190  1.1  mrg           /* Check that codeinfo for current stack frame is valid.
    191  1.1  mrg              Then compare the module address of current stack frame
    192  1.1  mrg              to target stack frame to determine if we have the pat
    193  1.1  mrg              stub address we want.  Also ensure we are dealing
    194  1.1  mrg              with a module crossing, stub return address. */
    195  1.1  mrg           if (is_a_stub && retval != INVALID_RETURN
    196  1.1  mrg              && targetcodeInfo.dli_fbase == currentcodeInfo.dli_fbase)
    197  1.1  mrg              {
    198  1.1  mrg                /* Yes! They are in the same module.
    199  1.1  mrg                   Force copy of TPF private stack area to
    200  1.1  mrg                   destination stack frame TPF private area. */
    201  1.1  mrg                destination_frame = (void *) *((unsigned long int *)
    202  1.1  mrg                    (*PREVIOUS_STACK_PTR() + R15_OFFSET));
    203  1.1  mrg 
    204  1.1  mrg                /* Copy TPF linkage area from current frame to
    205  1.1  mrg                   destination frame.  */
    206  1.1  mrg                memcpy((void *) (destination_frame + TPFAREA_OFFSET),
    207  1.1  mrg                  (void *) (stackptr + TPFAREA_OFFSET), TPFAREA_SIZE);
    208  1.1  mrg 
    209  1.1  mrg                /* Now overlay the
    210  1.1  mrg                   real target address into the TPF stack area of
    211  1.1  mrg                   the target frame we are jumping to.  */
    212  1.1  mrg                *((unsigned long int *) (destination_frame +
    213  1.1  mrg                    TPFRA_OFFSET)) = (unsigned long int) target;
    214  1.1  mrg 
    215  1.1  mrg                /* Before returning the desired pat stub address to
    216  1.1  mrg                   the exception handling unwinder so that it can
    217  1.1  mrg                   actually do the "leap" shift out the low order
    218  1.1  mrg                   bit designated to determine if we are in 64BIT mode.
    219  1.1  mrg                   This is necessary for CTOA stubs.
    220  1.1  mrg                   Otherwise we leap one byte past where we want to
    221  1.1  mrg                   go to in the TPF pat stub linkage code.  */
    222  1.1  mrg                shifter = *((unsigned long int *)
    223  1.1  mrg                      (stackptr + RA_OFFSET));
    224  1.1  mrg 
    225  1.1  mrg                shifter &= ~1ul;
    226  1.1  mrg 
    227  1.1  mrg                /* Store Pat Stub Address in destination Stack Frame.  */
    228  1.1  mrg                *((unsigned long int *) (destination_frame +
    229  1.1  mrg                    RA_OFFSET)) = shifter;
    230  1.1  mrg 
    231  1.1  mrg                /* Re-adjust pat stub address to go to correct place
    232  1.1  mrg                   in linkage.  */
    233  1.1  mrg                shifter = shifter - 4;
    234  1.1  mrg 
    235  1.1  mrg                return (void *) shifter;
    236  1.1  mrg              }
    237  1.1  mrg 
    238  1.1  mrg           /* Desired module pat stub not found ...
    239  1.1  mrg              Bump stack frame iterator.  */
    240  1.1  mrg           stackptr = (void *) *(unsigned long int *) stackptr;
    241  1.1  mrg 
    242  1.1  mrg           is_a_stub = 0;
    243  1.1  mrg 
    244  1.1  mrg         }  while (stackptr && retval != INVALID_RETURN
    245  1.1  mrg                 && targetcodeInfo.dli_fbase != currentcodeInfo.dli_fbase);
    246  1.1  mrg     }
    247  1.1  mrg 
    248  1.1  mrg   /* No pat stub found, could be a problem?  Simply return unmodified
    249  1.1  mrg      target address.  */
    250  1.1  mrg   return target;
    251  1.1  mrg }
    252  1.1  mrg 
    253