]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/s390-nat.c
* corelow.c (get_core_registers): Adjust.
[thirdparty/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__
8fe9ea88
MD
53#define SUBOFF(gdbarch, i) \
54 ((gdbarch_ptr_bit (gdbarch) == 32 \
9cbd5950
JB
55 && ((i) == S390_PSWA_REGNUM \
56 || ((i) >= S390_R0_REGNUM && (i) <= S390_R15_REGNUM)))? 4 : 0)
57#else
8fe9ea88 58#define SUBOFF(gdbarch, i) 0
9cbd5950
JB
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 66{
8fe9ea88 67 struct gdbarch *gdbarch = get_regcache_arch (regcache);
d0f54f9d
JB
68 int i;
69 for (i = 0; i < S390_NUM_REGS; i++)
70 if (regmap_gregset[i] != -1)
7f7fe91e 71 regcache_raw_supply (regcache, i,
8fe9ea88
MD
72 (const char *)regp + regmap_gregset[i]
73 + SUBOFF (gdbarch, i));
d0f54f9d
JB
74}
75
76/* Fill register REGNO (if it is a general-purpose register) in
77 *REGP with the value in GDB's register array. If REGNO is -1,
78 do this for all registers. */
79void
7f7fe91e 80fill_gregset (const struct regcache *regcache, gregset_t *regp, int regno)
d0f54f9d 81{
8fe9ea88 82 struct gdbarch *gdbarch = get_regcache_arch (regcache);
d0f54f9d
JB
83 int i;
84 for (i = 0; i < S390_NUM_REGS; i++)
85 if (regmap_gregset[i] != -1)
86 if (regno == -1 || regno == i)
7f7fe91e 87 regcache_raw_collect (regcache, i,
8fe9ea88
MD
88 (char *)regp + regmap_gregset[i]
89 + SUBOFF (gdbarch, i));
d0f54f9d
JB
90}
91
92/* Fill GDB's register array with the floating-point register values
93 in *REGP. */
94void
7f7fe91e 95supply_fpregset (struct regcache *regcache, const fpregset_t *regp)
d0f54f9d
JB
96{
97 int i;
98 for (i = 0; i < S390_NUM_REGS; i++)
99 if (regmap_fpregset[i] != -1)
7f7fe91e
UW
100 regcache_raw_supply (regcache, i,
101 (const char *)regp + regmap_fpregset[i]);
d0f54f9d
JB
102}
103
104/* Fill register REGNO (if it is a general-purpose register) in
105 *REGP with the value in GDB's register array. If REGNO is -1,
106 do this for all registers. */
107void
7f7fe91e 108fill_fpregset (const struct regcache *regcache, fpregset_t *regp, int regno)
d0f54f9d
JB
109{
110 int i;
111 for (i = 0; i < S390_NUM_REGS; i++)
112 if (regmap_fpregset[i] != -1)
113 if (regno == -1 || regno == i)
7f7fe91e
UW
114 regcache_raw_collect (regcache, i,
115 (char *)regp + regmap_fpregset[i]);
d0f54f9d
JB
116}
117
118/* Find the TID for the current inferior thread to use with ptrace. */
119static int
120s390_inferior_tid (void)
121{
122 /* GNU/Linux LWP ID's are process ID's. */
123 int tid = TIDGET (inferior_ptid);
124 if (tid == 0)
125 tid = PIDGET (inferior_ptid); /* Not a threaded program. */
126
127 return tid;
128}
129
130/* Fetch all general-purpose registers from process/thread TID and
131 store their values in GDB's register cache. */
132static void
56be3814 133fetch_regs (struct regcache *regcache, int tid)
d0f54f9d
JB
134{
135 gregset_t regs;
136 ptrace_area parea;
137
138 parea.len = sizeof (regs);
139 parea.process_addr = (addr_t) &regs;
140 parea.kernel_addr = offsetof (struct user_regs_struct, psw);
141 if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
e2e0b3e5 142 perror_with_name (_("Couldn't get registers"));
d0f54f9d 143
56be3814 144 supply_gregset (regcache, (const gregset_t *) &regs);
d0f54f9d
JB
145}
146
147/* Store all valid general-purpose registers in GDB's register cache
148 into the process/thread specified by TID. */
149static void
56be3814 150store_regs (const struct regcache *regcache, int tid, int regnum)
d0f54f9d
JB
151{
152 gregset_t regs;
153 ptrace_area parea;
154
155 parea.len = sizeof (regs);
156 parea.process_addr = (addr_t) &regs;
157 parea.kernel_addr = offsetof (struct user_regs_struct, psw);
158 if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
e2e0b3e5 159 perror_with_name (_("Couldn't get registers"));
d0f54f9d 160
56be3814 161 fill_gregset (regcache, &regs, regnum);
d0f54f9d
JB
162
163 if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
e2e0b3e5 164 perror_with_name (_("Couldn't write registers"));
d0f54f9d
JB
165}
166
167/* Fetch all floating-point registers from process/thread TID and store
168 their values in GDB's register cache. */
169static void
56be3814 170fetch_fpregs (struct regcache *regcache, int tid)
d0f54f9d
JB
171{
172 fpregset_t fpregs;
173 ptrace_area parea;
174
175 parea.len = sizeof (fpregs);
176 parea.process_addr = (addr_t) &fpregs;
177 parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
178 if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
e2e0b3e5 179 perror_with_name (_("Couldn't get floating point status"));
d0f54f9d 180
56be3814 181 supply_fpregset (regcache, (const fpregset_t *) &fpregs);
d0f54f9d
JB
182}
183
184/* Store all valid floating-point registers in GDB's register cache
185 into the process/thread specified by TID. */
186static void
56be3814 187store_fpregs (const struct regcache *regcache, int tid, int regnum)
d0f54f9d
JB
188{
189 fpregset_t fpregs;
190 ptrace_area parea;
191
192 parea.len = sizeof (fpregs);
193 parea.process_addr = (addr_t) &fpregs;
194 parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
195 if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
e2e0b3e5 196 perror_with_name (_("Couldn't get floating point status"));
d0f54f9d 197
56be3814 198 fill_fpregset (regcache, &fpregs, regnum);
d0f54f9d
JB
199
200 if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
e2e0b3e5 201 perror_with_name (_("Couldn't write floating point status"));
d0f54f9d
JB
202}
203
204/* Fetch register REGNUM from the child process. If REGNUM is -1, do
205 this for all registers. */
10d6c8cd 206static void
28439f5e
PA
207s390_linux_fetch_inferior_registers (struct target_ops *ops,
208 struct regcache *regcache, int regnum)
d0f54f9d
JB
209{
210 int tid = s390_inferior_tid ();
211
212 if (regnum == -1
213 || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
56be3814 214 fetch_regs (regcache, tid);
d0f54f9d
JB
215
216 if (regnum == -1
217 || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
56be3814 218 fetch_fpregs (regcache, tid);
d0f54f9d
JB
219}
220
221/* Store register REGNUM back into the child process. If REGNUM is
222 -1, do this for all registers. */
10d6c8cd 223static void
28439f5e
PA
224s390_linux_store_inferior_registers (struct target_ops *ops,
225 struct regcache *regcache, int regnum)
d0f54f9d
JB
226{
227 int tid = s390_inferior_tid ();
228
229 if (regnum == -1
230 || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
56be3814 231 store_regs (regcache, tid, regnum);
d0f54f9d
JB
232
233 if (regnum == -1
234 || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
56be3814 235 store_fpregs (regcache, tid, regnum);
5769d3cd
AC
236}
237
d0f54f9d 238
e1457d83
JB
239/* Hardware-assisted watchpoint handling. */
240
241/* We maintain a list of all currently active watchpoints in order
242 to properly handle watchpoint removal.
243
244 The only thing we actually need is the total address space area
245 spanned by the watchpoints. */
246
5769d3cd
AC
247struct watch_area
248{
e1457d83 249 struct watch_area *next;
5769d3cd
AC
250 CORE_ADDR lo_addr;
251 CORE_ADDR hi_addr;
252};
253
e1457d83 254static struct watch_area *watch_base = NULL;
5769d3cd 255
fd7979d1 256static int
e1457d83 257s390_stopped_by_watchpoint (void)
5769d3cd
AC
258{
259 per_lowcore_bits per_lowcore;
260 ptrace_area parea;
9f0bdab8 261 int result;
5769d3cd 262
e1457d83
JB
263 /* Speed up common case. */
264 if (!watch_base)
265 return 0;
266
5769d3cd
AC
267 parea.len = sizeof (per_lowcore);
268 parea.process_addr = (addr_t) & per_lowcore;
269 parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
e1457d83 270 if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
e2e0b3e5 271 perror_with_name (_("Couldn't retrieve watchpoint status"));
5769d3cd 272
9f0bdab8
DJ
273 result = (per_lowcore.perc_storage_alteration == 1
274 && per_lowcore.perc_store_real_address == 0);
275
276 if (result)
277 {
278 /* Do not report this watchpoint again. */
279 memset (&per_lowcore, 0, sizeof (per_lowcore));
280 if (ptrace (PTRACE_POKEUSR_AREA, s390_inferior_tid (), &parea) < 0)
281 perror_with_name (_("Couldn't clear watchpoint status"));
282 }
283
284 return result;
e1457d83 285}
5769d3cd 286
e1457d83 287static void
9f0bdab8 288s390_fix_watch_points (ptid_t ptid)
5769d3cd 289{
9f0bdab8 290 int tid;
e1457d83 291
5769d3cd
AC
292 per_struct per_info;
293 ptrace_area parea;
294
e1457d83
JB
295 CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0;
296 struct watch_area *area;
297
9f0bdab8
DJ
298 tid = TIDGET (ptid);
299 if (tid == 0)
300 tid = PIDGET (ptid);
301
e1457d83
JB
302 for (area = watch_base; area; area = area->next)
303 {
304 watch_lo_addr = min (watch_lo_addr, area->lo_addr);
305 watch_hi_addr = max (watch_hi_addr, area->hi_addr);
306 }
307
5769d3cd
AC
308 parea.len = sizeof (per_info);
309 parea.process_addr = (addr_t) & per_info;
e1457d83
JB
310 parea.kernel_addr = offsetof (struct user_regs_struct, per_info);
311 if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0)
e2e0b3e5 312 perror_with_name (_("Couldn't retrieve watchpoint status"));
e1457d83
JB
313
314 if (watch_base)
5769d3cd
AC
315 {
316 per_info.control_regs.bits.em_storage_alteration = 1;
317 per_info.control_regs.bits.storage_alt_space_ctl = 1;
318 }
319 else
320 {
321 per_info.control_regs.bits.em_storage_alteration = 0;
322 per_info.control_regs.bits.storage_alt_space_ctl = 0;
323 }
324 per_info.starting_addr = watch_lo_addr;
325 per_info.ending_addr = watch_hi_addr;
e1457d83
JB
326
327 if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0)
e2e0b3e5 328 perror_with_name (_("Couldn't modify watchpoint status"));
5769d3cd
AC
329}
330
fd7979d1 331static int
2f00de94 332s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
5769d3cd 333{
9f0bdab8
DJ
334 struct lwp_info *lp;
335 ptid_t ptid;
e1457d83 336 struct watch_area *area = xmalloc (sizeof (struct watch_area));
9f0bdab8 337
e1457d83
JB
338 if (!area)
339 return -1;
340
341 area->lo_addr = addr;
342 area->hi_addr = addr + len - 1;
343
344 area->next = watch_base;
345 watch_base = area;
346
9f0bdab8
DJ
347 ALL_LWPS (lp, ptid)
348 s390_fix_watch_points (ptid);
e1457d83 349 return 0;
5769d3cd
AC
350}
351
fd7979d1 352static int
2f00de94 353s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
5769d3cd 354{
9f0bdab8
DJ
355 struct lwp_info *lp;
356 ptid_t ptid;
e1457d83
JB
357 struct watch_area *area, **parea;
358
359 for (parea = &watch_base; *parea; parea = &(*parea)->next)
360 if ((*parea)->lo_addr == addr
361 && (*parea)->hi_addr == addr + len - 1)
362 break;
363
364 if (!*parea)
5769d3cd
AC
365 {
366 fprintf_unfiltered (gdb_stderr,
e1457d83 367 "Attempt to remove nonexistent watchpoint.\n");
5769d3cd
AC
368 return -1;
369 }
e1457d83
JB
370
371 area = *parea;
372 *parea = area->next;
373 xfree (area);
374
9f0bdab8
DJ
375 ALL_LWPS (lp, ptid)
376 s390_fix_watch_points (ptid);
e1457d83 377 return 0;
5769d3cd
AC
378}
379
fd7979d1
UW
380static int
381s390_can_use_hw_breakpoint (int type, int cnt, int othertype)
382{
383 return 1;
384}
e1457d83 385
fd7979d1 386static int
2a3cdf79 387s390_region_ok_for_hw_watchpoint (CORE_ADDR addr, int cnt)
5769d3cd 388{
fd7979d1 389 return 1;
5769d3cd
AC
390}
391
fd7979d1 392
10d6c8cd
DJ
393void _initialize_s390_nat (void);
394
395void
396_initialize_s390_nat (void)
397{
398 struct target_ops *t;
399
400 /* Fill in the generic GNU/Linux methods. */
401 t = linux_target ();
402
403 /* Add our register access methods. */
404 t->to_fetch_registers = s390_linux_fetch_inferior_registers;
405 t->to_store_registers = s390_linux_store_inferior_registers;
406
fd7979d1
UW
407 /* Add our watchpoint methods. */
408 t->to_can_use_hw_breakpoint = s390_can_use_hw_breakpoint;
2a3cdf79 409 t->to_region_ok_for_hw_watchpoint = s390_region_ok_for_hw_watchpoint;
fd7979d1
UW
410 t->to_have_continuable_watchpoint = 1;
411 t->to_stopped_by_watchpoint = s390_stopped_by_watchpoint;
412 t->to_insert_watchpoint = s390_insert_watchpoint;
413 t->to_remove_watchpoint = s390_remove_watchpoint;
414
10d6c8cd 415 /* Register the target. */
f973ed9c 416 linux_nat_add_target (t);
9f0bdab8 417 linux_nat_set_new_thread (t, s390_fix_watch_points);
10d6c8cd 418}