]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/s390-nat.c
Switch the license of all .c files to GPLv3.
[thirdparty/binutils-gdb.git] / gdb / s390-nat.c
1 /* S390 native-dependent code for GDB, the GNU debugger.
2 Copyright (C) 2001, 2003, 2004, 2005, 2006
3 Free Software Foundation, Inc
4
5 Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
6 for IBM Deutschland Entwicklung GmbH, IBM Corporation.
7
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 3 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, see <http://www.gnu.org/licenses/>. */
22
23 #include "defs.h"
24 #include "regcache.h"
25 #include "inferior.h"
26 #include "target.h"
27 #include "linux-nat.h"
28
29 #include "s390-tdep.h"
30
31 #include <asm/ptrace.h>
32 #include <sys/ptrace.h>
33 #include <asm/types.h>
34 #include <sys/procfs.h>
35 #include <sys/ucontext.h>
36
37
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
43 #else
44 #define regmap_gregset s390_regmap_gregset
45 #endif
46
47 #define regmap_fpregset s390_regmap_fpregset
48
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) \
54 ((gdbarch_ptr_bit (current_gdbarch) == 32 \
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
61
62 /* Fill GDB's register array with the general-purpose register values
63 in *REGP. */
64 void
65 supply_gregset (struct regcache *regcache, const gregset_t *regp)
66 {
67 int i;
68 for (i = 0; i < S390_NUM_REGS; i++)
69 if (regmap_gregset[i] != -1)
70 regcache_raw_supply (regcache, i,
71 (const char *)regp + regmap_gregset[i] + SUBOFF (i));
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. */
77 void
78 fill_gregset (const struct regcache *regcache, gregset_t *regp, int regno)
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)
84 regcache_raw_collect (regcache, i,
85 (char *)regp + regmap_gregset[i] + SUBOFF (i));
86 }
87
88 /* Fill GDB's register array with the floating-point register values
89 in *REGP. */
90 void
91 supply_fpregset (struct regcache *regcache, const fpregset_t *regp)
92 {
93 int i;
94 for (i = 0; i < S390_NUM_REGS; i++)
95 if (regmap_fpregset[i] != -1)
96 regcache_raw_supply (regcache, i,
97 (const char *)regp + regmap_fpregset[i]);
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. */
103 void
104 fill_fpregset (const struct regcache *regcache, fpregset_t *regp, int regno)
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)
110 regcache_raw_collect (regcache, i,
111 (char *)regp + regmap_fpregset[i]);
112 }
113
114 /* Find the TID for the current inferior thread to use with ptrace. */
115 static int
116 s390_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. */
128 static void
129 fetch_regs (struct regcache *regcache, int tid)
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)
138 perror_with_name (_("Couldn't get registers"));
139
140 supply_gregset (regcache, (const gregset_t *) &regs);
141 }
142
143 /* Store all valid general-purpose registers in GDB's register cache
144 into the process/thread specified by TID. */
145 static void
146 store_regs (const struct regcache *regcache, int tid, int regnum)
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)
155 perror_with_name (_("Couldn't get registers"));
156
157 fill_gregset (regcache, &regs, regnum);
158
159 if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
160 perror_with_name (_("Couldn't write registers"));
161 }
162
163 /* Fetch all floating-point registers from process/thread TID and store
164 their values in GDB's register cache. */
165 static void
166 fetch_fpregs (struct regcache *regcache, int tid)
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)
175 perror_with_name (_("Couldn't get floating point status"));
176
177 supply_fpregset (regcache, (const fpregset_t *) &fpregs);
178 }
179
180 /* Store all valid floating-point registers in GDB's register cache
181 into the process/thread specified by TID. */
182 static void
183 store_fpregs (const struct regcache *regcache, int tid, int regnum)
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)
192 perror_with_name (_("Couldn't get floating point status"));
193
194 fill_fpregset (regcache, &fpregs, regnum);
195
196 if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
197 perror_with_name (_("Couldn't write floating point status"));
198 }
199
200 /* Fetch register REGNUM from the child process. If REGNUM is -1, do
201 this for all registers. */
202 static void
203 s390_linux_fetch_inferior_registers (struct regcache *regcache, int regnum)
204 {
205 int tid = s390_inferior_tid ();
206
207 if (regnum == -1
208 || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
209 fetch_regs (regcache, tid);
210
211 if (regnum == -1
212 || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
213 fetch_fpregs (regcache, tid);
214 }
215
216 /* Store register REGNUM back into the child process. If REGNUM is
217 -1, do this for all registers. */
218 static void
219 s390_linux_store_inferior_registers (struct regcache *regcache, int regnum)
220 {
221 int tid = s390_inferior_tid ();
222
223 if (regnum == -1
224 || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
225 store_regs (regcache, tid, regnum);
226
227 if (regnum == -1
228 || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
229 store_fpregs (regcache, tid, regnum);
230 }
231
232
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
241 struct watch_area
242 {
243 struct watch_area *next;
244 CORE_ADDR lo_addr;
245 CORE_ADDR hi_addr;
246 };
247
248 static struct watch_area *watch_base = NULL;
249
250 static int
251 s390_stopped_by_watchpoint (void)
252 {
253 per_lowcore_bits per_lowcore;
254 ptrace_area parea;
255
256 /* Speed up common case. */
257 if (!watch_base)
258 return 0;
259
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);
263 if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
264 perror_with_name (_("Couldn't retrieve watchpoint status"));
265
266 return per_lowcore.perc_storage_alteration == 1
267 && per_lowcore.perc_store_real_address == 0;
268 }
269
270 static void
271 s390_fix_watch_points (void)
272 {
273 int tid = s390_inferior_tid ();
274
275 per_struct per_info;
276 ptrace_area parea;
277
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
287 parea.len = sizeof (per_info);
288 parea.process_addr = (addr_t) & per_info;
289 parea.kernel_addr = offsetof (struct user_regs_struct, per_info);
290 if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0)
291 perror_with_name (_("Couldn't retrieve watchpoint status"));
292
293 if (watch_base)
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;
305
306 if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0)
307 perror_with_name (_("Couldn't modify watchpoint status"));
308 }
309
310 static int
311 s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
312 {
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;
325 }
326
327 static int
328 s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
329 {
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)
338 {
339 fprintf_unfiltered (gdb_stderr,
340 "Attempt to remove nonexistent watchpoint.\n");
341 return -1;
342 }
343
344 area = *parea;
345 *parea = area->next;
346 xfree (area);
347
348 s390_fix_watch_points ();
349 return 0;
350 }
351
352 static int
353 s390_can_use_hw_breakpoint (int type, int cnt, int othertype)
354 {
355 return 1;
356 }
357
358 static int
359 s390_region_ok_for_hw_watchpoint (CORE_ADDR addr, int cnt)
360 {
361 return 1;
362 }
363
364
365 void _initialize_s390_nat (void);
366
367 void
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
379 /* Add our watchpoint methods. */
380 t->to_can_use_hw_breakpoint = s390_can_use_hw_breakpoint;
381 t->to_region_ok_for_hw_watchpoint = s390_region_ok_for_hw_watchpoint;
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
387 /* Register the target. */
388 linux_nat_add_target (t);
389 }