Line data Source code
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 8 : 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 8 : if ((pc & 0x3) != 0x3)
53 : return false;
54 6 : pc++;
55 : /* We can assume big-endian read here. */
56 6 : Dwarf_Word instr;
57 6 : if (! readfunc (pc, &instr, arg))
58 : return false;
59 : /* Fetch only the very first two bytes. */
60 6 : instr = (instr >> (ebl->class == ELFCLASS64 ? 48 : 16)) & 0xffff;
61 : /* See GDB s390_sigtramp_frame_sniffer. */
62 : /* Check for 'svc' as the first instruction. */
63 6 : if (((instr >> 8) & 0xff) != 0x0a)
64 : return false;
65 : /* Check for 'sigreturn' or 'rt_sigreturn' as the second instruction. */
66 0 : if ((instr & 0xff) != 119 && (instr & 0xff) != 173)
67 : return false;
68 : /* See GDB s390_sigtramp_frame_unwind_cache. */
69 0 : Dwarf_Word this_sp;
70 0 : if (! getfunc (0 + 15, 1, &this_sp, arg))
71 : return false;
72 0 : unsigned word_size = ebl->class == ELFCLASS64 ? 8 : 4;
73 0 : 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 0 : Dwarf_Word sigreg_ptr;
78 0 : if (! readfunc (next_cfa + 8, &sigreg_ptr, arg))
79 : return false;
80 : /* Skip PSW mask. */
81 0 : sigreg_ptr += word_size;
82 : /* Read PSW address. */
83 0 : Dwarf_Word val;
84 0 : if (! readfunc (sigreg_ptr, &val, arg))
85 : return false;
86 0 : if (! setfunc (-1, 1, &val, arg))
87 : return false;
88 0 : sigreg_ptr += word_size;
89 : /* Then the GPRs. */
90 0 : Dwarf_Word gprs[16];
91 0 : for (int i = 0; i < 16; i++)
92 : {
93 0 : if (! readfunc (sigreg_ptr, &gprs[i], arg))
94 : return false;
95 0 : sigreg_ptr += word_size;
96 : }
97 : /* Then the ACRs. Skip them, they are not used in CFI. */
98 0 : for (int i = 0; i < 16; i++)
99 0 : sigreg_ptr += 4;
100 : /* The floating-point control word. */
101 0 : sigreg_ptr += 8;
102 : /* And finally the FPRs. */
103 0 : Dwarf_Word fprs[16];
104 0 : for (int i = 0; i < 16; i++)
105 : {
106 0 : if (! readfunc (sigreg_ptr, &val, arg))
107 : return false;
108 0 : if (ebl->class == ELFCLASS32)
109 : {
110 0 : Dwarf_Addr val_low;
111 0 : if (! readfunc (sigreg_ptr + 4, &val_low, arg))
112 0 : return false;
113 0 : val = (val << 32) | val_low;
114 : }
115 0 : fprs[i] = val;
116 0 : sigreg_ptr += 8;
117 : }
118 : /* If we have them, the GPR upper halves are appended at the end. */
119 0 : if (ebl->class == ELFCLASS32)
120 : {
121 : /* Skip signal number. */
122 0 : sigreg_ptr += 4;
123 0 : for (int i = 0; i < 16; i++)
124 : {
125 0 : if (! readfunc (sigreg_ptr, &val, arg))
126 : return false;
127 0 : Dwarf_Word val_low = gprs[i];
128 0 : val = (val << 32) | val_low;
129 0 : gprs[i] = val;
130 0 : sigreg_ptr += 4;
131 : }
132 : }
133 0 : if (! setfunc (0, 16, gprs, arg))
134 : return false;
135 0 : if (! setfunc (16, 16, fprs, arg))
136 : return false;
137 0 : *signal_framep = true;
138 0 : return true;
139 : }
|