OSDN Git Service

* inferior.c (add_inferior): Move observer_notify_new_inferior
[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 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(gdbarch, i) \
54         ((gdbarch_ptr_bit (gdbarch) == 32 \
55           && ((i) == S390_PSWA_REGNUM \
56               || ((i) >= S390_R0_REGNUM && (i) <= S390_R15_REGNUM)))? 4 : 0)
57 #else
58 #define SUBOFF(gdbarch, 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   struct gdbarch *gdbarch = get_regcache_arch (regcache);
68   int i;
69   for (i = 0; i < S390_NUM_REGS; i++)
70     if (regmap_gregset[i] != -1)
71       regcache_raw_supply (regcache, i, 
72                            (const char *)regp + regmap_gregset[i]
73                              + SUBOFF (gdbarch, 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   struct gdbarch *gdbarch = get_regcache_arch (regcache);
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 (regcache, i, 
88                               (char *)regp + regmap_gregset[i]
89                                 + SUBOFF (gdbarch, i));
90 }
91
92 /* Fill GDB's register array with the floating-point register values
93    in *REGP.  */
94 void
95 supply_fpregset (struct regcache *regcache, const fpregset_t *regp)
96 {
97   int i;
98   for (i = 0; i < S390_NUM_REGS; i++)
99     if (regmap_fpregset[i] != -1)
100       regcache_raw_supply (regcache, i,
101                            (const char *)regp + regmap_fpregset[i]);
102 }
103
104 /* Fill register REGNO (if it is a general-purpose register) in
105    *REGP with the value in GDB's register array.  If REGNO is -1,
106    do this for all registers.  */
107 void
108 fill_fpregset (const struct regcache *regcache, fpregset_t *regp, int regno)
109 {
110   int i;
111   for (i = 0; i < S390_NUM_REGS; i++)
112     if (regmap_fpregset[i] != -1)
113       if (regno == -1 || regno == i)
114         regcache_raw_collect (regcache, i, 
115                               (char *)regp + regmap_fpregset[i]);
116 }
117
118 /* Find the TID for the current inferior thread to use with ptrace.  */
119 static int
120 s390_inferior_tid (void)
121 {
122   /* GNU/Linux LWP ID's are process ID's.  */
123   int tid = TIDGET (inferior_ptid);
124   if (tid == 0)
125     tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
126
127   return tid;
128 }
129
130 /* Fetch all general-purpose registers from process/thread TID and
131    store their values in GDB's register cache.  */
132 static void
133 fetch_regs (struct regcache *regcache, int tid)
134 {
135   gregset_t regs;
136   ptrace_area parea;
137
138   parea.len = sizeof (regs);
139   parea.process_addr = (addr_t) &regs;
140   parea.kernel_addr = offsetof (struct user_regs_struct, psw);
141   if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
142     perror_with_name (_("Couldn't get registers"));
143
144   supply_gregset (regcache, (const gregset_t *) &regs);
145 }
146
147 /* Store all valid general-purpose registers in GDB's register cache
148    into the process/thread specified by TID.  */
149 static void
150 store_regs (const struct regcache *regcache, int tid, int regnum)
151 {
152   gregset_t regs;
153   ptrace_area parea;
154
155   parea.len = sizeof (regs);
156   parea.process_addr = (addr_t) &regs;
157   parea.kernel_addr = offsetof (struct user_regs_struct, psw);
158   if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
159     perror_with_name (_("Couldn't get registers"));
160
161   fill_gregset (regcache, &regs, regnum);
162
163   if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
164     perror_with_name (_("Couldn't write registers"));
165 }
166
167 /* Fetch all floating-point registers from process/thread TID and store
168    their values in GDB's register cache.  */
169 static void
170 fetch_fpregs (struct regcache *regcache, int tid)
171 {
172   fpregset_t fpregs;
173   ptrace_area parea;
174
175   parea.len = sizeof (fpregs);
176   parea.process_addr = (addr_t) &fpregs;
177   parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
178   if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
179     perror_with_name (_("Couldn't get floating point status"));
180
181   supply_fpregset (regcache, (const fpregset_t *) &fpregs);
182 }
183
184 /* Store all valid floating-point registers in GDB's register cache
185    into the process/thread specified by TID.  */
186 static void
187 store_fpregs (const struct regcache *regcache, int tid, int regnum)
188 {
189   fpregset_t fpregs;
190   ptrace_area parea;
191
192   parea.len = sizeof (fpregs);
193   parea.process_addr = (addr_t) &fpregs;
194   parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
195   if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
196     perror_with_name (_("Couldn't get floating point status"));
197
198   fill_fpregset (regcache, &fpregs, regnum);
199
200   if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
201     perror_with_name (_("Couldn't write floating point status"));
202 }
203
204 /* Fetch register REGNUM from the child process.  If REGNUM is -1, do
205    this for all registers.  */
206 static void
207 s390_linux_fetch_inferior_registers (struct target_ops *ops,
208                                      struct regcache *regcache, int regnum)
209 {
210   int tid = s390_inferior_tid ();
211
212   if (regnum == -1 
213       || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
214     fetch_regs (regcache, tid);
215
216   if (regnum == -1 
217       || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
218     fetch_fpregs (regcache, tid);
219 }
220
221 /* Store register REGNUM back into the child process.  If REGNUM is
222    -1, do this for all registers.  */
223 static void
224 s390_linux_store_inferior_registers (struct target_ops *ops,
225                                      struct regcache *regcache, int regnum)
226 {
227   int tid = s390_inferior_tid ();
228
229   if (regnum == -1 
230       || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
231     store_regs (regcache, tid, regnum);
232
233   if (regnum == -1 
234       || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
235     store_fpregs (regcache, tid, regnum);
236 }
237
238
239 /* Hardware-assisted watchpoint handling.  */
240
241 /* We maintain a list of all currently active watchpoints in order
242    to properly handle watchpoint removal.
243
244    The only thing we actually need is the total address space area
245    spanned by the watchpoints.  */
246
247 struct watch_area
248 {
249   struct watch_area *next;
250   CORE_ADDR lo_addr;
251   CORE_ADDR hi_addr;
252 };
253
254 static struct watch_area *watch_base = NULL;
255
256 static int
257 s390_stopped_by_watchpoint (void)
258 {
259   per_lowcore_bits per_lowcore;
260   ptrace_area parea;
261   int result;
262
263   /* Speed up common case.  */
264   if (!watch_base)
265     return 0;
266
267   parea.len = sizeof (per_lowcore);
268   parea.process_addr = (addr_t) & per_lowcore;
269   parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
270   if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
271     perror_with_name (_("Couldn't retrieve watchpoint status"));
272
273   result = (per_lowcore.perc_storage_alteration == 1
274             && per_lowcore.perc_store_real_address == 0);
275
276   if (result)
277     {
278       /* Do not report this watchpoint again.  */
279       memset (&per_lowcore, 0, sizeof (per_lowcore));
280       if (ptrace (PTRACE_POKEUSR_AREA, s390_inferior_tid (), &parea) < 0)
281         perror_with_name (_("Couldn't clear watchpoint status"));
282     }
283
284   return result;
285 }
286
287 static void
288 s390_fix_watch_points (ptid_t ptid)
289 {
290   int tid;
291
292   per_struct per_info;
293   ptrace_area parea;
294
295   CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0;
296   struct watch_area *area;
297
298   tid = TIDGET (ptid);
299   if (tid == 0)
300     tid = PIDGET (ptid);
301
302   for (area = watch_base; area; area = area->next)
303     {
304       watch_lo_addr = min (watch_lo_addr, area->lo_addr);
305       watch_hi_addr = max (watch_hi_addr, area->hi_addr);
306     }
307
308   parea.len = sizeof (per_info);
309   parea.process_addr = (addr_t) & per_info;
310   parea.kernel_addr = offsetof (struct user_regs_struct, per_info);
311   if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0)
312     perror_with_name (_("Couldn't retrieve watchpoint status"));
313
314   if (watch_base)
315     {
316       per_info.control_regs.bits.em_storage_alteration = 1;
317       per_info.control_regs.bits.storage_alt_space_ctl = 1;
318     }
319   else
320     {
321       per_info.control_regs.bits.em_storage_alteration = 0;
322       per_info.control_regs.bits.storage_alt_space_ctl = 0;
323     }
324   per_info.starting_addr = watch_lo_addr;
325   per_info.ending_addr = watch_hi_addr;
326
327   if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0)
328     perror_with_name (_("Couldn't modify watchpoint status"));
329 }
330
331 static int
332 s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
333 {
334   struct lwp_info *lp;
335   ptid_t ptid;
336   struct watch_area *area = xmalloc (sizeof (struct watch_area));
337
338   if (!area)
339     return -1; 
340
341   area->lo_addr = addr;
342   area->hi_addr = addr + len - 1;
343  
344   area->next = watch_base;
345   watch_base = area;
346
347   ALL_LWPS (lp, ptid)
348     s390_fix_watch_points (ptid);
349   return 0;
350 }
351
352 static int
353 s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
354 {
355   struct lwp_info *lp;
356   ptid_t ptid;
357   struct watch_area *area, **parea;
358
359   for (parea = &watch_base; *parea; parea = &(*parea)->next)
360     if ((*parea)->lo_addr == addr
361         && (*parea)->hi_addr == addr + len - 1)
362       break;
363
364   if (!*parea)
365     {
366       fprintf_unfiltered (gdb_stderr,
367                           "Attempt to remove nonexistent watchpoint.\n");
368       return -1;
369     }
370
371   area = *parea;
372   *parea = area->next;
373   xfree (area);
374
375   ALL_LWPS (lp, ptid)
376     s390_fix_watch_points (ptid);
377   return 0;
378 }
379
380 static int
381 s390_can_use_hw_breakpoint (int type, int cnt, int othertype)
382 {
383   return 1;
384 }
385
386 static int
387 s390_region_ok_for_hw_watchpoint (CORE_ADDR addr, int cnt)
388 {
389   return 1;
390 }
391
392
393 void _initialize_s390_nat (void);
394
395 void
396 _initialize_s390_nat (void)
397 {
398   struct target_ops *t;
399
400   /* Fill in the generic GNU/Linux methods.  */
401   t = linux_target ();
402
403   /* Add our register access methods.  */
404   t->to_fetch_registers = s390_linux_fetch_inferior_registers;
405   t->to_store_registers = s390_linux_store_inferior_registers;
406
407   /* Add our watchpoint methods.  */
408   t->to_can_use_hw_breakpoint = s390_can_use_hw_breakpoint;
409   t->to_region_ok_for_hw_watchpoint = s390_region_ok_for_hw_watchpoint;
410   t->to_have_continuable_watchpoint = 1;
411   t->to_stopped_by_watchpoint = s390_stopped_by_watchpoint;
412   t->to_insert_watchpoint = s390_insert_watchpoint;
413   t->to_remove_watchpoint = s390_remove_watchpoint;
414
415   /* Register the target.  */
416   linux_nat_add_target (t);
417   linux_nat_set_new_thread (t, s390_fix_watch_points);
418 }