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.
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.
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.
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
24 #include <asm/ptrace.h>
25 #include <sys/ptrace.h>
26 #include <asm/processor.h>
27 #include <sys/procfs.h>
30 #include <sys/ucontext.h>
32 #define offsetof(type,member) ((size_t) &((type *)0)->member)
37 s390_register_u_addr (int blockend, int regnum)
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)
47 else if (regnum >= S390_FP0_REGNUM && regnum <= S390_FPLAST_REGNUM)
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);
66 ("s390_register_u_addr invalid regnum %s %d regnum=%d", __FILE__,
67 (int) __LINE__, regnum);
70 return retval + blockend;
74 /* watch_areas are required if you put 2 or more watchpoints on the same
75 address or overlapping areas gdb will call us to delete the watchpoint
76 more than once when we try to delete them.
77 attempted reference counting to reduce the number of areas unfortunately
78 they didn't shrink when areas had to be split overlapping occurs. */
80 typedef struct watch_area watch_area;
88 static watch_area *watch_base = NULL;
89 int watch_area_cnt = 0;
90 static CORE_ADDR watch_lo_addr = 0, watch_hi_addr = 0;
95 s390_stopped_by_watchpoint (int pid)
97 per_lowcore_bits per_lowcore;
100 parea.len = sizeof (per_lowcore);
101 parea.process_addr = (addr_t) & per_lowcore;
102 parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
103 ptrace (PTRACE_PEEKUSR_AREA, pid, &parea);
104 return ((per_lowcore.perc_storage_alteration == 1) &&
105 (per_lowcore.perc_store_real_address == 0));
110 s390_fix_watch_points (int pid)
115 parea.len = sizeof (per_info);
116 parea.process_addr = (addr_t) & per_info;
117 parea.kernel_addr = PT_CR_9;
118 ptrace (PTRACE_PEEKUSR_AREA, pid, &parea);
119 /* The kernel automatically sets the psw for per depending */
120 /* on whether the per control registers are set for event recording */
121 /* & sets cr9 & cr10 appropriately also */
124 per_info.control_regs.bits.em_storage_alteration = 1;
125 per_info.control_regs.bits.storage_alt_space_ctl = 1;
129 per_info.control_regs.bits.em_storage_alteration = 0;
130 per_info.control_regs.bits.storage_alt_space_ctl = 0;
132 per_info.starting_addr = watch_lo_addr;
133 per_info.ending_addr = watch_hi_addr;
134 ptrace (PTRACE_POKEUSR_AREA, pid, &parea);
138 s390_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
140 CORE_ADDR hi_addr = addr + len - 1;
141 watch_area *newarea = (watch_area *) malloc (sizeof (watch_area));
146 newarea->next = watch_base;
147 watch_base = newarea;
148 watch_lo_addr = min (watch_lo_addr, addr);
149 watch_hi_addr = max (watch_hi_addr, hi_addr);
150 newarea->lo_addr = addr;
151 newarea->hi_addr = hi_addr;
152 if (watch_area_cnt == 0)
154 watch_lo_addr = newarea->lo_addr;
155 watch_hi_addr = newarea->hi_addr;
158 s390_fix_watch_points (pid);
160 return newarea ? 0 : -1;
165 s390_remove_watchpoint (int pid, CORE_ADDR addr, int len)
167 watch_area *curr = watch_base, *prev, *matchCurr;
168 CORE_ADDR hi_addr = addr + len - 1;
169 CORE_ADDR watch_second_lo_addr = 0xffffffffUL, watch_second_hi_addr = 0;
170 int lo_addr_ref_cnt, hi_addr_ref_cnt;
171 prev = matchCurr = NULL;
172 lo_addr_ref_cnt = (addr == watch_lo_addr);
173 hi_addr_ref_cnt = (addr == watch_hi_addr);
176 if (matchCurr == NULL)
178 if (curr->lo_addr == addr && curr->hi_addr == hi_addr)
182 prev->next = curr->next;
184 watch_base = curr->next;
190 if (watch_lo_addr == curr->lo_addr)
192 if (curr->lo_addr > watch_lo_addr &&
193 curr->lo_addr < watch_second_lo_addr)
194 watch_second_lo_addr = curr->lo_addr;
198 if (watch_hi_addr == curr->hi_addr)
200 if (curr->hi_addr < watch_hi_addr &&
201 curr->hi_addr > watch_second_hi_addr)
202 watch_second_hi_addr = curr->hi_addr;
212 if (lo_addr_ref_cnt == 2)
213 watch_lo_addr = watch_second_lo_addr;
214 if (hi_addr_ref_cnt == 2)
215 watch_hi_addr = watch_second_hi_addr;
219 watch_lo_addr = watch_hi_addr = 0;
221 s390_fix_watch_points (pid);
226 fprintf_unfiltered (gdb_stderr,
227 "Attempt to remove nonexistent watchpoint in s390_remove_watchpoint\n");
235 return sizeof (struct user);
239 #if (defined (S390_FP0_REGNUM) && defined (HAVE_FPREGSET_T) && defined(HAVE_SYS_PROCFS_H) && defined (HAVE_GREGSET_T))
241 supply_gregset (gregset_t * gregsetp)
244 greg_t *gregp = (greg_t *) gregsetp;
246 supply_register (S390_PSWM_REGNUM, (char *) &gregp[S390_PSWM_REGNUM]);
247 supply_register (S390_PC_REGNUM, (char *) &gregp[S390_PC_REGNUM]);
248 for (regi = 0; regi < S390_NUM_GPRS; regi++)
249 supply_register (S390_GP0_REGNUM + regi,
250 (char *) &gregp[S390_GP0_REGNUM + regi]);
251 for (regi = 0; regi < S390_NUM_ACRS; regi++)
252 supply_register (S390_FIRST_ACR + regi,
253 (char *) &gregp[S390_FIRST_ACR + regi]);
254 /* unfortunately this isn't in gregsetp */
255 for (regi = 0; regi < S390_NUM_CRS; regi++)
256 supply_register (S390_FIRST_CR + regi, NULL);
261 supply_fpregset (fpregset_t * fpregsetp)
265 supply_register (S390_FPC_REGNUM, (char *) &fpregsetp->fpc);
266 for (regi = 0; regi < S390_NUM_FPRS; regi++)
267 supply_register (S390_FP0_REGNUM + regi, (char *) &fpregsetp->fprs[regi]);
272 fill_gregset (gregset_t * gregsetp, int regno)
274 greg_t *gregp = (greg_t *) gregsetp;
276 if (regno >= S390_FIRST_CR && regno <= S390_LAST_CR)
277 supply_register (regno, NULL);
278 else if (regno != -1)
279 supply_register (regno, (char *) &gregp[regno]);
281 supply_gregset (gregsetp);
284 /* Given a pointer to a floating point register set in /proc format
285 (fpregset_t *), update the register specified by REGNO from gdb's idea
286 of the current floating point register set. If REGNO is -1, update
290 fill_fpregset (fpregset_t * fpregsetp, int regno)
293 supply_fpregset (fpregsetp);
295 supply_register (regno,
296 &((char *) fpregsetp)[REGISTER_BYTE (regno) -
297 REGISTER_BYTE (S390_FPC_REGNUM)]);
302 #error "There are a few possibilities here"
303 #error "1) You aren't compiling for linux & don't need a core dumps to work."
304 #error "2) The header files sys/elf.h sys/user.h sys/ptrace.h & sys/procfs.h"
305 #error "libc files are inconsistent with linux/include/asm-s390/"
306 #error "3) you didn't do a completely clean build & delete config.cache."
308 #endif /* GDBSERVER */