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