gdb/testsuite/
[deliverable/binutils-gdb.git] / gdb / gdbserver / linux-s390-low.c
CommitLineData
265f716b
DJ
1/* GNU/Linux S/390 specific low level interface, for the remote server
2 for GDB.
4c38e0a4 3 Copyright (C) 2001, 2002, 2005, 2006, 2007, 2008, 2009, 2010
9b254dd1 4 Free Software Foundation, Inc.
265f716b
DJ
5
6 This file is part of GDB.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
a9762ec7 10 the Free Software Foundation; either version 3 of the License, or
265f716b
DJ
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
a9762ec7 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
265f716b
DJ
20
21/* This file is used for both 31-bit and 64-bit S/390 systems. */
22
23#include "server.h"
24#include "linux-low.h"
25
26#include <asm/ptrace.h>
7803799a 27#include <elf.h>
265f716b 28
7803799a
UW
29#ifndef HWCAP_S390_HIGH_GPRS
30#define HWCAP_S390_HIGH_GPRS 512
31#endif
d05b4ac3 32
7803799a
UW
33/* Defined in auto-generated file s390-linux32.c. */
34void init_registers_s390_linux32 (void);
35/* Defined in auto-generated file s390-linux64.c. */
36void init_registers_s390_linux64 (void);
37/* Defined in auto-generated file s390x-linux64.c. */
38void init_registers_s390x_linux64 (void);
d05b4ac3 39
d0f54f9d 40#define s390_num_regs 51
265f716b 41
2ec06d2e 42static int s390_regmap[] = {
265f716b
DJ
43 PT_PSWMASK, PT_PSWADDR,
44
45 PT_GPR0, PT_GPR1, PT_GPR2, PT_GPR3,
46 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
47 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
48 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15,
49
50 PT_ACR0, PT_ACR1, PT_ACR2, PT_ACR3,
51 PT_ACR4, PT_ACR5, PT_ACR6, PT_ACR7,
52 PT_ACR8, PT_ACR9, PT_ACR10, PT_ACR11,
53 PT_ACR12, PT_ACR13, PT_ACR14, PT_ACR15,
54
265f716b
DJ
55 PT_FPC,
56
d0f54f9d 57#ifndef __s390x__
265f716b
DJ
58 PT_FPR0_HI, PT_FPR1_HI, PT_FPR2_HI, PT_FPR3_HI,
59 PT_FPR4_HI, PT_FPR5_HI, PT_FPR6_HI, PT_FPR7_HI,
60 PT_FPR8_HI, PT_FPR9_HI, PT_FPR10_HI, PT_FPR11_HI,
61 PT_FPR12_HI, PT_FPR13_HI, PT_FPR14_HI, PT_FPR15_HI,
62#else
63 PT_FPR0, PT_FPR1, PT_FPR2, PT_FPR3,
64 PT_FPR4, PT_FPR5, PT_FPR6, PT_FPR7,
65 PT_FPR8, PT_FPR9, PT_FPR10, PT_FPR11,
66 PT_FPR12, PT_FPR13, PT_FPR14, PT_FPR15,
67#endif
68};
69
7803799a
UW
70#ifdef __s390x__
71#define s390_num_regs_3264 67
72
73static int s390_regmap_3264[] = {
74 PT_PSWMASK, PT_PSWADDR,
75
76 PT_GPR0, PT_GPR0, PT_GPR1, PT_GPR1, PT_GPR2, PT_GPR2, PT_GPR3, PT_GPR3,
77 PT_GPR4, PT_GPR4, PT_GPR5, PT_GPR5, PT_GPR6, PT_GPR6, PT_GPR7, PT_GPR7,
78 PT_GPR8, PT_GPR8, PT_GPR9, PT_GPR9, PT_GPR10, PT_GPR10, PT_GPR11, PT_GPR11,
79 PT_GPR12, PT_GPR12, PT_GPR13, PT_GPR13, PT_GPR14, PT_GPR14, PT_GPR15, PT_GPR15,
80
81 PT_ACR0, PT_ACR1, PT_ACR2, PT_ACR3,
82 PT_ACR4, PT_ACR5, PT_ACR6, PT_ACR7,
83 PT_ACR8, PT_ACR9, PT_ACR10, PT_ACR11,
84 PT_ACR12, PT_ACR13, PT_ACR14, PT_ACR15,
85
86 PT_FPC,
87
88 PT_FPR0, PT_FPR1, PT_FPR2, PT_FPR3,
89 PT_FPR4, PT_FPR5, PT_FPR6, PT_FPR7,
90 PT_FPR8, PT_FPR9, PT_FPR10, PT_FPR11,
91 PT_FPR12, PT_FPR13, PT_FPR14, PT_FPR15,
92};
93#endif
94
95
2ec06d2e
DJ
96static int
97s390_cannot_fetch_register (int regno)
265f716b 98{
265f716b
DJ
99 return 0;
100}
101
2ec06d2e
DJ
102static int
103s390_cannot_store_register (int regno)
265f716b 104{
265f716b
DJ
105 return 0;
106}
2ec06d2e 107
ee1a7ae4
UW
108static void
109s390_collect_ptrace_register (int regno, char *buf)
110{
111 int size = register_size (regno);
112 if (size < sizeof (long))
113 {
7803799a
UW
114 int regaddr = the_low_target.regmap[regno];
115
ee1a7ae4
UW
116 memset (buf, 0, sizeof (long));
117
7803799a
UW
118 if ((regno ^ 1) < the_low_target.num_regs
119 && the_low_target.regmap[regno ^ 1] == regaddr)
120 {
121 collect_register (regno & ~1, buf);
122 collect_register ((regno & ~1) + 1, buf + sizeof (long) - size);
123 }
124 else if (regaddr == PT_PSWADDR
125 || (regaddr >= PT_GPR0 && regaddr <= PT_GPR15))
ee1a7ae4
UW
126 collect_register (regno, buf + sizeof (long) - size);
127 else
128 collect_register (regno, buf);
129
130 /* When debugging a 32-bit inferior on a 64-bit host, make sure
131 the 31-bit addressing mode bit is set in the PSW mask. */
7803799a 132 if (regaddr == PT_PSWMASK)
ee1a7ae4
UW
133 buf[size] |= 0x80;
134 }
135 else
136 collect_register (regno, buf);
137}
138
139static void
140s390_supply_ptrace_register (int regno, const char *buf)
141{
142 int size = register_size (regno);
143 if (size < sizeof (long))
144 {
7803799a
UW
145 int regaddr = the_low_target.regmap[regno];
146
147 if ((regno ^ 1) < the_low_target.num_regs
148 && the_low_target.regmap[regno ^ 1] == regaddr)
149 {
150 supply_register (regno & ~1, buf);
151 supply_register ((regno & ~1) + 1, buf + sizeof (long) - size);
152 }
153 else if (regaddr == PT_PSWADDR
154 || (regaddr >= PT_GPR0 && regaddr <= PT_GPR15))
ee1a7ae4
UW
155 supply_register (regno, buf + sizeof (long) - size);
156 else
157 supply_register (regno, buf);
158 }
159 else
160 supply_register (regno, buf);
161}
162
b7149293
UW
163/* Provide only a fill function for the general register set. ps_lgetregs
164 will use this for NPTL support. */
165
166static void s390_fill_gregset (void *buf)
167{
168 int i;
169
7803799a
UW
170 for (i = 0; i < the_low_target.num_regs; i++)
171 {
172 if (the_low_target.regmap[i] < PT_PSWMASK
173 || the_low_target.regmap[i] > PT_ACR15)
174 continue;
175
176 s390_collect_ptrace_register (i, (char *) buf
177 + the_low_target.regmap[i]);
178 }
b7149293
UW
179}
180
181struct regset_info target_regsets[] = {
182 { 0, 0, 0, GENERAL_REGS, s390_fill_gregset, NULL },
183 { 0, 0, -1, -1, NULL, NULL }
184};
185
b0ded00b 186
f450004a 187static const unsigned char s390_breakpoint[] = { 0, 1 };
b0ded00b
UW
188#define s390_breakpoint_len 2
189
190static CORE_ADDR
191s390_get_pc ()
192{
d61ddec4
UW
193 if (register_size (0) == 4)
194 {
195 unsigned int pc;
196 collect_register_by_name ("pswa", &pc);
b0ded00b 197#ifndef __s390x__
d61ddec4 198 pc &= 0x7fffffff;
b0ded00b 199#endif
d61ddec4
UW
200 return pc;
201 }
202 else
203 {
204 unsigned long pc;
205 collect_register_by_name ("pswa", &pc);
206 return pc;
207 }
b0ded00b
UW
208}
209
210static void
211s390_set_pc (CORE_ADDR newpc)
212{
d61ddec4
UW
213 if (register_size (0) == 4)
214 {
215 unsigned int pc = newpc;
b0ded00b 216#ifndef __s390x__
d61ddec4 217 pc |= 0x80000000;
b0ded00b 218#endif
d61ddec4
UW
219 supply_register_by_name ("pswa", &pc);
220 }
221 else
222 {
223 unsigned long pc = newpc;
224 supply_register_by_name ("pswa", &pc);
225 }
b0ded00b
UW
226}
227
7803799a
UW
228#ifdef __s390x__
229static unsigned long
230s390_get_hwcap (void)
231{
232 int wordsize = register_size (0);
233 unsigned char *data = alloca (2 * wordsize);
234 int offset = 0;
235
236 while ((*the_target->read_auxv) (offset, data, 2 * wordsize) == 2 * wordsize)
237 {
238 if (wordsize == 4)
239 {
240 unsigned int *data_p = (unsigned int *)data;
241 if (data_p[0] == AT_HWCAP)
242 return data_p[1];
243 }
244 else
245 {
246 unsigned long *data_p = (unsigned long *)data;
247 if (data_p[0] == AT_HWCAP)
248 return data_p[1];
249 }
250
251 offset += 2 * wordsize;
252 }
253
254 return 0;
255}
256#endif
d61ddec4
UW
257
258static void
259s390_arch_setup (void)
260{
261 /* Assume 31-bit inferior process. */
7803799a
UW
262 init_registers_s390_linux32 ();
263 the_low_target.num_regs = s390_num_regs;
264 the_low_target.regmap = s390_regmap;
d61ddec4
UW
265
266 /* On a 64-bit host, check the low bit of the (31-bit) PSWM
267 -- if this is one, we actually have a 64-bit inferior. */
268#ifdef __s390x__
269 {
270 unsigned int pswm;
271 collect_register_by_name ("pswm", &pswm);
272 if (pswm & 1)
7803799a
UW
273 init_registers_s390x_linux64 ();
274
275 /* For a 31-bit inferior, check whether the kernel supports
276 using the full 64-bit GPRs. */
277 else if (s390_get_hwcap () & HWCAP_S390_HIGH_GPRS)
278 {
279 init_registers_s390_linux64 ();
280 the_low_target.num_regs = s390_num_regs_3264;
281 the_low_target.regmap = s390_regmap_3264;
282 }
d61ddec4
UW
283 }
284#endif
285}
286
287
b0ded00b
UW
288static int
289s390_breakpoint_at (CORE_ADDR pc)
290{
291 unsigned char c[s390_breakpoint_len];
292 read_inferior_memory (pc, c, s390_breakpoint_len);
293 return memcmp (c, s390_breakpoint, s390_breakpoint_len) == 0;
294}
295
296
2ec06d2e 297struct linux_target_ops the_low_target = {
d61ddec4 298 s390_arch_setup,
2ec06d2e
DJ
299 s390_num_regs,
300 s390_regmap,
301 s390_cannot_fetch_register,
302 s390_cannot_store_register,
b0ded00b
UW
303 s390_get_pc,
304 s390_set_pc,
305 s390_breakpoint,
306 s390_breakpoint_len,
307 NULL,
308 s390_breakpoint_len,
309 s390_breakpoint_at,
ee1a7ae4
UW
310 NULL,
311 NULL,
312 NULL,
313 NULL,
314 s390_collect_ptrace_register,
315 s390_supply_ptrace_register,
2ec06d2e 316};
This page took 0.671795 seconds and 4 git commands to generate.