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