2003-04-14 Elena Zannoni <ezannoni@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>
28#include <sys/procfs.h>
29#include <sys/user.h>
30#include <value.h>
31#include <sys/ucontext.h>
32#ifndef offsetof
33#define offsetof(type,member) ((size_t) &((type *)0)->member)
34#endif
35
36
37int
38s390_register_u_addr (int blockend, int regnum)
39{
40 int retval;
41
42 if (regnum >= S390_GP0_REGNUM && regnum <= S390_GP_LAST_REGNUM)
43 retval = PT_GPR0 + ((regnum - S390_GP0_REGNUM) * S390_GPR_SIZE);
44 else if (regnum >= S390_PSWM_REGNUM && regnum <= S390_PC_REGNUM)
45 retval = PT_PSWMASK + ((regnum - S390_PSWM_REGNUM) * S390_PSW_MASK_SIZE);
46 else if (regnum == S390_FPC_REGNUM)
47 retval = PT_FPC;
48 else if (regnum >= S390_FP0_REGNUM && regnum <= S390_FPLAST_REGNUM)
49 retval =
50#if CONFIG_ARCH_S390X
51 PT_FPR0
52#else
53 PT_FPR0_HI
54#endif
55 + ((regnum - S390_FP0_REGNUM) * S390_FPR_SIZE);
56 else if (regnum >= S390_FIRST_ACR && regnum <= S390_LAST_ACR)
57 retval = PT_ACR0 + ((regnum - S390_FIRST_ACR) * S390_ACR_SIZE);
58 else if (regnum >= (S390_FIRST_CR + 9) && regnum <= (S390_FIRST_CR + 11))
59 retval = PT_CR_9 + ((regnum - (S390_FIRST_CR + 9)) * S390_CR_SIZE);
60 else
61 {
62#ifdef GDBSERVER
e2d46a8c
JB
63 error ("s390_register_u_addr invalid regnum %s %d regnum=%d",
64 __FILE__, (int) __LINE__, regnum);
5769d3cd 65#else
e2d46a8c
JB
66 internal_error (__FILE__, __LINE__,
67 "s390_register_u_addr invalid regnum regnum=%d",
68 regnum);
5769d3cd 69#endif
5769d3cd
AC
70 retval = 0;
71 }
72 return retval + blockend;
73}
74
75#ifndef GDBSERVER
76/* watch_areas are required if you put 2 or more watchpoints on the same
77 address or overlapping areas gdb will call us to delete the watchpoint
78 more than once when we try to delete them.
79 attempted reference counting to reduce the number of areas unfortunately
80 they didn't shrink when areas had to be split overlapping occurs. */
81struct watch_area;
82typedef struct watch_area watch_area;
83struct watch_area
84{
85 watch_area *next;
86 CORE_ADDR lo_addr;
87 CORE_ADDR hi_addr;
88};
89
90static watch_area *watch_base = NULL;
91int watch_area_cnt = 0;
92static CORE_ADDR watch_lo_addr = 0, watch_hi_addr = 0;
93
94
95
96CORE_ADDR
97s390_stopped_by_watchpoint (int pid)
98{
99 per_lowcore_bits per_lowcore;
100 ptrace_area parea;
101
102 parea.len = sizeof (per_lowcore);
103 parea.process_addr = (addr_t) & per_lowcore;
104 parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
105 ptrace (PTRACE_PEEKUSR_AREA, pid, &parea);
106 return ((per_lowcore.perc_storage_alteration == 1) &&
107 (per_lowcore.perc_store_real_address == 0));
108}
109
110
111void
112s390_fix_watch_points (int pid)
113{
114 per_struct per_info;
115 ptrace_area parea;
116
117 parea.len = sizeof (per_info);
118 parea.process_addr = (addr_t) & per_info;
119 parea.kernel_addr = PT_CR_9;
120 ptrace (PTRACE_PEEKUSR_AREA, pid, &parea);
121 /* The kernel automatically sets the psw for per depending */
122 /* on whether the per control registers are set for event recording */
123 /* & sets cr9 & cr10 appropriately also */
124 if (watch_area_cnt)
125 {
126 per_info.control_regs.bits.em_storage_alteration = 1;
127 per_info.control_regs.bits.storage_alt_space_ctl = 1;
128 }
129 else
130 {
131 per_info.control_regs.bits.em_storage_alteration = 0;
132 per_info.control_regs.bits.storage_alt_space_ctl = 0;
133 }
134 per_info.starting_addr = watch_lo_addr;
135 per_info.ending_addr = watch_hi_addr;
136 ptrace (PTRACE_POKEUSR_AREA, pid, &parea);
137}
138
139int
140s390_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
141{
142 CORE_ADDR hi_addr = addr + len - 1;
1de2edba 143 watch_area *newarea = (watch_area *) xmalloc (sizeof (watch_area));
5769d3cd
AC
144
145
146 if (newarea)
147 {
148 newarea->next = watch_base;
149 watch_base = newarea;
150 watch_lo_addr = min (watch_lo_addr, addr);
151 watch_hi_addr = max (watch_hi_addr, hi_addr);
152 newarea->lo_addr = addr;
153 newarea->hi_addr = hi_addr;
154 if (watch_area_cnt == 0)
155 {
156 watch_lo_addr = newarea->lo_addr;
157 watch_hi_addr = newarea->hi_addr;
158 }
159 watch_area_cnt++;
160 s390_fix_watch_points (pid);
161 }
162 return newarea ? 0 : -1;
163}
164
165
166int
167s390_remove_watchpoint (int pid, CORE_ADDR addr, int len)
168{
169 watch_area *curr = watch_base, *prev, *matchCurr;
170 CORE_ADDR hi_addr = addr + len - 1;
171 CORE_ADDR watch_second_lo_addr = 0xffffffffUL, watch_second_hi_addr = 0;
172 int lo_addr_ref_cnt, hi_addr_ref_cnt;
173 prev = matchCurr = NULL;
174 lo_addr_ref_cnt = (addr == watch_lo_addr);
175 hi_addr_ref_cnt = (addr == watch_hi_addr);
176 while (curr)
177 {
178 if (matchCurr == NULL)
179 {
180 if (curr->lo_addr == addr && curr->hi_addr == hi_addr)
181 {
182 matchCurr = curr;
183 if (prev)
184 prev->next = curr->next;
185 else
186 watch_base = curr->next;
187 }
188 prev = curr;
189 }
190 if (lo_addr_ref_cnt)
191 {
192 if (watch_lo_addr == curr->lo_addr)
193 lo_addr_ref_cnt++;
194 if (curr->lo_addr > watch_lo_addr &&
195 curr->lo_addr < watch_second_lo_addr)
196 watch_second_lo_addr = curr->lo_addr;
197 }
198 if (hi_addr_ref_cnt)
199 {
200 if (watch_hi_addr == curr->hi_addr)
201 hi_addr_ref_cnt++;
202 if (curr->hi_addr < watch_hi_addr &&
203 curr->hi_addr > watch_second_hi_addr)
204 watch_second_hi_addr = curr->hi_addr;
205 }
206 curr = curr->next;
207 }
208 if (matchCurr)
209 {
1de2edba 210 xfree (matchCurr);
5769d3cd
AC
211 watch_area_cnt--;
212 if (watch_area_cnt)
213 {
214 if (lo_addr_ref_cnt == 2)
215 watch_lo_addr = watch_second_lo_addr;
216 if (hi_addr_ref_cnt == 2)
217 watch_hi_addr = watch_second_hi_addr;
218 }
219 else
220 {
221 watch_lo_addr = watch_hi_addr = 0;
222 }
223 s390_fix_watch_points (pid);
224 return 0;
225 }
226 else
227 {
228 fprintf_unfiltered (gdb_stderr,
229 "Attempt to remove nonexistent watchpoint in s390_remove_watchpoint\n");
230 return -1;
231 }
232}
233
234int
235kernel_u_size (void)
236{
237 return sizeof (struct user);
238}
239
240
241#if (defined (S390_FP0_REGNUM) && defined (HAVE_FPREGSET_T) && defined(HAVE_SYS_PROCFS_H) && defined (HAVE_GREGSET_T))
242void
243supply_gregset (gregset_t * gregsetp)
244{
245 int regi;
246 greg_t *gregp = (greg_t *) gregsetp;
247
248 supply_register (S390_PSWM_REGNUM, (char *) &gregp[S390_PSWM_REGNUM]);
249 supply_register (S390_PC_REGNUM, (char *) &gregp[S390_PC_REGNUM]);
250 for (regi = 0; regi < S390_NUM_GPRS; regi++)
251 supply_register (S390_GP0_REGNUM + regi,
252 (char *) &gregp[S390_GP0_REGNUM + regi]);
253 for (regi = 0; regi < S390_NUM_ACRS; regi++)
254 supply_register (S390_FIRST_ACR + regi,
255 (char *) &gregp[S390_FIRST_ACR + regi]);
256 /* unfortunately this isn't in gregsetp */
257 for (regi = 0; regi < S390_NUM_CRS; regi++)
258 supply_register (S390_FIRST_CR + regi, NULL);
259}
260
261
262void
263supply_fpregset (fpregset_t * fpregsetp)
264{
265 int regi;
266
267 supply_register (S390_FPC_REGNUM, (char *) &fpregsetp->fpc);
268 for (regi = 0; regi < S390_NUM_FPRS; regi++)
269 supply_register (S390_FP0_REGNUM + regi, (char *) &fpregsetp->fprs[regi]);
270
271}
272
273void
274fill_gregset (gregset_t * gregsetp, int regno)
275{
30413464 276 int regi;
5769d3cd
AC
277 greg_t *gregp = (greg_t *) gregsetp;
278
30413464
AC
279 if (regno < 0)
280 {
281 regcache_collect (S390_PSWM_REGNUM, &gregp[S390_PSWM_REGNUM]);
282 regcache_collect (S390_PC_REGNUM, &gregp[S390_PC_REGNUM]);
283 for (regi = 0; regi < S390_NUM_GPRS; regi++)
284 regcache_collect (S390_GP0_REGNUM + regi,
285 &gregp[S390_GP0_REGNUM + regi]);
286 for (regi = 0; regi < S390_NUM_ACRS; regi++)
287 regcache_collect (S390_FIRST_ACR + regi,
288 &gregp[S390_FIRST_ACR + regi]);
289 }
290 else if (regno >= S390_PSWM_REGNUM && regno <= S390_LAST_ACR)
291 regcache_collect (regno, &gregp[regno]);
5769d3cd
AC
292}
293
294/* Given a pointer to a floating point register set in /proc format
295 (fpregset_t *), update the register specified by REGNO from gdb's idea
296 of the current floating point register set. If REGNO is -1, update
297 them all. */
298
299void
300fill_fpregset (fpregset_t * fpregsetp, int regno)
301{
30413464
AC
302 int regi;
303
304 if (regno < 0)
305 {
306 regcache_collect (S390_FPC_REGNUM, &fpregsetp->fpc);
307 for (regi = 0; regi < S390_NUM_FPRS; regi++)
308 regcache_collect (S390_FP0_REGNUM + regi, &fpregsetp->fprs[regi]);
309 }
310 else if (regno == S390_FPC_REGNUM)
311 regcache_collect (S390_FPC_REGNUM, &fpregsetp->fpc);
312 else if (regno >= S390_FP0_REGNUM && regno <= S390_FPLAST_REGNUM)
313 regcache_collect (regno, &fpregsetp->fprs[regno - S390_FP0_REGNUM]);
5769d3cd
AC
314}
315
316
317#else
318#error "There are a few possibilities here"
319#error "1) You aren't compiling for linux & don't need a core dumps to work."
320#error "2) The header files sys/elf.h sys/user.h sys/ptrace.h & sys/procfs.h"
321#error "libc files are inconsistent with linux/include/asm-s390/"
322#error "3) you didn't do a completely clean build & delete config.cache."
323#endif
324#endif /* GDBSERVER */
This page took 0.234553 seconds and 4 git commands to generate.