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