gdb/
[deliverable/binutils-gdb.git] / gdb / gdbserver / linux-s390-low.c
... / ...
CommitLineData
1/* GNU/Linux S/390 specific low level interface, for the remote server
2 for GDB.
3 Copyright (C) 2001, 2002, 2005, 2006, 2007, 2008, 2009, 2010, 2011
4 Free Software Foundation, Inc.
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
10 the Free Software Foundation; either version 3 of the License, or
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
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
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#include "elf/common.h"
26
27#include <asm/ptrace.h>
28#include <sys/ptrace.h>
29#include <sys/uio.h>
30#include <elf.h>
31
32#ifndef HWCAP_S390_HIGH_GPRS
33#define HWCAP_S390_HIGH_GPRS 512
34#endif
35
36#ifndef PTRACE_GETREGSET
37#define PTRACE_GETREGSET 0x4204
38#endif
39
40#ifndef PTRACE_SETREGSET
41#define PTRACE_SETREGSET 0x4205
42#endif
43
44/* Defined in auto-generated file s390-linux32.c. */
45void init_registers_s390_linux32 (void);
46/* Defined in auto-generated file s390-linux32v1.c. */
47void init_registers_s390_linux32v1 (void);
48/* Defined in auto-generated file s390-linux32v2.c. */
49void init_registers_s390_linux32v2 (void);
50/* Defined in auto-generated file s390-linux64.c. */
51void init_registers_s390_linux64 (void);
52/* Defined in auto-generated file s390-linux64v1.c. */
53void init_registers_s390_linux64v1 (void);
54/* Defined in auto-generated file s390-linux64v2.c. */
55void init_registers_s390_linux64v2 (void);
56/* Defined in auto-generated file s390x-linux64.c. */
57void init_registers_s390x_linux64 (void);
58/* Defined in auto-generated file s390x-linux64v1.c. */
59void init_registers_s390x_linux64v1 (void);
60/* Defined in auto-generated file s390x-linux64v2.c. */
61void init_registers_s390x_linux64v2 (void);
62
63#define s390_num_regs 52
64
65static int s390_regmap[] = {
66 PT_PSWMASK, PT_PSWADDR,
67
68 PT_GPR0, PT_GPR1, PT_GPR2, PT_GPR3,
69 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
70 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
71 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15,
72
73 PT_ACR0, PT_ACR1, PT_ACR2, PT_ACR3,
74 PT_ACR4, PT_ACR5, PT_ACR6, PT_ACR7,
75 PT_ACR8, PT_ACR9, PT_ACR10, PT_ACR11,
76 PT_ACR12, PT_ACR13, PT_ACR14, PT_ACR15,
77
78 PT_FPC,
79
80#ifndef __s390x__
81 PT_FPR0_HI, PT_FPR1_HI, PT_FPR2_HI, PT_FPR3_HI,
82 PT_FPR4_HI, PT_FPR5_HI, PT_FPR6_HI, PT_FPR7_HI,
83 PT_FPR8_HI, PT_FPR9_HI, PT_FPR10_HI, PT_FPR11_HI,
84 PT_FPR12_HI, PT_FPR13_HI, PT_FPR14_HI, PT_FPR15_HI,
85#else
86 PT_FPR0, PT_FPR1, PT_FPR2, PT_FPR3,
87 PT_FPR4, PT_FPR5, PT_FPR6, PT_FPR7,
88 PT_FPR8, PT_FPR9, PT_FPR10, PT_FPR11,
89 PT_FPR12, PT_FPR13, PT_FPR14, PT_FPR15,
90#endif
91
92 PT_ORIGGPR2,
93};
94
95#ifdef __s390x__
96#define s390_num_regs_3264 68
97
98static int s390_regmap_3264[] = {
99 PT_PSWMASK, PT_PSWADDR,
100
101 PT_GPR0, PT_GPR0, PT_GPR1, PT_GPR1,
102 PT_GPR2, PT_GPR2, PT_GPR3, PT_GPR3,
103 PT_GPR4, PT_GPR4, PT_GPR5, PT_GPR5,
104 PT_GPR6, PT_GPR6, PT_GPR7, PT_GPR7,
105 PT_GPR8, PT_GPR8, PT_GPR9, PT_GPR9,
106 PT_GPR10, PT_GPR10, PT_GPR11, PT_GPR11,
107 PT_GPR12, PT_GPR12, PT_GPR13, PT_GPR13,
108 PT_GPR14, PT_GPR14, PT_GPR15, PT_GPR15,
109
110 PT_ACR0, PT_ACR1, PT_ACR2, PT_ACR3,
111 PT_ACR4, PT_ACR5, PT_ACR6, PT_ACR7,
112 PT_ACR8, PT_ACR9, PT_ACR10, PT_ACR11,
113 PT_ACR12, PT_ACR13, PT_ACR14, PT_ACR15,
114
115 PT_FPC,
116
117 PT_FPR0, PT_FPR1, PT_FPR2, PT_FPR3,
118 PT_FPR4, PT_FPR5, PT_FPR6, PT_FPR7,
119 PT_FPR8, PT_FPR9, PT_FPR10, PT_FPR11,
120 PT_FPR12, PT_FPR13, PT_FPR14, PT_FPR15,
121
122 PT_ORIGGPR2,
123};
124#endif
125
126
127static int
128s390_cannot_fetch_register (int regno)
129{
130 return 0;
131}
132
133static int
134s390_cannot_store_register (int regno)
135{
136 return 0;
137}
138
139static void
140s390_collect_ptrace_register (struct regcache *regcache, int regno, char *buf)
141{
142 int size = register_size (regno);
143 if (size < sizeof (long))
144 {
145 int regaddr = the_low_target.regmap[regno];
146
147 memset (buf, 0, sizeof (long));
148
149 if ((regno ^ 1) < the_low_target.num_regs
150 && the_low_target.regmap[regno ^ 1] == regaddr)
151 {
152 collect_register (regcache, regno & ~1, buf);
153 collect_register (regcache, (regno & ~1) + 1,
154 buf + sizeof (long) - size);
155 }
156 else if (regaddr == PT_PSWMASK)
157 {
158 /* Convert 4-byte PSW mask to 8 bytes by clearing bit 12 and copying
159 the basic addressing mode bit from the PSW address. */
160 char *addr = alloca (register_size (regno ^ 1));
161 collect_register (regcache, regno, buf);
162 collect_register (regcache, regno ^ 1, addr);
163 buf[1] &= ~0x8;
164 buf[size] |= (addr[0] & 0x80);
165 }
166 else if (regaddr == PT_PSWADDR)
167 {
168 /* Convert 4-byte PSW address to 8 bytes by clearing the addressing
169 mode bit (which gets copied to the PSW mask instead). */
170 collect_register (regcache, regno, buf + sizeof (long) - size);
171 buf[sizeof (long) - size] &= ~0x80;
172 }
173 else if ((regaddr >= PT_GPR0 && regaddr <= PT_GPR15)
174 || regaddr == PT_ORIGGPR2)
175 collect_register (regcache, regno, buf + sizeof (long) - size);
176 else
177 collect_register (regcache, regno, buf);
178 }
179 else
180 collect_register (regcache, regno, buf);
181}
182
183static void
184s390_supply_ptrace_register (struct regcache *regcache,
185 int regno, const char *buf)
186{
187 int size = register_size (regno);
188 if (size < sizeof (long))
189 {
190 int regaddr = the_low_target.regmap[regno];
191
192 if ((regno ^ 1) < the_low_target.num_regs
193 && the_low_target.regmap[regno ^ 1] == regaddr)
194 {
195 supply_register (regcache, regno & ~1, buf);
196 supply_register (regcache, (regno & ~1) + 1,
197 buf + sizeof (long) - size);
198 }
199 else if (regaddr == PT_PSWMASK)
200 {
201 /* Convert 8-byte PSW mask to 4 bytes by setting bit 12 and copying
202 the basic addressing mode into the PSW address. */
203 char *mask = alloca (size);
204 char *addr = alloca (register_size (regno ^ 1));
205 memcpy (mask, buf, size);
206 mask[1] |= 0x8;
207 supply_register (regcache, regno, mask);
208
209 collect_register (regcache, regno ^ 1, addr);
210 addr[0] &= ~0x80;
211 addr[0] |= (buf[size] & 0x80);
212 supply_register (regcache, regno ^ 1, addr);
213 }
214 else if (regaddr == PT_PSWADDR)
215 {
216 /* Convert 8-byte PSW address to 4 bytes by truncating, but
217 keeping the addressing mode bit (which was set from the mask). */
218 char *addr = alloca (size);
219 char amode;
220 collect_register (regcache, regno, addr);
221 amode = addr[0] & 0x80;
222 memcpy (addr, buf + sizeof (long) - size, size);
223 addr[0] &= ~0x80;
224 addr[0] |= amode;
225 supply_register (regcache, regno, addr);
226 }
227 else if ((regaddr >= PT_GPR0 && regaddr <= PT_GPR15)
228 || regaddr == PT_ORIGGPR2)
229 supply_register (regcache, regno, buf + sizeof (long) - size);
230 else
231 supply_register (regcache, regno, buf);
232 }
233 else
234 supply_register (regcache, regno, buf);
235}
236
237/* Provide only a fill function for the general register set. ps_lgetregs
238 will use this for NPTL support. */
239
240static void s390_fill_gregset (struct regcache *regcache, void *buf)
241{
242 int i;
243
244 for (i = 0; i < the_low_target.num_regs; i++)
245 {
246 if (the_low_target.regmap[i] < PT_PSWMASK
247 || the_low_target.regmap[i] > PT_ACR15)
248 continue;
249
250 s390_collect_ptrace_register (regcache, i, (char *) buf
251 + the_low_target.regmap[i]);
252 }
253}
254
255/* Fill and store functions for extended register sets. */
256
257static void
258s390_fill_last_break (struct regcache *regcache, void *buf)
259{
260 /* Last break address is read-only. */
261}
262
263static void
264s390_store_last_break (struct regcache *regcache, const void *buf)
265{
266 supply_register_by_name (regcache, "last_break",
267 (const char *)buf + 8 - register_size (0));
268}
269
270static void
271s390_fill_system_call (struct regcache *regcache, void *buf)
272{
273 collect_register_by_name (regcache, "system_call", buf);
274}
275
276static void
277s390_store_system_call (struct regcache *regcache, const void *buf)
278{
279 supply_register_by_name (regcache, "system_call", buf);
280}
281
282struct regset_info target_regsets[] = {
283 { 0, 0, 0, 0, GENERAL_REGS, s390_fill_gregset, NULL },
284 /* Last break address is read-only; do not attempt PTRACE_SETREGSET. */
285 { PTRACE_GETREGSET, PTRACE_GETREGSET, NT_S390_LAST_BREAK, 0,
286 EXTENDED_REGS, s390_fill_last_break, s390_store_last_break },
287 { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_S390_SYSTEM_CALL, 0,
288 EXTENDED_REGS, s390_fill_system_call, s390_store_system_call },
289 { 0, 0, 0, -1, -1, NULL, NULL }
290};
291
292
293static const unsigned char s390_breakpoint[] = { 0, 1 };
294#define s390_breakpoint_len 2
295
296static CORE_ADDR
297s390_get_pc (struct regcache *regcache)
298{
299 if (register_size (0) == 4)
300 {
301 unsigned int pswa;
302 collect_register_by_name (regcache, "pswa", &pswa);
303 return pswa & 0x7fffffff;
304 }
305 else
306 {
307 unsigned long pc;
308 collect_register_by_name (regcache, "pswa", &pc);
309 return pc;
310 }
311}
312
313static void
314s390_set_pc (struct regcache *regcache, CORE_ADDR newpc)
315{
316 if (register_size (0) == 4)
317 {
318 unsigned int pswa;
319 collect_register_by_name (regcache, "pswa", &pswa);
320 pswa = (pswa & 0x80000000) | (newpc & 0x7fffffff);
321 supply_register_by_name (regcache, "pswa", &pswa);
322 }
323 else
324 {
325 unsigned long pc = newpc;
326 supply_register_by_name (regcache, "pswa", &pc);
327 }
328}
329
330#ifdef __s390x__
331static unsigned long
332s390_get_hwcap (void)
333{
334 int wordsize = register_size (0);
335 unsigned char *data = alloca (2 * wordsize);
336 int offset = 0;
337
338 while ((*the_target->read_auxv) (offset, data, 2 * wordsize) == 2 * wordsize)
339 {
340 if (wordsize == 4)
341 {
342 unsigned int *data_p = (unsigned int *)data;
343 if (data_p[0] == AT_HWCAP)
344 return data_p[1];
345 }
346 else
347 {
348 unsigned long *data_p = (unsigned long *)data;
349 if (data_p[0] == AT_HWCAP)
350 return data_p[1];
351 }
352
353 offset += 2 * wordsize;
354 }
355
356 return 0;
357}
358#endif
359
360static int
361s390_check_regset (int pid, int regset, int regsize)
362{
363 gdb_byte *buf = alloca (regsize);
364 struct iovec iov;
365
366 iov.iov_base = buf;
367 iov.iov_len = regsize;
368
369 if (ptrace (PTRACE_GETREGSET, pid, (long) regset, (long) &iov) < 0)
370 return 0;
371 else
372 return 1;
373}
374
375static void
376s390_arch_setup (void)
377{
378 struct regset_info *regset;
379
380 /* Check whether the kernel supports extra register sets. */
381 int pid = pid_of (get_thread_lwp (current_inferior));
382 int have_regset_last_break
383 = s390_check_regset (pid, NT_S390_LAST_BREAK, 8);
384 int have_regset_system_call
385 = s390_check_regset (pid, NT_S390_SYSTEM_CALL, 4);
386
387 /* Update target_regsets according to available register sets. */
388 for (regset = target_regsets; regset->fill_function != NULL; regset++)
389 if (regset->get_request == PTRACE_GETREGSET)
390 switch (regset->nt_type)
391 {
392 case NT_S390_LAST_BREAK:
393 regset->size = have_regset_last_break? 8 : 0;
394 break;
395 case NT_S390_SYSTEM_CALL:
396 regset->size = have_regset_system_call? 4 : 0;
397 break;
398 default:
399 break;
400 }
401
402 /* Assume 31-bit inferior process. */
403 if (have_regset_system_call)
404 init_registers_s390_linux32v2 ();
405 else if (have_regset_last_break)
406 init_registers_s390_linux32v1 ();
407 else
408 init_registers_s390_linux32 ();
409
410 the_low_target.num_regs = s390_num_regs;
411 the_low_target.regmap = s390_regmap;
412
413 /* On a 64-bit host, check the low bit of the (31-bit) PSWM
414 -- if this is one, we actually have a 64-bit inferior. */
415#ifdef __s390x__
416 {
417 unsigned int pswm;
418 struct regcache *regcache = new_register_cache ();
419 fetch_inferior_registers (regcache, find_regno ("pswm"));
420 collect_register_by_name (regcache, "pswm", &pswm);
421 free_register_cache (regcache);
422
423 if (pswm & 1)
424 {
425 if (have_regset_system_call)
426 init_registers_s390x_linux64v2 ();
427 else if (have_regset_last_break)
428 init_registers_s390x_linux64v1 ();
429 else
430 init_registers_s390x_linux64 ();
431 }
432
433 /* For a 31-bit inferior, check whether the kernel supports
434 using the full 64-bit GPRs. */
435 else if (s390_get_hwcap () & HWCAP_S390_HIGH_GPRS)
436 {
437 if (have_regset_system_call)
438 init_registers_s390_linux64v2 ();
439 else if (have_regset_last_break)
440 init_registers_s390_linux64v1 ();
441 else
442 init_registers_s390_linux64 ();
443
444 the_low_target.num_regs = s390_num_regs_3264;
445 the_low_target.regmap = s390_regmap_3264;
446 }
447 }
448#endif
449}
450
451
452static int
453s390_breakpoint_at (CORE_ADDR pc)
454{
455 unsigned char c[s390_breakpoint_len];
456 read_inferior_memory (pc, c, s390_breakpoint_len);
457 return memcmp (c, s390_breakpoint, s390_breakpoint_len) == 0;
458}
459
460
461struct linux_target_ops the_low_target = {
462 s390_arch_setup,
463 s390_num_regs,
464 s390_regmap,
465 s390_cannot_fetch_register,
466 s390_cannot_store_register,
467 s390_get_pc,
468 s390_set_pc,
469 s390_breakpoint,
470 s390_breakpoint_len,
471 NULL,
472 s390_breakpoint_len,
473 s390_breakpoint_at,
474 NULL,
475 NULL,
476 NULL,
477 NULL,
478 s390_collect_ptrace_register,
479 s390_supply_ptrace_register,
480};
This page took 0.023465 seconds and 4 git commands to generate.