OSDN Git Service

* gregset.h (struct regcache): Add forward declaration.
[pf3gnuchains/pf3gnuchains3x.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 "regcache.h"
27 #include "inferior.h"
28 #include "target.h"
29 #include "linux-nat.h"
30
31 #include "s390-tdep.h"
32
33 #include <asm/ptrace.h>
34 #include <sys/ptrace.h>
35 #include <asm/types.h>
36 #include <sys/procfs.h>
37 #include <sys/ucontext.h>
38
39
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
45 #else
46 #define regmap_gregset s390_regmap_gregset
47 #endif
48
49 #define regmap_fpregset s390_regmap_fpregset
50
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) \
56         ((TARGET_PTR_BIT == 32 \
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
63
64 /* Fill GDB's register array with the general-purpose register values
65    in *REGP.  */
66 void
67 supply_gregset (struct regcache *regcache, const gregset_t *regp)
68 {
69   int i;
70   for (i = 0; i < S390_NUM_REGS; i++)
71     if (regmap_gregset[i] != -1)
72       regcache_raw_supply (regcache, i, 
73                            (const char *)regp + regmap_gregset[i] + SUBOFF (i));
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.  */
79 void
80 fill_gregset (const struct regcache *regcache, gregset_t *regp, int regno)
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)
86         regcache_raw_collect (regcache, i, 
87                               (char *)regp + regmap_gregset[i] + SUBOFF (i));
88 }
89
90 /* Fill GDB's register array with the floating-point register values
91    in *REGP.  */
92 void
93 supply_fpregset (struct regcache *regcache, const fpregset_t *regp)
94 {
95   int i;
96   for (i = 0; i < S390_NUM_REGS; i++)
97     if (regmap_fpregset[i] != -1)
98       regcache_raw_supply (regcache, i,
99                            (const char *)regp + regmap_fpregset[i]);
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.  */
105 void
106 fill_fpregset (const struct regcache *regcache, fpregset_t *regp, int regno)
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)
112         regcache_raw_collect (regcache, i, 
113                               (char *)regp + regmap_fpregset[i]);
114 }
115
116 /* Find the TID for the current inferior thread to use with ptrace.  */
117 static int
118 s390_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.  */
130 static void
131 fetch_regs (int tid)
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)
140     perror_with_name (_("Couldn't get registers"));
141
142   supply_gregset (current_regcache, (const gregset_t *) &regs);
143 }
144
145 /* Store all valid general-purpose registers in GDB's register cache
146    into the process/thread specified by TID.  */
147 static void
148 store_regs (int tid, int regnum)
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)
157     perror_with_name (_("Couldn't get registers"));
158
159   fill_gregset (current_regcache, &regs, regnum);
160
161   if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
162     perror_with_name (_("Couldn't write registers"));
163 }
164
165 /* Fetch all floating-point registers from process/thread TID and store
166    their values in GDB's register cache.  */
167 static void
168 fetch_fpregs (int tid)
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)
177     perror_with_name (_("Couldn't get floating point status"));
178
179   supply_fpregset (current_regcache, (const fpregset_t *) &fpregs);
180 }
181
182 /* Store all valid floating-point registers in GDB's register cache
183    into the process/thread specified by TID.  */
184 static void
185 store_fpregs (int tid, int regnum)
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)
194     perror_with_name (_("Couldn't get floating point status"));
195
196   fill_fpregset (current_regcache, &fpregs, regnum);
197
198   if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
199     perror_with_name (_("Couldn't write floating point status"));
200 }
201
202 /* Fetch register REGNUM from the child process.  If REGNUM is -1, do
203    this for all registers.  */
204 static void
205 s390_linux_fetch_inferior_registers (int regnum)
206 {
207   int tid = s390_inferior_tid ();
208
209   if (regnum == -1 
210       || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
211     fetch_regs (tid);
212
213   if (regnum == -1 
214       || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
215     fetch_fpregs (tid);
216 }
217
218 /* Store register REGNUM back into the child process.  If REGNUM is
219    -1, do this for all registers.  */
220 static void
221 s390_linux_store_inferior_registers (int regnum)
222 {
223   int tid = s390_inferior_tid ();
224
225   if (regnum == -1 
226       || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
227     store_regs (tid, regnum);
228
229   if (regnum == -1 
230       || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
231     store_fpregs (tid, regnum);
232 }
233
234
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
243 struct watch_area
244 {
245   struct watch_area *next;
246   CORE_ADDR lo_addr;
247   CORE_ADDR hi_addr;
248 };
249
250 static struct watch_area *watch_base = NULL;
251
252 static int
253 s390_stopped_by_watchpoint (void)
254 {
255   per_lowcore_bits per_lowcore;
256   ptrace_area parea;
257
258   /* Speed up common case.  */
259   if (!watch_base)
260     return 0;
261
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);
265   if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
266     perror_with_name (_("Couldn't retrieve watchpoint status"));
267
268   return per_lowcore.perc_storage_alteration == 1
269          && per_lowcore.perc_store_real_address == 0;
270 }
271
272 static void
273 s390_fix_watch_points (void)
274 {
275   int tid = s390_inferior_tid ();
276
277   per_struct per_info;
278   ptrace_area parea;
279
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
289   parea.len = sizeof (per_info);
290   parea.process_addr = (addr_t) & per_info;
291   parea.kernel_addr = offsetof (struct user_regs_struct, per_info);
292   if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0)
293     perror_with_name (_("Couldn't retrieve watchpoint status"));
294
295   if (watch_base)
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;
307
308   if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0)
309     perror_with_name (_("Couldn't modify watchpoint status"));
310 }
311
312 static int
313 s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
314 {
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;
327 }
328
329 static int
330 s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
331 {
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)
340     {
341       fprintf_unfiltered (gdb_stderr,
342                           "Attempt to remove nonexistent watchpoint.\n");
343       return -1;
344     }
345
346   area = *parea;
347   *parea = area->next;
348   xfree (area);
349
350   s390_fix_watch_points ();
351   return 0;
352 }
353
354 static int
355 s390_can_use_hw_breakpoint (int type, int cnt, int othertype)
356 {
357   return 1;
358 }
359
360 static int
361 s390_region_ok_for_hw_watchpoint (CORE_ADDR addr, int cnt)
362 {
363   return 1;
364 }
365
366
367 void _initialize_s390_nat (void);
368
369 void
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
381   /* Add our watchpoint methods.  */
382   t->to_can_use_hw_breakpoint = s390_can_use_hw_breakpoint;
383   t->to_region_ok_for_hw_watchpoint = s390_region_ok_for_hw_watchpoint;
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
389   /* Register the target.  */
390   linux_nat_add_target (t);
391 }