2007-10-08 Markus Deuling <deuling@de.ibm.com>
[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;
9f0bdab8 255 int result;
5769d3cd 256
e1457d83
JB
257 /* Speed up common case. */
258 if (!watch_base)
259 return 0;
260
5769d3cd
AC
261 parea.len = sizeof (per_lowcore);
262 parea.process_addr = (addr_t) & per_lowcore;
263 parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
e1457d83 264 if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
e2e0b3e5 265 perror_with_name (_("Couldn't retrieve watchpoint status"));
5769d3cd 266
9f0bdab8
DJ
267 result = (per_lowcore.perc_storage_alteration == 1
268 && per_lowcore.perc_store_real_address == 0);
269
270 if (result)
271 {
272 /* Do not report this watchpoint again. */
273 memset (&per_lowcore, 0, sizeof (per_lowcore));
274 if (ptrace (PTRACE_POKEUSR_AREA, s390_inferior_tid (), &parea) < 0)
275 perror_with_name (_("Couldn't clear watchpoint status"));
276 }
277
278 return result;
e1457d83 279}
5769d3cd 280
e1457d83 281static void
9f0bdab8 282s390_fix_watch_points (ptid_t ptid)
5769d3cd 283{
9f0bdab8 284 int tid;
e1457d83 285
5769d3cd
AC
286 per_struct per_info;
287 ptrace_area parea;
288
e1457d83
JB
289 CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0;
290 struct watch_area *area;
291
9f0bdab8
DJ
292 tid = TIDGET (ptid);
293 if (tid == 0)
294 tid = PIDGET (ptid);
295
e1457d83
JB
296 for (area = watch_base; area; area = area->next)
297 {
298 watch_lo_addr = min (watch_lo_addr, area->lo_addr);
299 watch_hi_addr = max (watch_hi_addr, area->hi_addr);
300 }
301
5769d3cd
AC
302 parea.len = sizeof (per_info);
303 parea.process_addr = (addr_t) & per_info;
e1457d83
JB
304 parea.kernel_addr = offsetof (struct user_regs_struct, per_info);
305 if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0)
e2e0b3e5 306 perror_with_name (_("Couldn't retrieve watchpoint status"));
e1457d83
JB
307
308 if (watch_base)
5769d3cd
AC
309 {
310 per_info.control_regs.bits.em_storage_alteration = 1;
311 per_info.control_regs.bits.storage_alt_space_ctl = 1;
312 }
313 else
314 {
315 per_info.control_regs.bits.em_storage_alteration = 0;
316 per_info.control_regs.bits.storage_alt_space_ctl = 0;
317 }
318 per_info.starting_addr = watch_lo_addr;
319 per_info.ending_addr = watch_hi_addr;
e1457d83
JB
320
321 if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0)
e2e0b3e5 322 perror_with_name (_("Couldn't modify watchpoint status"));
5769d3cd
AC
323}
324
fd7979d1 325static int
2f00de94 326s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
5769d3cd 327{
9f0bdab8
DJ
328 struct lwp_info *lp;
329 ptid_t ptid;
e1457d83 330 struct watch_area *area = xmalloc (sizeof (struct watch_area));
9f0bdab8 331
e1457d83
JB
332 if (!area)
333 return -1;
334
335 area->lo_addr = addr;
336 area->hi_addr = addr + len - 1;
337
338 area->next = watch_base;
339 watch_base = area;
340
9f0bdab8
DJ
341 ALL_LWPS (lp, ptid)
342 s390_fix_watch_points (ptid);
e1457d83 343 return 0;
5769d3cd
AC
344}
345
fd7979d1 346static int
2f00de94 347s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
5769d3cd 348{
9f0bdab8
DJ
349 struct lwp_info *lp;
350 ptid_t ptid;
e1457d83
JB
351 struct watch_area *area, **parea;
352
353 for (parea = &watch_base; *parea; parea = &(*parea)->next)
354 if ((*parea)->lo_addr == addr
355 && (*parea)->hi_addr == addr + len - 1)
356 break;
357
358 if (!*parea)
5769d3cd
AC
359 {
360 fprintf_unfiltered (gdb_stderr,
e1457d83 361 "Attempt to remove nonexistent watchpoint.\n");
5769d3cd
AC
362 return -1;
363 }
e1457d83
JB
364
365 area = *parea;
366 *parea = area->next;
367 xfree (area);
368
9f0bdab8
DJ
369 ALL_LWPS (lp, ptid)
370 s390_fix_watch_points (ptid);
e1457d83 371 return 0;
5769d3cd
AC
372}
373
fd7979d1
UW
374static int
375s390_can_use_hw_breakpoint (int type, int cnt, int othertype)
376{
377 return 1;
378}
e1457d83 379
fd7979d1 380static int
2a3cdf79 381s390_region_ok_for_hw_watchpoint (CORE_ADDR addr, int cnt)
5769d3cd 382{
fd7979d1 383 return 1;
5769d3cd
AC
384}
385
fd7979d1 386
10d6c8cd
DJ
387void _initialize_s390_nat (void);
388
389void
390_initialize_s390_nat (void)
391{
392 struct target_ops *t;
393
394 /* Fill in the generic GNU/Linux methods. */
395 t = linux_target ();
396
397 /* Add our register access methods. */
398 t->to_fetch_registers = s390_linux_fetch_inferior_registers;
399 t->to_store_registers = s390_linux_store_inferior_registers;
400
fd7979d1
UW
401 /* Add our watchpoint methods. */
402 t->to_can_use_hw_breakpoint = s390_can_use_hw_breakpoint;
2a3cdf79 403 t->to_region_ok_for_hw_watchpoint = s390_region_ok_for_hw_watchpoint;
fd7979d1
UW
404 t->to_have_continuable_watchpoint = 1;
405 t->to_stopped_by_watchpoint = s390_stopped_by_watchpoint;
406 t->to_insert_watchpoint = s390_insert_watchpoint;
407 t->to_remove_watchpoint = s390_remove_watchpoint;
408
10d6c8cd 409 /* Register the target. */
f973ed9c 410 linux_nat_add_target (t);
9f0bdab8 411 linux_nat_set_new_thread (t, s390_fix_watch_points);
10d6c8cd 412}
This page took 0.613712 seconds and 4 git commands to generate.