2003-12-03 Andrew Cagney <cagney@redhat.com>
[deliverable/binutils-gdb.git] / gdb / s390-nat.c
CommitLineData
5769d3cd
AC
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"
3ecc0ae2 24#include "regcache.h"
5769d3cd
AC
25#include <asm/ptrace.h>
26#include <sys/ptrace.h>
27#include <asm/processor.h>
2d0c7962 28#include <asm/types.h>
5769d3cd
AC
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
38int
39s390_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 {
e2d46a8c
JB
63 internal_error (__FILE__, __LINE__,
64 "s390_register_u_addr invalid regnum regnum=%d",
65 regnum);
5769d3cd
AC
66 retval = 0;
67 }
68 return retval + blockend;
69}
70
5769d3cd
AC
71/* watch_areas are required if you put 2 or more watchpoints on the same
72 address or overlapping areas gdb will call us to delete the watchpoint
73 more than once when we try to delete them.
74 attempted reference counting to reduce the number of areas unfortunately
75 they didn't shrink when areas had to be split overlapping occurs. */
76struct watch_area;
77typedef struct watch_area watch_area;
78struct watch_area
79{
80 watch_area *next;
81 CORE_ADDR lo_addr;
82 CORE_ADDR hi_addr;
83};
84
85static watch_area *watch_base = NULL;
86int watch_area_cnt = 0;
87static CORE_ADDR watch_lo_addr = 0, watch_hi_addr = 0;
88
89
90
91CORE_ADDR
92s390_stopped_by_watchpoint (int pid)
93{
94 per_lowcore_bits per_lowcore;
95 ptrace_area parea;
96
97 parea.len = sizeof (per_lowcore);
98 parea.process_addr = (addr_t) & per_lowcore;
99 parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
100 ptrace (PTRACE_PEEKUSR_AREA, pid, &parea);
101 return ((per_lowcore.perc_storage_alteration == 1) &&
102 (per_lowcore.perc_store_real_address == 0));
103}
104
105
106void
107s390_fix_watch_points (int pid)
108{
109 per_struct per_info;
110 ptrace_area parea;
111
112 parea.len = sizeof (per_info);
113 parea.process_addr = (addr_t) & per_info;
114 parea.kernel_addr = PT_CR_9;
115 ptrace (PTRACE_PEEKUSR_AREA, pid, &parea);
116 /* The kernel automatically sets the psw for per depending */
117 /* on whether the per control registers are set for event recording */
118 /* & sets cr9 & cr10 appropriately also */
119 if (watch_area_cnt)
120 {
121 per_info.control_regs.bits.em_storage_alteration = 1;
122 per_info.control_regs.bits.storage_alt_space_ctl = 1;
123 }
124 else
125 {
126 per_info.control_regs.bits.em_storage_alteration = 0;
127 per_info.control_regs.bits.storage_alt_space_ctl = 0;
128 }
129 per_info.starting_addr = watch_lo_addr;
130 per_info.ending_addr = watch_hi_addr;
131 ptrace (PTRACE_POKEUSR_AREA, pid, &parea);
132}
133
134int
135s390_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
136{
137 CORE_ADDR hi_addr = addr + len - 1;
1de2edba 138 watch_area *newarea = (watch_area *) xmalloc (sizeof (watch_area));
5769d3cd
AC
139
140
141 if (newarea)
142 {
143 newarea->next = watch_base;
144 watch_base = newarea;
145 watch_lo_addr = min (watch_lo_addr, addr);
146 watch_hi_addr = max (watch_hi_addr, hi_addr);
147 newarea->lo_addr = addr;
148 newarea->hi_addr = hi_addr;
149 if (watch_area_cnt == 0)
150 {
151 watch_lo_addr = newarea->lo_addr;
152 watch_hi_addr = newarea->hi_addr;
153 }
154 watch_area_cnt++;
155 s390_fix_watch_points (pid);
156 }
157 return newarea ? 0 : -1;
158}
159
160
161int
162s390_remove_watchpoint (int pid, CORE_ADDR addr, int len)
163{
164 watch_area *curr = watch_base, *prev, *matchCurr;
165 CORE_ADDR hi_addr = addr + len - 1;
166 CORE_ADDR watch_second_lo_addr = 0xffffffffUL, watch_second_hi_addr = 0;
167 int lo_addr_ref_cnt, hi_addr_ref_cnt;
168 prev = matchCurr = NULL;
169 lo_addr_ref_cnt = (addr == watch_lo_addr);
170 hi_addr_ref_cnt = (addr == watch_hi_addr);
171 while (curr)
172 {
173 if (matchCurr == NULL)
174 {
175 if (curr->lo_addr == addr && curr->hi_addr == hi_addr)
176 {
177 matchCurr = curr;
178 if (prev)
179 prev->next = curr->next;
180 else
181 watch_base = curr->next;
182 }
183 prev = curr;
184 }
185 if (lo_addr_ref_cnt)
186 {
187 if (watch_lo_addr == curr->lo_addr)
188 lo_addr_ref_cnt++;
189 if (curr->lo_addr > watch_lo_addr &&
190 curr->lo_addr < watch_second_lo_addr)
191 watch_second_lo_addr = curr->lo_addr;
192 }
193 if (hi_addr_ref_cnt)
194 {
195 if (watch_hi_addr == curr->hi_addr)
196 hi_addr_ref_cnt++;
197 if (curr->hi_addr < watch_hi_addr &&
198 curr->hi_addr > watch_second_hi_addr)
199 watch_second_hi_addr = curr->hi_addr;
200 }
201 curr = curr->next;
202 }
203 if (matchCurr)
204 {
1de2edba 205 xfree (matchCurr);
5769d3cd
AC
206 watch_area_cnt--;
207 if (watch_area_cnt)
208 {
209 if (lo_addr_ref_cnt == 2)
210 watch_lo_addr = watch_second_lo_addr;
211 if (hi_addr_ref_cnt == 2)
212 watch_hi_addr = watch_second_hi_addr;
213 }
214 else
215 {
216 watch_lo_addr = watch_hi_addr = 0;
217 }
218 s390_fix_watch_points (pid);
219 return 0;
220 }
221 else
222 {
223 fprintf_unfiltered (gdb_stderr,
224 "Attempt to remove nonexistent watchpoint in s390_remove_watchpoint\n");
225 return -1;
226 }
227}
228
229int
230kernel_u_size (void)
231{
232 return sizeof (struct user);
233}
234
235
236#if (defined (S390_FP0_REGNUM) && defined (HAVE_FPREGSET_T) && defined(HAVE_SYS_PROCFS_H) && defined (HAVE_GREGSET_T))
237void
238supply_gregset (gregset_t * gregsetp)
239{
240 int regi;
241 greg_t *gregp = (greg_t *) gregsetp;
242
243 supply_register (S390_PSWM_REGNUM, (char *) &gregp[S390_PSWM_REGNUM]);
244 supply_register (S390_PC_REGNUM, (char *) &gregp[S390_PC_REGNUM]);
245 for (regi = 0; regi < S390_NUM_GPRS; regi++)
246 supply_register (S390_GP0_REGNUM + regi,
247 (char *) &gregp[S390_GP0_REGNUM + regi]);
1bb792e9
JB
248
249#if defined (CONFIG_ARCH_S390X)
250 /* On the s390x, each element of gregset_t is 8 bytes long, but
251 each access register is still only 32 bits long. So they're
252 packed two per element. It's apparently traditional that
253 gregset_t must be an array, so when the registers it provides
254 have different sizes, something has to get strange
255 somewhere. */
256 {
257 unsigned int *acrs = (unsigned int *) &gregp[S390_FIRST_ACR];
258
259 for (regi = 0; regi < S390_NUM_ACRS; regi++)
260 supply_register (S390_FIRST_ACR + regi, (char *) &acrs[regi]);
261 }
262#else
5769d3cd
AC
263 for (regi = 0; regi < S390_NUM_ACRS; regi++)
264 supply_register (S390_FIRST_ACR + regi,
1bb792e9
JB
265 (char *) &gregp[S390_FIRST_ACR + regi]);
266#endif
267
5769d3cd
AC
268 /* unfortunately this isn't in gregsetp */
269 for (regi = 0; regi < S390_NUM_CRS; regi++)
270 supply_register (S390_FIRST_CR + regi, NULL);
271}
272
273
274void
275supply_fpregset (fpregset_t * fpregsetp)
276{
277 int regi;
278
279 supply_register (S390_FPC_REGNUM, (char *) &fpregsetp->fpc);
280 for (regi = 0; regi < S390_NUM_FPRS; regi++)
281 supply_register (S390_FP0_REGNUM + regi, (char *) &fpregsetp->fprs[regi]);
282
283}
284
285void
286fill_gregset (gregset_t * gregsetp, int regno)
287{
30413464 288 int regi;
5769d3cd
AC
289 greg_t *gregp = (greg_t *) gregsetp;
290
30413464
AC
291 if (regno < 0)
292 {
293 regcache_collect (S390_PSWM_REGNUM, &gregp[S390_PSWM_REGNUM]);
294 regcache_collect (S390_PC_REGNUM, &gregp[S390_PC_REGNUM]);
295 for (regi = 0; regi < S390_NUM_GPRS; regi++)
296 regcache_collect (S390_GP0_REGNUM + regi,
297 &gregp[S390_GP0_REGNUM + regi]);
1bb792e9
JB
298#if defined (CONFIG_ARCH_S390X)
299 /* See the comments about the access registers in
300 supply_gregset, above. */
301 {
302 unsigned int *acrs = (unsigned int *) &gregp[S390_FIRST_ACR];
303
304 for (regi = 0; regi < S390_NUM_ACRS; regi++)
305 regcache_collect (S390_FIRST_ACR + regi, &acrs[regi]);
306 }
307#else
30413464
AC
308 for (regi = 0; regi < S390_NUM_ACRS; regi++)
309 regcache_collect (S390_FIRST_ACR + regi,
310 &gregp[S390_FIRST_ACR + regi]);
1bb792e9 311#endif
30413464 312 }
1bb792e9 313 else if (regno >= S390_PSWM_REGNUM && regno < S390_FIRST_ACR)
30413464 314 regcache_collect (regno, &gregp[regno]);
1bb792e9
JB
315 else if (regno >= S390_FIRST_ACR && regno <= S390_LAST_ACR)
316 {
317#if defined (CONFIG_ARCH_S390X)
318 /* See the comments about the access registers in
319 supply_gregset, above. */
320 unsigned int *acrs = (unsigned int *) &gregp[S390_FIRST_ACR];
321
322 regcache_collect (regno, &acrs[regno - S390_FIRST_ACR]);
323#else
324 regcache_collect (regno, &gregp[regno]);
325#endif
326 }
5769d3cd
AC
327}
328
329/* Given a pointer to a floating point register set in /proc format
330 (fpregset_t *), update the register specified by REGNO from gdb's idea
331 of the current floating point register set. If REGNO is -1, update
332 them all. */
333
334void
335fill_fpregset (fpregset_t * fpregsetp, int regno)
336{
30413464
AC
337 int regi;
338
339 if (regno < 0)
340 {
341 regcache_collect (S390_FPC_REGNUM, &fpregsetp->fpc);
342 for (regi = 0; regi < S390_NUM_FPRS; regi++)
343 regcache_collect (S390_FP0_REGNUM + regi, &fpregsetp->fprs[regi]);
344 }
345 else if (regno == S390_FPC_REGNUM)
346 regcache_collect (S390_FPC_REGNUM, &fpregsetp->fpc);
347 else if (regno >= S390_FP0_REGNUM && regno <= S390_FPLAST_REGNUM)
348 regcache_collect (regno, &fpregsetp->fprs[regno - S390_FP0_REGNUM]);
5769d3cd
AC
349}
350
351
352#else
353#error "There are a few possibilities here"
354#error "1) You aren't compiling for linux & don't need a core dumps to work."
355#error "2) The header files sys/elf.h sys/user.h sys/ptrace.h & sys/procfs.h"
356#error "libc files are inconsistent with linux/include/asm-s390/"
357#error "3) you didn't do a completely clean build & delete config.cache."
358#endif
This page took 0.280145 seconds and 4 git commands to generate.