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