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
);
62 error ("s390_register_u_addr invalid regnum %s %d regnum=%d",
63 __FILE__
, (int) __LINE__
, regnum
);
65 internal_error (__FILE__
, __LINE__
,
66 "s390_register_u_addr invalid regnum regnum=%d",
71 return retval
+ blockend
;
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. */
81 typedef struct watch_area watch_area
;
89 static watch_area
*watch_base
= NULL
;
90 int watch_area_cnt
= 0;
91 static CORE_ADDR watch_lo_addr
= 0, watch_hi_addr
= 0;
96 s390_stopped_by_watchpoint (int pid
)
98 per_lowcore_bits per_lowcore
;
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));
111 s390_fix_watch_points (int pid
)
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 */
125 per_info
.control_regs
.bits
.em_storage_alteration
= 1;
126 per_info
.control_regs
.bits
.storage_alt_space_ctl
= 1;
130 per_info
.control_regs
.bits
.em_storage_alteration
= 0;
131 per_info
.control_regs
.bits
.storage_alt_space_ctl
= 0;
133 per_info
.starting_addr
= watch_lo_addr
;
134 per_info
.ending_addr
= watch_hi_addr
;
135 ptrace (PTRACE_POKEUSR_AREA
, pid
, &parea
);
139 s390_insert_watchpoint (int pid
, CORE_ADDR addr
, int len
, int rw
)
141 CORE_ADDR hi_addr
= addr
+ len
- 1;
142 watch_area
*newarea
= (watch_area
*) xmalloc (sizeof (watch_area
));
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)
155 watch_lo_addr
= newarea
->lo_addr
;
156 watch_hi_addr
= newarea
->hi_addr
;
159 s390_fix_watch_points (pid
);
161 return newarea
? 0 : -1;
166 s390_remove_watchpoint (int pid
, CORE_ADDR addr
, int len
)
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
);
177 if (matchCurr
== NULL
)
179 if (curr
->lo_addr
== addr
&& curr
->hi_addr
== hi_addr
)
183 prev
->next
= curr
->next
;
185 watch_base
= curr
->next
;
191 if (watch_lo_addr
== curr
->lo_addr
)
193 if (curr
->lo_addr
> watch_lo_addr
&&
194 curr
->lo_addr
< watch_second_lo_addr
)
195 watch_second_lo_addr
= curr
->lo_addr
;
199 if (watch_hi_addr
== curr
->hi_addr
)
201 if (curr
->hi_addr
< watch_hi_addr
&&
202 curr
->hi_addr
> watch_second_hi_addr
)
203 watch_second_hi_addr
= curr
->hi_addr
;
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
;
220 watch_lo_addr
= watch_hi_addr
= 0;
222 s390_fix_watch_points (pid
);
227 fprintf_unfiltered (gdb_stderr
,
228 "Attempt to remove nonexistent watchpoint in s390_remove_watchpoint\n");
236 return sizeof (struct user
);
240 #if (defined (S390_FP0_REGNUM) && defined (HAVE_FPREGSET_T) && defined(HAVE_SYS_PROCFS_H) && defined (HAVE_GREGSET_T))
242 supply_gregset (gregset_t
* gregsetp
)
245 greg_t
*gregp
= (greg_t
*) gregsetp
;
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
);
262 supply_fpregset (fpregset_t
* fpregsetp
)
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
]);
273 fill_gregset (gregset_t
* gregsetp
, int regno
)
275 greg_t
*gregp
= (greg_t
*) gregsetp
;
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
]);
282 supply_gregset (gregsetp
);
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
291 fill_fpregset (fpregset_t
* fpregsetp
, int regno
)
294 supply_fpregset (fpregsetp
);
296 supply_register (regno
,
297 &((char *) fpregsetp
)[REGISTER_BYTE (regno
) -
298 REGISTER_BYTE (S390_FPC_REGNUM
)]);
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."
309 #endif /* GDBSERVER */