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
25 #include <asm/ptrace.h>
26 #include <sys/ptrace.h>
27 #include <asm/processor.h>
28 #include <sys/procfs.h>
31 #include <sys/ucontext.h>
33 #define offsetof(type,member) ((size_t) &((type *)0)->member)
38 s390_register_u_addr (int blockend, int regnum)
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)
48 else if (regnum >= S390_FP0_REGNUM && regnum <= S390_FPLAST_REGNUM)
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);
63 error ("s390_register_u_addr invalid regnum %s %d regnum=%d",
64 __FILE__, (int) __LINE__, regnum);
66 internal_error (__FILE__, __LINE__,
67 "s390_register_u_addr invalid regnum regnum=%d",
72 return retval + blockend;
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. */
82 typedef struct watch_area watch_area;
90 static watch_area *watch_base = NULL;
91 int watch_area_cnt = 0;
92 static CORE_ADDR watch_lo_addr = 0, watch_hi_addr = 0;
97 s390_stopped_by_watchpoint (int pid)
99 per_lowcore_bits per_lowcore;
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));
112 s390_fix_watch_points (int pid)
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 */
126 per_info.control_regs.bits.em_storage_alteration = 1;
127 per_info.control_regs.bits.storage_alt_space_ctl = 1;
131 per_info.control_regs.bits.em_storage_alteration = 0;
132 per_info.control_regs.bits.storage_alt_space_ctl = 0;
134 per_info.starting_addr = watch_lo_addr;
135 per_info.ending_addr = watch_hi_addr;
136 ptrace (PTRACE_POKEUSR_AREA, pid, &parea);
140 s390_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
142 CORE_ADDR hi_addr = addr + len - 1;
143 watch_area *newarea = (watch_area *) xmalloc (sizeof (watch_area));
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)
156 watch_lo_addr = newarea->lo_addr;
157 watch_hi_addr = newarea->hi_addr;
160 s390_fix_watch_points (pid);
162 return newarea ? 0 : -1;
167 s390_remove_watchpoint (int pid, CORE_ADDR addr, int len)
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);
178 if (matchCurr == NULL)
180 if (curr->lo_addr == addr && curr->hi_addr == hi_addr)
184 prev->next = curr->next;
186 watch_base = curr->next;
192 if (watch_lo_addr == curr->lo_addr)
194 if (curr->lo_addr > watch_lo_addr &&
195 curr->lo_addr < watch_second_lo_addr)
196 watch_second_lo_addr = curr->lo_addr;
200 if (watch_hi_addr == curr->hi_addr)
202 if (curr->hi_addr < watch_hi_addr &&
203 curr->hi_addr > watch_second_hi_addr)
204 watch_second_hi_addr = curr->hi_addr;
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;
221 watch_lo_addr = watch_hi_addr = 0;
223 s390_fix_watch_points (pid);
228 fprintf_unfiltered (gdb_stderr,
229 "Attempt to remove nonexistent watchpoint in s390_remove_watchpoint\n");
237 return sizeof (struct user);
241 #if (defined (S390_FP0_REGNUM) && defined (HAVE_FPREGSET_T) && defined(HAVE_SYS_PROCFS_H) && defined (HAVE_GREGSET_T))
243 supply_gregset (gregset_t * gregsetp)
246 greg_t *gregp = (greg_t *) gregsetp;
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);
263 supply_fpregset (fpregset_t * fpregsetp)
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]);
274 fill_gregset (gregset_t * gregsetp, int regno)
276 greg_t *gregp = (greg_t *) gregsetp;
278 if (regno >= S390_FIRST_CR && regno <= S390_LAST_CR)
279 supply_register (regno, NULL);
280 else if (regno != -1)
281 supply_register (regno, (char *) &gregp[regno]);
283 supply_gregset (gregsetp);
286 /* Given a pointer to a floating point register set in /proc format
287 (fpregset_t *), update the register specified by REGNO from gdb's idea
288 of the current floating point register set. If REGNO is -1, update
292 fill_fpregset (fpregset_t * fpregsetp, int regno)
295 supply_fpregset (fpregsetp);
297 supply_register (regno,
298 &((char *) fpregsetp)[REGISTER_BYTE (regno) -
299 REGISTER_BYTE (S390_FPC_REGNUM)]);
304 #error "There are a few possibilities here"
305 #error "1) You aren't compiling for linux & don't need a core dumps to work."
306 #error "2) The header files sys/elf.h sys/user.h sys/ptrace.h & sys/procfs.h"
307 #error "libc files are inconsistent with linux/include/asm-s390/"
308 #error "3) you didn't do a completely clean build & delete config.cache."
310 #endif /* GDBSERVER */