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