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