* sparcnbsd-tdep.c: Include "gdb_string.h".
[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 {
63#ifdef GDBSERVER
e2d46a8c
JB
64 error ("s390_register_u_addr invalid regnum %s %d regnum=%d",
65 __FILE__, (int) __LINE__, regnum);
5769d3cd 66#else
e2d46a8c
JB
67 internal_error (__FILE__, __LINE__,
68 "s390_register_u_addr invalid regnum regnum=%d",
69 regnum);
5769d3cd 70#endif
5769d3cd
AC
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. */
82struct watch_area;
83typedef struct watch_area watch_area;
84struct watch_area
85{
86 watch_area *next;
87 CORE_ADDR lo_addr;
88 CORE_ADDR hi_addr;
89};
90
91static watch_area *watch_base = NULL;
92int watch_area_cnt = 0;
93static CORE_ADDR watch_lo_addr = 0, watch_hi_addr = 0;
94
95
96
97CORE_ADDR
98s390_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
112void
113s390_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
140int
141s390_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
142{
143 CORE_ADDR hi_addr = addr + len - 1;
1de2edba 144 watch_area *newarea = (watch_area *) xmalloc (sizeof (watch_area));
5769d3cd
AC
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
167int
168s390_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 {
1de2edba 211 xfree (matchCurr);
5769d3cd
AC
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
235int
236kernel_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))
243void
244supply_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 for (regi = 0; regi < S390_NUM_ACRS; regi++)
255 supply_register (S390_FIRST_ACR + regi,
256 (char *) &gregp[S390_FIRST_ACR + regi]);
257 /* unfortunately this isn't in gregsetp */
258 for (regi = 0; regi < S390_NUM_CRS; regi++)
259 supply_register (S390_FIRST_CR + regi, NULL);
260}
261
262
263void
264supply_fpregset (fpregset_t * fpregsetp)
265{
266 int regi;
267
268 supply_register (S390_FPC_REGNUM, (char *) &fpregsetp->fpc);
269 for (regi = 0; regi < S390_NUM_FPRS; regi++)
270 supply_register (S390_FP0_REGNUM + regi, (char *) &fpregsetp->fprs[regi]);
271
272}
273
274void
275fill_gregset (gregset_t * gregsetp, int regno)
276{
30413464 277 int regi;
5769d3cd
AC
278 greg_t *gregp = (greg_t *) gregsetp;
279
30413464
AC
280 if (regno < 0)
281 {
282 regcache_collect (S390_PSWM_REGNUM, &gregp[S390_PSWM_REGNUM]);
283 regcache_collect (S390_PC_REGNUM, &gregp[S390_PC_REGNUM]);
284 for (regi = 0; regi < S390_NUM_GPRS; regi++)
285 regcache_collect (S390_GP0_REGNUM + regi,
286 &gregp[S390_GP0_REGNUM + regi]);
287 for (regi = 0; regi < S390_NUM_ACRS; regi++)
288 regcache_collect (S390_FIRST_ACR + regi,
289 &gregp[S390_FIRST_ACR + regi]);
290 }
291 else if (regno >= S390_PSWM_REGNUM && regno <= S390_LAST_ACR)
292 regcache_collect (regno, &gregp[regno]);
5769d3cd
AC
293}
294
295/* Given a pointer to a floating point register set in /proc format
296 (fpregset_t *), update the register specified by REGNO from gdb's idea
297 of the current floating point register set. If REGNO is -1, update
298 them all. */
299
300void
301fill_fpregset (fpregset_t * fpregsetp, int regno)
302{
30413464
AC
303 int regi;
304
305 if (regno < 0)
306 {
307 regcache_collect (S390_FPC_REGNUM, &fpregsetp->fpc);
308 for (regi = 0; regi < S390_NUM_FPRS; regi++)
309 regcache_collect (S390_FP0_REGNUM + regi, &fpregsetp->fprs[regi]);
310 }
311 else if (regno == S390_FPC_REGNUM)
312 regcache_collect (S390_FPC_REGNUM, &fpregsetp->fpc);
313 else if (regno >= S390_FP0_REGNUM && regno <= S390_FPLAST_REGNUM)
314 regcache_collect (regno, &fpregsetp->fprs[regno - S390_FP0_REGNUM]);
5769d3cd
AC
315}
316
317
318#else
319#error "There are a few possibilities here"
320#error "1) You aren't compiling for linux & don't need a core dumps to work."
321#error "2) The header files sys/elf.h sys/user.h sys/ptrace.h & sys/procfs.h"
322#error "libc files are inconsistent with linux/include/asm-s390/"
323#error "3) you didn't do a completely clean build & delete config.cache."
324#endif
325#endif /* GDBSERVER */
This page took 0.273577 seconds and 4 git commands to generate.