Home | History | Annotate | Download | only in backends
      1 /* Get previous frame state for an existing frame state.
      2    Copyright (C) 2013 Red Hat, Inc.
      3    This file is part of elfutils.
      4 
      5    This file is free software; you can redistribute it and/or modify
      6    it under the terms of either
      7 
      8      * the GNU Lesser General Public License as published by the Free
      9        Software Foundation; either version 3 of the License, or (at
     10        your option) any later version
     11 
     12    or
     13 
     14      * the GNU General Public License as published by the Free
     15        Software Foundation; either version 2 of the License, or (at
     16        your option) any later version
     17 
     18    or both in parallel, as here.
     19 
     20    elfutils is distributed in the hope that it will be useful, but
     21    WITHOUT ANY WARRANTY; without even the implied warranty of
     22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     23    General Public License for more details.
     24 
     25    You should have received copies of the GNU General Public License and
     26    the GNU Lesser General Public License along with this program.  If
     27    not, see <http://www.gnu.org/licenses/>.  */
     28 
     29 #ifdef HAVE_CONFIG_H
     30 # include <config.h>
     31 #endif
     32 
     33 #include <stdlib.h>
     34 #include <assert.h>
     35 
     36 #define BACKEND s390_
     37 #include "libebl_CPU.h"
     38 
     39 /* s390/s390x do not annotate signal handler frame by CFI.  It would be also
     40    difficult as PC points into a stub built on stack.  Function below is called
     41    only if unwinder could not find CFI.  Function then verifies the register
     42    state for this frame really belongs to a signal frame.  In such case it
     43    fetches original registers saved by the signal frame.  */
     44 
     45 bool
     46 s390_unwind (Ebl *ebl, Dwarf_Addr pc, ebl_tid_registers_t *setfunc,
     47 	     ebl_tid_registers_get_t *getfunc, ebl_pid_memory_read_t *readfunc,
     48 	     void *arg, bool *signal_framep)
     49 {
     50   /* Caller already assumed caller adjustment but S390 instructions are 4 bytes
     51      long.  Undo it.  */
     52   if ((pc & 0x3) != 0x3)
     53     return false;
     54   pc++;
     55   /* We can assume big-endian read here.  */
     56   Dwarf_Word instr;
     57   if (! readfunc (pc, &instr, arg))
     58     return false;
     59   /* Fetch only the very first two bytes.  */
     60   instr = (instr >> (ebl->class == ELFCLASS64 ? 48 : 16)) & 0xffff;
     61   /* See GDB s390_sigtramp_frame_sniffer.  */
     62   /* Check for 'svc' as the first instruction.  */
     63   if (((instr >> 8) & 0xff) != 0x0a)
     64     return false;
     65   /* Check for 'sigreturn' or 'rt_sigreturn' as the second instruction.  */
     66   if ((instr & 0xff) != 119 && (instr & 0xff) != 173)
     67     return false;
     68   /* See GDB s390_sigtramp_frame_unwind_cache.  */
     69   Dwarf_Word this_sp;
     70   if (! getfunc (0 + 15, 1, &this_sp, arg))
     71     return false;
     72   unsigned word_size = ebl->class == ELFCLASS64 ? 8 : 4;
     73   Dwarf_Addr next_cfa = this_sp + 16 * word_size + 32;
     74   /* "New-style RT frame" is not supported,
     75      assuming "Old-style RT frame and all non-RT frames".
     76      Pointer to the array of saved registers is at NEXT_CFA + 8.  */
     77   Dwarf_Word sigreg_ptr;
     78   if (! readfunc (next_cfa + 8, &sigreg_ptr, arg))
     79     return false;
     80   /* Skip PSW mask.  */
     81   sigreg_ptr += word_size;
     82   /* Read PSW address.  */
     83   Dwarf_Word val;
     84   if (! readfunc (sigreg_ptr, &val, arg))
     85     return false;
     86   if (! setfunc (-1, 1, &val, arg))
     87     return false;
     88   sigreg_ptr += word_size;
     89   /* Then the GPRs.  */
     90   Dwarf_Word gprs[16];
     91   for (int i = 0; i < 16; i++)
     92     {
     93       if (! readfunc (sigreg_ptr, &gprs[i], arg))
     94 	return false;
     95       sigreg_ptr += word_size;
     96     }
     97   /* Then the ACRs.  Skip them, they are not used in CFI.  */
     98   for (int i = 0; i < 16; i++)
     99     sigreg_ptr += 4;
    100   /* The floating-point control word.  */
    101   sigreg_ptr += 8;
    102   /* And finally the FPRs.  */
    103   Dwarf_Word fprs[16];
    104   for (int i = 0; i < 16; i++)
    105     {
    106       if (! readfunc (sigreg_ptr, &val, arg))
    107 	return false;
    108       if (ebl->class == ELFCLASS32)
    109 	{
    110 	  Dwarf_Addr val_low;
    111 	  if (! readfunc (sigreg_ptr + 4, &val_low, arg))
    112 	    return false;
    113 	  val = (val << 32) | val_low;
    114 	}
    115       fprs[i] = val;
    116       sigreg_ptr += 8;
    117     }
    118   /* If we have them, the GPR upper halves are appended at the end.  */
    119   if (ebl->class == ELFCLASS32)
    120     {
    121       /* Skip signal number.  */
    122       sigreg_ptr += 4;
    123       for (int i = 0; i < 16; i++)
    124 	{
    125 	  if (! readfunc (sigreg_ptr, &val, arg))
    126 	    return false;
    127 	  Dwarf_Word val_low = gprs[i];
    128 	  val = (val << 32) | val_low;
    129 	  gprs[i] = val;
    130 	  sigreg_ptr += 4;
    131 	}
    132     }
    133   if (! setfunc (0, 16, gprs, arg))
    134     return false;
    135   if (! setfunc (16, 16, fprs, arg))
    136     return false;
    137   *signal_framep = true;
    138   return true;
    139 }
    140