* s390-nat.c (supply_gregset, fill_gregset): On the s390x, the
[platform/upstream/binutils.git] / gdb / s390-nat.c
1 /* S390 native-dependent code for GDB, the GNU debugger.
2    Copyright 2001 Free Software Foundation, Inc
3    Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
4    for IBM Deutschland Entwicklung GmbH, IBM Corporation.
5    This file is part of GDB.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
21
22 #include "defs.h"
23 #include "tm.h"
24 #include "regcache.h"
25 #include <asm/ptrace.h>
26 #include <sys/ptrace.h>
27 #include <asm/processor.h>
28 #include <asm/types.h>
29 #include <sys/procfs.h>
30 #include <sys/user.h>
31 #include <value.h>
32 #include <sys/ucontext.h>
33 #ifndef offsetof
34 #define offsetof(type,member) ((size_t) &((type *)0)->member)
35 #endif
36
37
38 int
39 s390_register_u_addr (int blockend, int regnum)
40 {
41   int retval;
42
43   if (regnum >= S390_GP0_REGNUM && regnum <= S390_GP_LAST_REGNUM)
44     retval = PT_GPR0 + ((regnum - S390_GP0_REGNUM) * S390_GPR_SIZE);
45   else if (regnum >= S390_PSWM_REGNUM && regnum <= S390_PC_REGNUM)
46     retval = PT_PSWMASK + ((regnum - S390_PSWM_REGNUM) * S390_PSW_MASK_SIZE);
47   else if (regnum == S390_FPC_REGNUM)
48     retval = PT_FPC;
49   else if (regnum >= S390_FP0_REGNUM && regnum <= S390_FPLAST_REGNUM)
50     retval =
51 #if CONFIG_ARCH_S390X
52       PT_FPR0
53 #else
54       PT_FPR0_HI
55 #endif
56       + ((regnum - S390_FP0_REGNUM) * S390_FPR_SIZE);
57   else if (regnum >= S390_FIRST_ACR && regnum <= S390_LAST_ACR)
58     retval = PT_ACR0 + ((regnum - S390_FIRST_ACR) * S390_ACR_SIZE);
59   else if (regnum >= (S390_FIRST_CR + 9) && regnum <= (S390_FIRST_CR + 11))
60     retval = PT_CR_9 + ((regnum - (S390_FIRST_CR + 9)) * S390_CR_SIZE);
61   else
62     {
63 #ifdef GDBSERVER
64       error ("s390_register_u_addr invalid regnum %s %d regnum=%d",
65              __FILE__, (int) __LINE__, regnum);
66 #else
67       internal_error (__FILE__, __LINE__,
68                       "s390_register_u_addr invalid regnum regnum=%d",
69                       regnum);
70 #endif
71       retval = 0;
72     }
73   return retval + blockend;
74 }
75
76 #ifndef GDBSERVER
77 /* watch_areas are required if you put 2 or more watchpoints on the same 
78    address or overlapping areas gdb will call us to delete the watchpoint 
79    more than once when we try to delete them.
80    attempted reference counting to reduce the number of areas unfortunately
81    they didn't shrink when areas had to be split overlapping occurs. */
82 struct watch_area;
83 typedef struct watch_area watch_area;
84 struct watch_area
85 {
86   watch_area *next;
87   CORE_ADDR lo_addr;
88   CORE_ADDR hi_addr;
89 };
90
91 static watch_area *watch_base = NULL;
92 int watch_area_cnt = 0;
93 static CORE_ADDR watch_lo_addr = 0, watch_hi_addr = 0;
94
95
96
97 CORE_ADDR
98 s390_stopped_by_watchpoint (int pid)
99 {
100   per_lowcore_bits per_lowcore;
101   ptrace_area parea;
102
103   parea.len = sizeof (per_lowcore);
104   parea.process_addr = (addr_t) & per_lowcore;
105   parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
106   ptrace (PTRACE_PEEKUSR_AREA, pid, &parea);
107   return ((per_lowcore.perc_storage_alteration == 1) &&
108           (per_lowcore.perc_store_real_address == 0));
109 }
110
111
112 void
113 s390_fix_watch_points (int pid)
114 {
115   per_struct per_info;
116   ptrace_area parea;
117
118   parea.len = sizeof (per_info);
119   parea.process_addr = (addr_t) & per_info;
120   parea.kernel_addr = PT_CR_9;
121   ptrace (PTRACE_PEEKUSR_AREA, pid, &parea);
122   /* The kernel automatically sets the psw for per depending */
123   /* on whether the per control registers are set for event recording */
124   /* & sets cr9 & cr10 appropriately also */
125   if (watch_area_cnt)
126     {
127       per_info.control_regs.bits.em_storage_alteration = 1;
128       per_info.control_regs.bits.storage_alt_space_ctl = 1;
129     }
130   else
131     {
132       per_info.control_regs.bits.em_storage_alteration = 0;
133       per_info.control_regs.bits.storage_alt_space_ctl = 0;
134     }
135   per_info.starting_addr = watch_lo_addr;
136   per_info.ending_addr = watch_hi_addr;
137   ptrace (PTRACE_POKEUSR_AREA, pid, &parea);
138 }
139
140 int
141 s390_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
142 {
143   CORE_ADDR hi_addr = addr + len - 1;
144   watch_area *newarea = (watch_area *) xmalloc (sizeof (watch_area));
145
146
147   if (newarea)
148     {
149       newarea->next = watch_base;
150       watch_base = newarea;
151       watch_lo_addr = min (watch_lo_addr, addr);
152       watch_hi_addr = max (watch_hi_addr, hi_addr);
153       newarea->lo_addr = addr;
154       newarea->hi_addr = hi_addr;
155       if (watch_area_cnt == 0)
156         {
157           watch_lo_addr = newarea->lo_addr;
158           watch_hi_addr = newarea->hi_addr;
159         }
160       watch_area_cnt++;
161       s390_fix_watch_points (pid);
162     }
163   return newarea ? 0 : -1;
164 }
165
166
167 int
168 s390_remove_watchpoint (int pid, CORE_ADDR addr, int len)
169 {
170   watch_area *curr = watch_base, *prev, *matchCurr;
171   CORE_ADDR hi_addr = addr + len - 1;
172   CORE_ADDR watch_second_lo_addr = 0xffffffffUL, watch_second_hi_addr = 0;
173   int lo_addr_ref_cnt, hi_addr_ref_cnt;
174   prev = matchCurr = NULL;
175   lo_addr_ref_cnt = (addr == watch_lo_addr);
176   hi_addr_ref_cnt = (addr == watch_hi_addr);
177   while (curr)
178     {
179       if (matchCurr == NULL)
180         {
181           if (curr->lo_addr == addr && curr->hi_addr == hi_addr)
182             {
183               matchCurr = curr;
184               if (prev)
185                 prev->next = curr->next;
186               else
187                 watch_base = curr->next;
188             }
189           prev = curr;
190         }
191       if (lo_addr_ref_cnt)
192         {
193           if (watch_lo_addr == curr->lo_addr)
194             lo_addr_ref_cnt++;
195           if (curr->lo_addr > watch_lo_addr &&
196               curr->lo_addr < watch_second_lo_addr)
197             watch_second_lo_addr = curr->lo_addr;
198         }
199       if (hi_addr_ref_cnt)
200         {
201           if (watch_hi_addr == curr->hi_addr)
202             hi_addr_ref_cnt++;
203           if (curr->hi_addr < watch_hi_addr &&
204               curr->hi_addr > watch_second_hi_addr)
205             watch_second_hi_addr = curr->hi_addr;
206         }
207       curr = curr->next;
208     }
209   if (matchCurr)
210     {
211       xfree (matchCurr);
212       watch_area_cnt--;
213       if (watch_area_cnt)
214         {
215           if (lo_addr_ref_cnt == 2)
216             watch_lo_addr = watch_second_lo_addr;
217           if (hi_addr_ref_cnt == 2)
218             watch_hi_addr = watch_second_hi_addr;
219         }
220       else
221         {
222           watch_lo_addr = watch_hi_addr = 0;
223         }
224       s390_fix_watch_points (pid);
225       return 0;
226     }
227   else
228     {
229       fprintf_unfiltered (gdb_stderr,
230                           "Attempt to remove nonexistent watchpoint in s390_remove_watchpoint\n");
231       return -1;
232     }
233 }
234
235 int
236 kernel_u_size (void)
237 {
238   return sizeof (struct user);
239 }
240
241
242 #if  (defined (S390_FP0_REGNUM) && defined (HAVE_FPREGSET_T) && defined(HAVE_SYS_PROCFS_H) && defined (HAVE_GREGSET_T))
243 void
244 supply_gregset (gregset_t * gregsetp)
245 {
246   int regi;
247   greg_t *gregp = (greg_t *) gregsetp;
248
249   supply_register (S390_PSWM_REGNUM, (char *) &gregp[S390_PSWM_REGNUM]);
250   supply_register (S390_PC_REGNUM, (char *) &gregp[S390_PC_REGNUM]);
251   for (regi = 0; regi < S390_NUM_GPRS; regi++)
252     supply_register (S390_GP0_REGNUM + regi,
253                      (char *) &gregp[S390_GP0_REGNUM + regi]);
254
255 #if defined (CONFIG_ARCH_S390X)
256   /* On the s390x, each element of gregset_t is 8 bytes long, but
257      each access register is still only 32 bits long.  So they're
258      packed two per element.  It's apparently traditional that
259      gregset_t must be an array, so when the registers it provides
260      have different sizes, something has to get strange
261      somewhere.  */
262   {
263     unsigned int *acrs = (unsigned int *) &gregp[S390_FIRST_ACR];
264
265     for (regi = 0; regi < S390_NUM_ACRS; regi++)
266       supply_register (S390_FIRST_ACR + regi, (char *) &acrs[regi]);
267   }
268 #else
269   for (regi = 0; regi < S390_NUM_ACRS; regi++)
270     supply_register (S390_FIRST_ACR + regi,
271                      (char *) &gregp[S390_FIRST_ACR + regi]);
272 #endif
273
274   /* unfortunately this isn't in gregsetp */
275   for (regi = 0; regi < S390_NUM_CRS; regi++)
276     supply_register (S390_FIRST_CR + regi, NULL);
277 }
278
279
280 void
281 supply_fpregset (fpregset_t * fpregsetp)
282 {
283   int regi;
284
285   supply_register (S390_FPC_REGNUM, (char *) &fpregsetp->fpc);
286   for (regi = 0; regi < S390_NUM_FPRS; regi++)
287     supply_register (S390_FP0_REGNUM + regi, (char *) &fpregsetp->fprs[regi]);
288
289 }
290
291 void
292 fill_gregset (gregset_t * gregsetp, int regno)
293 {
294   int regi;
295   greg_t *gregp = (greg_t *) gregsetp;
296
297   if (regno < 0) 
298     {
299       regcache_collect (S390_PSWM_REGNUM, &gregp[S390_PSWM_REGNUM]);
300       regcache_collect (S390_PC_REGNUM, &gregp[S390_PC_REGNUM]);
301       for (regi = 0; regi < S390_NUM_GPRS; regi++)
302         regcache_collect (S390_GP0_REGNUM + regi,
303                           &gregp[S390_GP0_REGNUM + regi]);
304 #if defined (CONFIG_ARCH_S390X)
305       /* See the comments about the access registers in
306          supply_gregset, above.  */
307       {
308         unsigned int *acrs = (unsigned int *) &gregp[S390_FIRST_ACR];
309         
310         for (regi = 0; regi < S390_NUM_ACRS; regi++)
311           regcache_collect (S390_FIRST_ACR + regi, &acrs[regi]);
312       }
313 #else
314       for (regi = 0; regi < S390_NUM_ACRS; regi++)
315         regcache_collect (S390_FIRST_ACR + regi,
316                           &gregp[S390_FIRST_ACR + regi]);
317 #endif
318     }
319   else if (regno >= S390_PSWM_REGNUM && regno < S390_FIRST_ACR)
320     regcache_collect (regno, &gregp[regno]);
321   else if (regno >= S390_FIRST_ACR && regno <= S390_LAST_ACR)
322     {
323 #if defined (CONFIG_ARCH_S390X)
324       /* See the comments about the access registers in
325          supply_gregset, above.  */
326       unsigned int *acrs = (unsigned int *) &gregp[S390_FIRST_ACR];
327         
328       regcache_collect (regno, &acrs[regno - S390_FIRST_ACR]);
329 #else
330       regcache_collect (regno, &gregp[regno]);
331 #endif
332     }
333 }
334
335 /*  Given a pointer to a floating point register set in /proc format
336    (fpregset_t *), update the register specified by REGNO from gdb's idea
337    of the current floating point register set.  If REGNO is -1, update
338    them all. */
339
340 void
341 fill_fpregset (fpregset_t * fpregsetp, int regno)
342 {
343   int regi;
344
345   if (regno < 0) 
346     {
347       regcache_collect (S390_FPC_REGNUM, &fpregsetp->fpc);
348       for (regi = 0; regi < S390_NUM_FPRS; regi++)
349         regcache_collect (S390_FP0_REGNUM + regi, &fpregsetp->fprs[regi]);
350     }
351   else if (regno == S390_FPC_REGNUM)
352     regcache_collect (S390_FPC_REGNUM, &fpregsetp->fpc);
353   else if (regno >= S390_FP0_REGNUM && regno <= S390_FPLAST_REGNUM)
354     regcache_collect (regno, &fpregsetp->fprs[regno - S390_FP0_REGNUM]);
355 }
356
357
358 #else
359 #error "There are a few possibilities here"
360 #error "1) You aren't compiling for linux & don't need a core dumps to work."
361 #error "2) The header files sys/elf.h sys/user.h sys/ptrace.h & sys/procfs.h"
362 #error "libc files are inconsistent with linux/include/asm-s390/"
363 #error "3) you didn't do a completely clean build & delete config.cache."
364 #endif
365 #endif /* GDBSERVER */