Home | History | Annotate | Line # | Download | only in s390
tpf-unwind.h revision 1.1.1.3.4.2
      1          1.1     mrg /* DWARF2 EH unwinding support for TPF OS.
      2  1.1.1.3.4.2  martin    Copyright (C) 2004-2018 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.1.2     mrg #include <stdbool.h>
     28          1.1     mrg 
     29          1.1     mrg /* Function Name: __isPATrange
     30          1.1     mrg    Parameters passed into it:  address to check
     31          1.1     mrg    Return Value: A 1 if address is in pat code "range", 0 if not
     32          1.1     mrg    Description: This function simply checks to see if the address
     33          1.1     mrg    passed to it is in the CP pat code range.  */
     34          1.1     mrg 
     35          1.1     mrg #define MIN_PATRANGE 0x10000
     36          1.1     mrg #define MAX_PATRANGE 0x800000
     37          1.1     mrg 
     38          1.1     mrg static inline unsigned int
     39          1.1     mrg __isPATrange (void *addr)
     40          1.1     mrg {
     41          1.1     mrg   if (addr > (void *)MIN_PATRANGE && addr < (void *)MAX_PATRANGE)
     42          1.1     mrg     return 1;
     43          1.1     mrg   else
     44          1.1     mrg     return 0;
     45          1.1     mrg }
     46          1.1     mrg 
     47          1.1     mrg /* TPF return address offset from start of stack frame.  */
     48          1.1     mrg #define TPFRA_OFFSET 168
     49          1.1     mrg 
     50          1.1     mrg /* Exceptions macro defined for TPF so that functions without
     51          1.1     mrg    dwarf frame information can be used with exceptions.  */
     52          1.1     mrg #define MD_FALLBACK_FRAME_STATE_FOR s390_fallback_frame_state
     53          1.1     mrg 
     54          1.1     mrg static _Unwind_Reason_Code
     55          1.1     mrg s390_fallback_frame_state (struct _Unwind_Context *context,
     56          1.1     mrg 			   _Unwind_FrameState *fs)
     57          1.1     mrg {
     58          1.1     mrg   unsigned long int regs;
     59          1.1     mrg   unsigned long int new_cfa;
     60          1.1     mrg   int i;
     61          1.1     mrg 
     62          1.1     mrg   regs = *((unsigned long int *)
     63          1.1     mrg         (((unsigned long int) context->cfa) - STACK_POINTER_OFFSET));
     64          1.1     mrg 
     65          1.1     mrg   /* Are we going through special linkage code?  */
     66          1.1     mrg   if (__isPATrange (context->ra))
     67          1.1     mrg     {
     68          1.1     mrg 
     69          1.1     mrg       /* Our return register isn't zero for end of stack, so
     70          1.1     mrg          check backward stackpointer to see if it is zero.  */
     71          1.1     mrg       if (regs == NULL)
     72          1.1     mrg          return _URC_END_OF_STACK;
     73          1.1     mrg 
     74          1.1     mrg       /* No stack frame.  */
     75          1.1     mrg       fs->regs.cfa_how = CFA_REG_OFFSET;
     76          1.1     mrg       fs->regs.cfa_reg = 15;
     77          1.1     mrg       fs->regs.cfa_offset = STACK_POINTER_OFFSET;
     78          1.1     mrg 
     79          1.1     mrg       /* All registers remain unchanged ...  */
     80          1.1     mrg       for (i = 0; i < 32; i++)
     81          1.1     mrg 	{
     82          1.1     mrg 	  fs->regs.reg[i].how = REG_SAVED_REG;
     83          1.1     mrg 	  fs->regs.reg[i].loc.reg = i;
     84          1.1     mrg 	}
     85          1.1     mrg 
     86          1.1     mrg       /* ... except for %r14, which is stored at CFA-112
     87          1.1     mrg 	 and used as return address.  */
     88          1.1     mrg       fs->regs.reg[14].how = REG_SAVED_OFFSET;
     89          1.1     mrg       fs->regs.reg[14].loc.offset = TPFRA_OFFSET - STACK_POINTER_OFFSET;
     90          1.1     mrg       fs->retaddr_column = 14;
     91          1.1     mrg 
     92          1.1     mrg       return _URC_NO_REASON;
     93          1.1     mrg     }
     94          1.1     mrg 
     95          1.1     mrg   regs = *((unsigned long int *)
     96          1.1     mrg         (((unsigned long int) context->cfa) - STACK_POINTER_OFFSET));
     97          1.1     mrg   new_cfa = regs + STACK_POINTER_OFFSET;
     98          1.1     mrg 
     99          1.1     mrg   fs->regs.cfa_how = CFA_REG_OFFSET;
    100          1.1     mrg   fs->regs.cfa_reg = 15;
    101          1.1     mrg   fs->regs.cfa_offset = new_cfa -
    102          1.1     mrg         (unsigned long int) context->cfa + STACK_POINTER_OFFSET;
    103          1.1     mrg 
    104          1.1     mrg   for (i = 0; i < 16; i++)
    105          1.1     mrg     {
    106          1.1     mrg       fs->regs.reg[i].how = REG_SAVED_OFFSET;
    107          1.1     mrg       fs->regs.reg[i].loc.offset = regs + i*8 - new_cfa;
    108          1.1     mrg     }
    109          1.1     mrg 
    110          1.1     mrg   for (i = 0; i < 4; i++)
    111          1.1     mrg     {
    112          1.1     mrg       fs->regs.reg[16 + i].how = REG_SAVED_OFFSET;
    113          1.1     mrg       fs->regs.reg[16 + i].loc.offset = regs + 16*8 + i*8 - new_cfa;
    114          1.1     mrg     }
    115          1.1     mrg 
    116          1.1     mrg   fs->retaddr_column = 14;
    117          1.1     mrg 
    118          1.1     mrg   return _URC_NO_REASON;
    119          1.1     mrg }
    120          1.1     mrg 
    121          1.1     mrg /* Function Name: __tpf_eh_return
    122          1.1     mrg    Parameters passed into it: Destination address to jump to.
    123          1.1     mrg    Return Value: Converted Destination address if a Pat Stub exists.
    124          1.1     mrg    Description: This function swaps the unwinding return address
    125          1.1     mrg       with the cp stub code.  The original target return address is
    126          1.1     mrg       then stored into the tpf return address field.  The cp stub
    127          1.1     mrg       code is searched for by climbing back up the stack and
    128          1.1     mrg       comparing the tpf stored return address object address to
    129          1.1     mrg       that of the targets object address.  */
    130          1.1     mrg 
    131          1.1     mrg #define CURRENT_STACK_PTR() \
    132          1.1     mrg   ({ register unsigned long int *stack_ptr asm ("%r15"); stack_ptr; })
    133          1.1     mrg 
    134          1.1     mrg #define PREVIOUS_STACK_PTR() \
    135          1.1     mrg   ((unsigned long int *)(*(CURRENT_STACK_PTR())))
    136          1.1     mrg 
    137          1.1     mrg #define RA_OFFSET 112
    138          1.1     mrg #define R15_OFFSET 120
    139          1.1     mrg #define TPFAREA_OFFSET 160
    140          1.1     mrg #define TPFAREA_SIZE STACK_POINTER_OFFSET-TPFAREA_OFFSET
    141          1.1     mrg #define INVALID_RETURN 0
    142          1.1     mrg 
    143      1.1.1.2     mrg void * __tpf_eh_return (void *target, void *origRA);
    144          1.1     mrg 
    145          1.1     mrg void *
    146      1.1.1.2     mrg __tpf_eh_return (void *target, void *origRA)
    147          1.1     mrg {
    148          1.1     mrg   Dl_info targetcodeInfo, currentcodeInfo;
    149          1.1     mrg   int retval;
    150          1.1     mrg   void *current, *stackptr, *destination_frame;
    151      1.1.1.2     mrg   unsigned long int shifter;
    152      1.1.1.2     mrg   bool is_a_stub, frameDepth2, firstIteration;
    153          1.1     mrg 
    154      1.1.1.2     mrg   is_a_stub = false;
    155      1.1.1.2     mrg   frameDepth2 = false;
    156      1.1.1.2     mrg   firstIteration = true;
    157          1.1     mrg 
    158          1.1     mrg   /* Get code info for target return's address.  */
    159          1.1     mrg   retval = dladdr (target, &targetcodeInfo);
    160          1.1     mrg 
    161      1.1.1.2     mrg   /* Check if original RA is a Pat stub.  If so set flag.  */
    162      1.1.1.2     mrg   if (__isPATrange (origRA))
    163      1.1.1.2     mrg     frameDepth2 = true;
    164      1.1.1.2     mrg 
    165          1.1     mrg   /* Ensure the code info is valid (for target).  */
    166          1.1     mrg   if (retval != INVALID_RETURN)
    167          1.1     mrg     {
    168      1.1.1.2     mrg       /* Get the stack pointer of the first stack frame beyond the
    169      1.1.1.2     mrg          unwinder or if exists the calling C++ runtime function (e.g.,
    170      1.1.1.2     mrg          __cxa_throw).  */
    171      1.1.1.2     mrg       if (!frameDepth2)
    172      1.1.1.2     mrg         stackptr = (void *) *((unsigned long int *) (*(PREVIOUS_STACK_PTR())));
    173      1.1.1.2     mrg       else
    174      1.1.1.2     mrg         stackptr = (void *) *(PREVIOUS_STACK_PTR());
    175          1.1     mrg 
    176          1.1     mrg       /* Begin looping through stack frames.  Stop if invalid
    177          1.1     mrg          code information is retrieved or if a match between the
    178          1.1     mrg          current stack frame iteration shared object's address
    179          1.1     mrg          matches that of the target, calculated above.  */
    180          1.1     mrg       do
    181          1.1     mrg         {
    182      1.1.1.2     mrg           if (!frameDepth2 || (frameDepth2 && !firstIteration))
    183      1.1.1.2     mrg             {
    184      1.1.1.2     mrg               /* Get return address based on our stackptr iterator.  */
    185      1.1.1.2     mrg               current = (void *) *((unsigned long int *)
    186      1.1.1.2     mrg                                    (stackptr + RA_OFFSET));
    187          1.1     mrg 
    188      1.1.1.2     mrg               /* Is it a Pat Stub?  */
    189      1.1.1.2     mrg               if (__isPATrange (current))
    190      1.1.1.2     mrg                 {
    191      1.1.1.2     mrg                   /* Yes it was, get real return address in TPF stack area.  */
    192      1.1.1.2     mrg                   current = (void *) *((unsigned long int *)
    193      1.1.1.2     mrg                                        (stackptr + TPFRA_OFFSET))
    194      1.1.1.2     mrg                   is_a_stub = true;
    195      1.1.1.2     mrg                 }
    196      1.1.1.2     mrg             }
    197      1.1.1.2     mrg           else
    198          1.1     mrg             {
    199          1.1     mrg               current = (void *) *((unsigned long int *)
    200      1.1.1.2     mrg                                    (stackptr + TPFRA_OFFSET));
    201      1.1.1.2     mrg               is_a_stub = true;
    202          1.1     mrg             }
    203          1.1     mrg 
    204          1.1     mrg           /* Get codeinfo on RA so that we can figure out
    205          1.1     mrg              the module address.  */
    206          1.1     mrg           retval = dladdr (current, &currentcodeInfo);
    207          1.1     mrg 
    208          1.1     mrg           /* Check that codeinfo for current stack frame is valid.
    209          1.1     mrg              Then compare the module address of current stack frame
    210          1.1     mrg              to target stack frame to determine if we have the pat
    211          1.1     mrg              stub address we want.  Also ensure we are dealing
    212          1.1     mrg              with a module crossing, stub return address. */
    213          1.1     mrg           if (is_a_stub && retval != INVALID_RETURN
    214          1.1     mrg              && targetcodeInfo.dli_fbase == currentcodeInfo.dli_fbase)
    215          1.1     mrg              {
    216          1.1     mrg                /* Yes! They are in the same module.
    217          1.1     mrg                   Force copy of TPF private stack area to
    218          1.1     mrg                   destination stack frame TPF private area. */
    219          1.1     mrg                destination_frame = (void *) *((unsigned long int *)
    220          1.1     mrg                    (*PREVIOUS_STACK_PTR() + R15_OFFSET));
    221          1.1     mrg 
    222          1.1     mrg                /* Copy TPF linkage area from current frame to
    223          1.1     mrg                   destination frame.  */
    224          1.1     mrg                memcpy((void *) (destination_frame + TPFAREA_OFFSET),
    225          1.1     mrg                  (void *) (stackptr + TPFAREA_OFFSET), TPFAREA_SIZE);
    226          1.1     mrg 
    227          1.1     mrg                /* Now overlay the
    228          1.1     mrg                   real target address into the TPF stack area of
    229          1.1     mrg                   the target frame we are jumping to.  */
    230          1.1     mrg                *((unsigned long int *) (destination_frame +
    231          1.1     mrg                    TPFRA_OFFSET)) = (unsigned long int) target;
    232          1.1     mrg 
    233          1.1     mrg                /* Before returning the desired pat stub address to
    234          1.1     mrg                   the exception handling unwinder so that it can
    235          1.1     mrg                   actually do the "leap" shift out the low order
    236          1.1     mrg                   bit designated to determine if we are in 64BIT mode.
    237          1.1     mrg                   This is necessary for CTOA stubs.
    238          1.1     mrg                   Otherwise we leap one byte past where we want to
    239          1.1     mrg                   go to in the TPF pat stub linkage code.  */
    240      1.1.1.2     mrg                if (!frameDepth2 || (frameDepth2 && !firstIteration))
    241      1.1.1.2     mrg                  shifter = *((unsigned long int *) (stackptr + RA_OFFSET));
    242      1.1.1.2     mrg                else
    243      1.1.1.2     mrg                  shifter = (unsigned long int) origRA;
    244          1.1     mrg 
    245          1.1     mrg                shifter &= ~1ul;
    246          1.1     mrg 
    247          1.1     mrg                /* Store Pat Stub Address in destination Stack Frame.  */
    248          1.1     mrg                *((unsigned long int *) (destination_frame +
    249          1.1     mrg                    RA_OFFSET)) = shifter;
    250          1.1     mrg 
    251          1.1     mrg                /* Re-adjust pat stub address to go to correct place
    252          1.1     mrg                   in linkage.  */
    253          1.1     mrg                shifter = shifter - 4;
    254          1.1     mrg 
    255          1.1     mrg                return (void *) shifter;
    256          1.1     mrg              }
    257          1.1     mrg 
    258          1.1     mrg           /* Desired module pat stub not found ...
    259          1.1     mrg              Bump stack frame iterator.  */
    260          1.1     mrg           stackptr = (void *) *(unsigned long int *) stackptr;
    261          1.1     mrg 
    262      1.1.1.2     mrg           is_a_stub = false;
    263      1.1.1.2     mrg           firstIteration = false;
    264          1.1     mrg 
    265          1.1     mrg         }  while (stackptr && retval != INVALID_RETURN
    266          1.1     mrg                 && targetcodeInfo.dli_fbase != currentcodeInfo.dli_fbase);
    267          1.1     mrg     }
    268          1.1     mrg 
    269          1.1     mrg   /* No pat stub found, could be a problem?  Simply return unmodified
    270          1.1     mrg      target address.  */
    271          1.1     mrg   return target;
    272          1.1     mrg }
    273          1.1     mrg 
    274