gas/testsuite/
[deliverable/binutils-gdb.git] / gdb / s390-nat.c
CommitLineData
5769d3cd 1/* S390 native-dependent code for GDB, the GNU debugger.
c9dd6fef
WZ
2 Copyright (C) 2001, 2003, 2004, 2005, 2006
3 Free Software Foundation, Inc
d0f54f9d 4
5769d3cd
AC
5 Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
6 for IBM Deutschland Entwicklung GmbH, IBM Corporation.
d0f54f9d 7
5769d3cd
AC
8 This file is part of GDB.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
a9762ec7 12 the Free Software Foundation; either version 3 of the License, or
5769d3cd
AC
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
a9762ec7 21 along with this program. If not, see <http://www.gnu.org/licenses/>. */
5769d3cd
AC
22
23#include "defs.h"
3ecc0ae2 24#include "regcache.h"
d0f54f9d 25#include "inferior.h"
10d6c8cd
DJ
26#include "target.h"
27#include "linux-nat.h"
d0f54f9d
JB
28
29#include "s390-tdep.h"
30
5769d3cd
AC
31#include <asm/ptrace.h>
32#include <sys/ptrace.h>
2d0c7962 33#include <asm/types.h>
5769d3cd 34#include <sys/procfs.h>
5769d3cd 35#include <sys/ucontext.h>
5769d3cd
AC
36
37
d0f54f9d
JB
38/* Map registers to gregset/ptrace offsets.
39 These arrays are defined in s390-tdep.c. */
40
41#ifdef __s390x__
42#define regmap_gregset s390x_regmap_gregset
5769d3cd 43#else
d0f54f9d 44#define regmap_gregset s390_regmap_gregset
5769d3cd 45#endif
d0f54f9d
JB
46
47#define regmap_fpregset s390_regmap_fpregset
48
9cbd5950
JB
49/* When debugging a 32-bit executable running under a 64-bit kernel,
50 we have to fix up the 64-bit registers we get from the kernel
51 to make them look like 32-bit registers. */
52#ifdef __s390x__
53#define SUBOFF(i) \
819844ad 54 ((gdbarch_ptr_bit (current_gdbarch) == 32 \
9cbd5950
JB
55 && ((i) == S390_PSWA_REGNUM \
56 || ((i) >= S390_R0_REGNUM && (i) <= S390_R15_REGNUM)))? 4 : 0)
57#else
58#define SUBOFF(i) 0
59#endif
60
d0f54f9d
JB
61
62/* Fill GDB's register array with the general-purpose register values
63 in *REGP. */
64void
7f7fe91e 65supply_gregset (struct regcache *regcache, const gregset_t *regp)
d0f54f9d
JB
66{
67 int i;
68 for (i = 0; i < S390_NUM_REGS; i++)
69 if (regmap_gregset[i] != -1)
7f7fe91e
UW
70 regcache_raw_supply (regcache, i,
71 (const char *)regp + regmap_gregset[i] + SUBOFF (i));
d0f54f9d
JB
72}
73
74/* Fill register REGNO (if it is a general-purpose register) in
75 *REGP with the value in GDB's register array. If REGNO is -1,
76 do this for all registers. */
77void
7f7fe91e 78fill_gregset (const struct regcache *regcache, gregset_t *regp, int regno)
d0f54f9d
JB
79{
80 int i;
81 for (i = 0; i < S390_NUM_REGS; i++)
82 if (regmap_gregset[i] != -1)
83 if (regno == -1 || regno == i)
7f7fe91e 84 regcache_raw_collect (regcache, i,
9cbd5950 85 (char *)regp + regmap_gregset[i] + SUBOFF (i));
d0f54f9d
JB
86}
87
88/* Fill GDB's register array with the floating-point register values
89 in *REGP. */
90void
7f7fe91e 91supply_fpregset (struct regcache *regcache, const fpregset_t *regp)
d0f54f9d
JB
92{
93 int i;
94 for (i = 0; i < S390_NUM_REGS; i++)
95 if (regmap_fpregset[i] != -1)
7f7fe91e
UW
96 regcache_raw_supply (regcache, i,
97 (const char *)regp + regmap_fpregset[i]);
d0f54f9d
JB
98}
99
100/* Fill register REGNO (if it is a general-purpose register) in
101 *REGP with the value in GDB's register array. If REGNO is -1,
102 do this for all registers. */
103void
7f7fe91e 104fill_fpregset (const struct regcache *regcache, fpregset_t *regp, int regno)
d0f54f9d
JB
105{
106 int i;
107 for (i = 0; i < S390_NUM_REGS; i++)
108 if (regmap_fpregset[i] != -1)
109 if (regno == -1 || regno == i)
7f7fe91e
UW
110 regcache_raw_collect (regcache, i,
111 (char *)regp + regmap_fpregset[i]);
d0f54f9d
JB
112}
113
114/* Find the TID for the current inferior thread to use with ptrace. */
115static int
116s390_inferior_tid (void)
117{
118 /* GNU/Linux LWP ID's are process ID's. */
119 int tid = TIDGET (inferior_ptid);
120 if (tid == 0)
121 tid = PIDGET (inferior_ptid); /* Not a threaded program. */
122
123 return tid;
124}
125
126/* Fetch all general-purpose registers from process/thread TID and
127 store their values in GDB's register cache. */
128static void
56be3814 129fetch_regs (struct regcache *regcache, int tid)
d0f54f9d
JB
130{
131 gregset_t regs;
132 ptrace_area parea;
133
134 parea.len = sizeof (regs);
135 parea.process_addr = (addr_t) &regs;
136 parea.kernel_addr = offsetof (struct user_regs_struct, psw);
137 if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
e2e0b3e5 138 perror_with_name (_("Couldn't get registers"));
d0f54f9d 139
56be3814 140 supply_gregset (regcache, (const gregset_t *) &regs);
d0f54f9d
JB
141}
142
143/* Store all valid general-purpose registers in GDB's register cache
144 into the process/thread specified by TID. */
145static void
56be3814 146store_regs (const struct regcache *regcache, int tid, int regnum)
d0f54f9d
JB
147{
148 gregset_t regs;
149 ptrace_area parea;
150
151 parea.len = sizeof (regs);
152 parea.process_addr = (addr_t) &regs;
153 parea.kernel_addr = offsetof (struct user_regs_struct, psw);
154 if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
e2e0b3e5 155 perror_with_name (_("Couldn't get registers"));
d0f54f9d 156
56be3814 157 fill_gregset (regcache, &regs, regnum);
d0f54f9d
JB
158
159 if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
e2e0b3e5 160 perror_with_name (_("Couldn't write registers"));
d0f54f9d
JB
161}
162
163/* Fetch all floating-point registers from process/thread TID and store
164 their values in GDB's register cache. */
165static void
56be3814 166fetch_fpregs (struct regcache *regcache, int tid)
d0f54f9d
JB
167{
168 fpregset_t fpregs;
169 ptrace_area parea;
170
171 parea.len = sizeof (fpregs);
172 parea.process_addr = (addr_t) &fpregs;
173 parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
174 if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
e2e0b3e5 175 perror_with_name (_("Couldn't get floating point status"));
d0f54f9d 176
56be3814 177 supply_fpregset (regcache, (const fpregset_t *) &fpregs);
d0f54f9d
JB
178}
179
180/* Store all valid floating-point registers in GDB's register cache
181 into the process/thread specified by TID. */
182static void
56be3814 183store_fpregs (const struct regcache *regcache, int tid, int regnum)
d0f54f9d
JB
184{
185 fpregset_t fpregs;
186 ptrace_area parea;
187
188 parea.len = sizeof (fpregs);
189 parea.process_addr = (addr_t) &fpregs;
190 parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
191 if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
e2e0b3e5 192 perror_with_name (_("Couldn't get floating point status"));
d0f54f9d 193
56be3814 194 fill_fpregset (regcache, &fpregs, regnum);
d0f54f9d
JB
195
196 if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
e2e0b3e5 197 perror_with_name (_("Couldn't write floating point status"));
d0f54f9d
JB
198}
199
200/* Fetch register REGNUM from the child process. If REGNUM is -1, do
201 this for all registers. */
10d6c8cd 202static void
56be3814 203s390_linux_fetch_inferior_registers (struct regcache *regcache, int regnum)
d0f54f9d
JB
204{
205 int tid = s390_inferior_tid ();
206
207 if (regnum == -1
208 || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
56be3814 209 fetch_regs (regcache, tid);
d0f54f9d
JB
210
211 if (regnum == -1
212 || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
56be3814 213 fetch_fpregs (regcache, tid);
d0f54f9d
JB
214}
215
216/* Store register REGNUM back into the child process. If REGNUM is
217 -1, do this for all registers. */
10d6c8cd 218static void
56be3814 219s390_linux_store_inferior_registers (struct regcache *regcache, int regnum)
d0f54f9d
JB
220{
221 int tid = s390_inferior_tid ();
222
223 if (regnum == -1
224 || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
56be3814 225 store_regs (regcache, tid, regnum);
d0f54f9d
JB
226
227 if (regnum == -1
228 || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
56be3814 229 store_fpregs (regcache, tid, regnum);
5769d3cd
AC
230}
231
d0f54f9d 232
e1457d83
JB
233/* Hardware-assisted watchpoint handling. */
234
235/* We maintain a list of all currently active watchpoints in order
236 to properly handle watchpoint removal.
237
238 The only thing we actually need is the total address space area
239 spanned by the watchpoints. */
240
5769d3cd
AC
241struct watch_area
242{
e1457d83 243 struct watch_area *next;
5769d3cd
AC
244 CORE_ADDR lo_addr;
245 CORE_ADDR hi_addr;
246};
247
e1457d83 248static struct watch_area *watch_base = NULL;
5769d3cd 249
fd7979d1 250static int
e1457d83 251s390_stopped_by_watchpoint (void)
5769d3cd
AC
252{
253 per_lowcore_bits per_lowcore;
254 ptrace_area parea;
255
e1457d83
JB
256 /* Speed up common case. */
257 if (!watch_base)
258 return 0;
259
5769d3cd
AC
260 parea.len = sizeof (per_lowcore);
261 parea.process_addr = (addr_t) & per_lowcore;
262 parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
e1457d83 263 if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
e2e0b3e5 264 perror_with_name (_("Couldn't retrieve watchpoint status"));
5769d3cd 265
e1457d83
JB
266 return per_lowcore.perc_storage_alteration == 1
267 && per_lowcore.perc_store_real_address == 0;
268}
5769d3cd 269
e1457d83
JB
270static void
271s390_fix_watch_points (void)
5769d3cd 272{
e1457d83
JB
273 int tid = s390_inferior_tid ();
274
5769d3cd
AC
275 per_struct per_info;
276 ptrace_area parea;
277
e1457d83
JB
278 CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0;
279 struct watch_area *area;
280
281 for (area = watch_base; area; area = area->next)
282 {
283 watch_lo_addr = min (watch_lo_addr, area->lo_addr);
284 watch_hi_addr = max (watch_hi_addr, area->hi_addr);
285 }
286
5769d3cd
AC
287 parea.len = sizeof (per_info);
288 parea.process_addr = (addr_t) & per_info;
e1457d83
JB
289 parea.kernel_addr = offsetof (struct user_regs_struct, per_info);
290 if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0)
e2e0b3e5 291 perror_with_name (_("Couldn't retrieve watchpoint status"));
e1457d83
JB
292
293 if (watch_base)
5769d3cd
AC
294 {
295 per_info.control_regs.bits.em_storage_alteration = 1;
296 per_info.control_regs.bits.storage_alt_space_ctl = 1;
297 }
298 else
299 {
300 per_info.control_regs.bits.em_storage_alteration = 0;
301 per_info.control_regs.bits.storage_alt_space_ctl = 0;
302 }
303 per_info.starting_addr = watch_lo_addr;
304 per_info.ending_addr = watch_hi_addr;
e1457d83
JB
305
306 if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0)
e2e0b3e5 307 perror_with_name (_("Couldn't modify watchpoint status"));
5769d3cd
AC
308}
309
fd7979d1 310static int
2f00de94 311s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
5769d3cd 312{
e1457d83
JB
313 struct watch_area *area = xmalloc (sizeof (struct watch_area));
314 if (!area)
315 return -1;
316
317 area->lo_addr = addr;
318 area->hi_addr = addr + len - 1;
319
320 area->next = watch_base;
321 watch_base = area;
322
323 s390_fix_watch_points ();
324 return 0;
5769d3cd
AC
325}
326
fd7979d1 327static int
2f00de94 328s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
5769d3cd 329{
e1457d83
JB
330 struct watch_area *area, **parea;
331
332 for (parea = &watch_base; *parea; parea = &(*parea)->next)
333 if ((*parea)->lo_addr == addr
334 && (*parea)->hi_addr == addr + len - 1)
335 break;
336
337 if (!*parea)
5769d3cd
AC
338 {
339 fprintf_unfiltered (gdb_stderr,
e1457d83 340 "Attempt to remove nonexistent watchpoint.\n");
5769d3cd
AC
341 return -1;
342 }
e1457d83
JB
343
344 area = *parea;
345 *parea = area->next;
346 xfree (area);
347
348 s390_fix_watch_points ();
349 return 0;
5769d3cd
AC
350}
351
fd7979d1
UW
352static int
353s390_can_use_hw_breakpoint (int type, int cnt, int othertype)
354{
355 return 1;
356}
e1457d83 357
fd7979d1 358static int
2a3cdf79 359s390_region_ok_for_hw_watchpoint (CORE_ADDR addr, int cnt)
5769d3cd 360{
fd7979d1 361 return 1;
5769d3cd
AC
362}
363
fd7979d1 364
10d6c8cd
DJ
365void _initialize_s390_nat (void);
366
367void
368_initialize_s390_nat (void)
369{
370 struct target_ops *t;
371
372 /* Fill in the generic GNU/Linux methods. */
373 t = linux_target ();
374
375 /* Add our register access methods. */
376 t->to_fetch_registers = s390_linux_fetch_inferior_registers;
377 t->to_store_registers = s390_linux_store_inferior_registers;
378
fd7979d1
UW
379 /* Add our watchpoint methods. */
380 t->to_can_use_hw_breakpoint = s390_can_use_hw_breakpoint;
2a3cdf79 381 t->to_region_ok_for_hw_watchpoint = s390_region_ok_for_hw_watchpoint;
fd7979d1
UW
382 t->to_have_continuable_watchpoint = 1;
383 t->to_stopped_by_watchpoint = s390_stopped_by_watchpoint;
384 t->to_insert_watchpoint = s390_insert_watchpoint;
385 t->to_remove_watchpoint = s390_remove_watchpoint;
386
10d6c8cd 387 /* Register the target. */
f973ed9c 388 linux_nat_add_target (t);
10d6c8cd 389}
This page took 0.617986 seconds and 4 git commands to generate.