* linux-low.c (PTRACE_ARG3_TYPE): Change from long to void*.
[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 108static void
442ea881 109s390_collect_ptrace_register (struct regcache *regcache, int regno, char *buf)
ee1a7ae4
UW
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))
442ea881 126 collect_register (regcache, regno, buf + sizeof (long) - size);
ee1a7ae4 127 else
442ea881 128 collect_register (regcache, regno, buf);
ee1a7ae4
UW
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
442ea881 140s390_supply_ptrace_register (struct regcache *regcache, int regno, const char *buf)
ee1a7ae4
UW
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))
442ea881 155 supply_register (regcache, regno, buf + sizeof (long) - size);
ee1a7ae4 156 else
442ea881 157 supply_register (regcache, regno, buf);
ee1a7ae4
UW
158 }
159 else
442ea881 160 supply_register (regcache, regno, buf);
ee1a7ae4
UW
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
442ea881 166static void s390_fill_gregset (struct regcache *regcache, void *buf)
b7149293
UW
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
442ea881 176 s390_collect_ptrace_register (regcache, i, (char *) buf
7803799a
UW
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
442ea881 191s390_get_pc (struct regcache *regcache)
b0ded00b 192{
d61ddec4
UW
193 if (register_size (0) == 4)
194 {
195 unsigned int pc;
442ea881 196 collect_register_by_name (regcache, "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;
442ea881 205 collect_register_by_name (regcache, "pswa", &pc);
d61ddec4
UW
206 return pc;
207 }
b0ded00b
UW
208}
209
210static void
442ea881 211s390_set_pc (struct regcache *regcache, CORE_ADDR newpc)
b0ded00b 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
442ea881 219 supply_register_by_name (regcache, "pswa", &pc);
d61ddec4
UW
220 }
221 else
222 {
223 unsigned long pc = newpc;
442ea881 224 supply_register_by_name (regcache, "pswa", &pc);
d61ddec4 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;
442ea881
PA
271 struct regcache *regcache = get_thread_regcache (current_inferior, 1);
272 collect_register_by_name (regcache, "pswm", &pswm);
d61ddec4 273 if (pswm & 1)
7803799a
UW
274 init_registers_s390x_linux64 ();
275
276 /* For a 31-bit inferior, check whether the kernel supports
277 using the full 64-bit GPRs. */
278 else if (s390_get_hwcap () & HWCAP_S390_HIGH_GPRS)
279 {
280 init_registers_s390_linux64 ();
281 the_low_target.num_regs = s390_num_regs_3264;
282 the_low_target.regmap = s390_regmap_3264;
283 }
d61ddec4
UW
284 }
285#endif
286}
287
288
b0ded00b
UW
289static int
290s390_breakpoint_at (CORE_ADDR pc)
291{
292 unsigned char c[s390_breakpoint_len];
293 read_inferior_memory (pc, c, s390_breakpoint_len);
294 return memcmp (c, s390_breakpoint, s390_breakpoint_len) == 0;
295}
296
297
2ec06d2e 298struct linux_target_ops the_low_target = {
d61ddec4 299 s390_arch_setup,
2ec06d2e
DJ
300 s390_num_regs,
301 s390_regmap,
302 s390_cannot_fetch_register,
303 s390_cannot_store_register,
b0ded00b
UW
304 s390_get_pc,
305 s390_set_pc,
306 s390_breakpoint,
307 s390_breakpoint_len,
308 NULL,
309 s390_breakpoint_len,
310 s390_breakpoint_at,
ee1a7ae4
UW
311 NULL,
312 NULL,
313 NULL,
314 NULL,
315 s390_collect_ptrace_register,
316 s390_supply_ptrace_register,
2ec06d2e 317};
This page took 0.569613 seconds and 4 git commands to generate.