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