1 /* S390 native-dependent code for GDB, the GNU debugger.
2 Copyright (C) 2001, 2003, 2004, 2005, 2006
3 Free Software Foundation, Inc
5 Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
6 for IBM Deutschland Entwicklung GmbH, IBM Corporation.
8 This file is part of GDB.
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>. */
27 #include "linux-nat.h"
29 #include "s390-tdep.h"
31 #include <asm/ptrace.h>
32 #include <sys/ptrace.h>
33 #include <asm/types.h>
34 #include <sys/procfs.h>
35 #include <sys/ucontext.h>
38 /* Map registers to gregset/ptrace offsets.
39 These arrays are defined in s390-tdep.c. */
42 #define regmap_gregset s390x_regmap_gregset
44 #define regmap_gregset s390_regmap_gregset
47 #define regmap_fpregset s390_regmap_fpregset
49 /* When debugging a 32-bit executable running under a 64-bit kernel,
50 we have to fix up the 64-bit registers we get from the kernel
51 to make them look like 32-bit registers. */
54 ((gdbarch_ptr_bit (current_gdbarch) == 32 \
55 && ((i) == S390_PSWA_REGNUM \
56 || ((i) >= S390_R0_REGNUM && (i) <= S390_R15_REGNUM)))? 4 : 0)
62 /* Fill GDB's register array with the general-purpose register values
65 supply_gregset (struct regcache
*regcache
, const gregset_t
*regp
)
68 for (i
= 0; i
< S390_NUM_REGS
; i
++)
69 if (regmap_gregset
[i
] != -1)
70 regcache_raw_supply (regcache
, i
,
71 (const char *)regp
+ regmap_gregset
[i
] + SUBOFF (i
));
74 /* Fill register REGNO (if it is a general-purpose register) in
75 *REGP with the value in GDB's register array. If REGNO is -1,
76 do this for all registers. */
78 fill_gregset (const struct regcache
*regcache
, gregset_t
*regp
, int regno
)
81 for (i
= 0; i
< S390_NUM_REGS
; i
++)
82 if (regmap_gregset
[i
] != -1)
83 if (regno
== -1 || regno
== i
)
84 regcache_raw_collect (regcache
, i
,
85 (char *)regp
+ regmap_gregset
[i
] + SUBOFF (i
));
88 /* Fill GDB's register array with the floating-point register values
91 supply_fpregset (struct regcache
*regcache
, const fpregset_t
*regp
)
94 for (i
= 0; i
< S390_NUM_REGS
; i
++)
95 if (regmap_fpregset
[i
] != -1)
96 regcache_raw_supply (regcache
, i
,
97 (const char *)regp
+ regmap_fpregset
[i
]);
100 /* Fill register REGNO (if it is a general-purpose register) in
101 *REGP with the value in GDB's register array. If REGNO is -1,
102 do this for all registers. */
104 fill_fpregset (const struct regcache
*regcache
, fpregset_t
*regp
, int regno
)
107 for (i
= 0; i
< S390_NUM_REGS
; i
++)
108 if (regmap_fpregset
[i
] != -1)
109 if (regno
== -1 || regno
== i
)
110 regcache_raw_collect (regcache
, i
,
111 (char *)regp
+ regmap_fpregset
[i
]);
114 /* Find the TID for the current inferior thread to use with ptrace. */
116 s390_inferior_tid (void)
118 /* GNU/Linux LWP ID's are process ID's. */
119 int tid
= TIDGET (inferior_ptid
);
121 tid
= PIDGET (inferior_ptid
); /* Not a threaded program. */
126 /* Fetch all general-purpose registers from process/thread TID and
127 store their values in GDB's register cache. */
129 fetch_regs (struct regcache
*regcache
, int tid
)
134 parea
.len
= sizeof (regs
);
135 parea
.process_addr
= (addr_t
) ®s
;
136 parea
.kernel_addr
= offsetof (struct user_regs_struct
, psw
);
137 if (ptrace (PTRACE_PEEKUSR_AREA
, tid
, (long) &parea
) < 0)
138 perror_with_name (_("Couldn't get registers"));
140 supply_gregset (regcache
, (const gregset_t
*) ®s
);
143 /* Store all valid general-purpose registers in GDB's register cache
144 into the process/thread specified by TID. */
146 store_regs (const struct regcache
*regcache
, int tid
, int regnum
)
151 parea
.len
= sizeof (regs
);
152 parea
.process_addr
= (addr_t
) ®s
;
153 parea
.kernel_addr
= offsetof (struct user_regs_struct
, psw
);
154 if (ptrace (PTRACE_PEEKUSR_AREA
, tid
, (long) &parea
) < 0)
155 perror_with_name (_("Couldn't get registers"));
157 fill_gregset (regcache
, ®s
, regnum
);
159 if (ptrace (PTRACE_POKEUSR_AREA
, tid
, (long) &parea
) < 0)
160 perror_with_name (_("Couldn't write registers"));
163 /* Fetch all floating-point registers from process/thread TID and store
164 their values in GDB's register cache. */
166 fetch_fpregs (struct regcache
*regcache
, int tid
)
171 parea
.len
= sizeof (fpregs
);
172 parea
.process_addr
= (addr_t
) &fpregs
;
173 parea
.kernel_addr
= offsetof (struct user_regs_struct
, fp_regs
);
174 if (ptrace (PTRACE_PEEKUSR_AREA
, tid
, (long) &parea
) < 0)
175 perror_with_name (_("Couldn't get floating point status"));
177 supply_fpregset (regcache
, (const fpregset_t
*) &fpregs
);
180 /* Store all valid floating-point registers in GDB's register cache
181 into the process/thread specified by TID. */
183 store_fpregs (const struct regcache
*regcache
, int tid
, int regnum
)
188 parea
.len
= sizeof (fpregs
);
189 parea
.process_addr
= (addr_t
) &fpregs
;
190 parea
.kernel_addr
= offsetof (struct user_regs_struct
, fp_regs
);
191 if (ptrace (PTRACE_PEEKUSR_AREA
, tid
, (long) &parea
) < 0)
192 perror_with_name (_("Couldn't get floating point status"));
194 fill_fpregset (regcache
, &fpregs
, regnum
);
196 if (ptrace (PTRACE_POKEUSR_AREA
, tid
, (long) &parea
) < 0)
197 perror_with_name (_("Couldn't write floating point status"));
200 /* Fetch register REGNUM from the child process. If REGNUM is -1, do
201 this for all registers. */
203 s390_linux_fetch_inferior_registers (struct regcache
*regcache
, int regnum
)
205 int tid
= s390_inferior_tid ();
208 || (regnum
< S390_NUM_REGS
&& regmap_gregset
[regnum
] != -1))
209 fetch_regs (regcache
, tid
);
212 || (regnum
< S390_NUM_REGS
&& regmap_fpregset
[regnum
] != -1))
213 fetch_fpregs (regcache
, tid
);
216 /* Store register REGNUM back into the child process. If REGNUM is
217 -1, do this for all registers. */
219 s390_linux_store_inferior_registers (struct regcache
*regcache
, int regnum
)
221 int tid
= s390_inferior_tid ();
224 || (regnum
< S390_NUM_REGS
&& regmap_gregset
[regnum
] != -1))
225 store_regs (regcache
, tid
, regnum
);
228 || (regnum
< S390_NUM_REGS
&& regmap_fpregset
[regnum
] != -1))
229 store_fpregs (regcache
, tid
, regnum
);
233 /* Hardware-assisted watchpoint handling. */
235 /* We maintain a list of all currently active watchpoints in order
236 to properly handle watchpoint removal.
238 The only thing we actually need is the total address space area
239 spanned by the watchpoints. */
243 struct watch_area
*next
;
248 static struct watch_area
*watch_base
= NULL
;
251 s390_stopped_by_watchpoint (void)
253 per_lowcore_bits per_lowcore
;
257 /* Speed up common case. */
261 parea
.len
= sizeof (per_lowcore
);
262 parea
.process_addr
= (addr_t
) & per_lowcore
;
263 parea
.kernel_addr
= offsetof (struct user_regs_struct
, per_info
.lowcore
);
264 if (ptrace (PTRACE_PEEKUSR_AREA
, s390_inferior_tid (), &parea
) < 0)
265 perror_with_name (_("Couldn't retrieve watchpoint status"));
267 result
= (per_lowcore
.perc_storage_alteration
== 1
268 && per_lowcore
.perc_store_real_address
== 0);
272 /* Do not report this watchpoint again. */
273 memset (&per_lowcore
, 0, sizeof (per_lowcore
));
274 if (ptrace (PTRACE_POKEUSR_AREA
, s390_inferior_tid (), &parea
) < 0)
275 perror_with_name (_("Couldn't clear watchpoint status"));
282 s390_fix_watch_points (ptid_t ptid
)
289 CORE_ADDR watch_lo_addr
= (CORE_ADDR
)-1, watch_hi_addr
= 0;
290 struct watch_area
*area
;
296 for (area
= watch_base
; area
; area
= area
->next
)
298 watch_lo_addr
= min (watch_lo_addr
, area
->lo_addr
);
299 watch_hi_addr
= max (watch_hi_addr
, area
->hi_addr
);
302 parea
.len
= sizeof (per_info
);
303 parea
.process_addr
= (addr_t
) & per_info
;
304 parea
.kernel_addr
= offsetof (struct user_regs_struct
, per_info
);
305 if (ptrace (PTRACE_PEEKUSR_AREA
, tid
, &parea
) < 0)
306 perror_with_name (_("Couldn't retrieve watchpoint status"));
310 per_info
.control_regs
.bits
.em_storage_alteration
= 1;
311 per_info
.control_regs
.bits
.storage_alt_space_ctl
= 1;
315 per_info
.control_regs
.bits
.em_storage_alteration
= 0;
316 per_info
.control_regs
.bits
.storage_alt_space_ctl
= 0;
318 per_info
.starting_addr
= watch_lo_addr
;
319 per_info
.ending_addr
= watch_hi_addr
;
321 if (ptrace (PTRACE_POKEUSR_AREA
, tid
, &parea
) < 0)
322 perror_with_name (_("Couldn't modify watchpoint status"));
326 s390_insert_watchpoint (CORE_ADDR addr
, int len
, int type
)
330 struct watch_area
*area
= xmalloc (sizeof (struct watch_area
));
335 area
->lo_addr
= addr
;
336 area
->hi_addr
= addr
+ len
- 1;
338 area
->next
= watch_base
;
342 s390_fix_watch_points (ptid
);
347 s390_remove_watchpoint (CORE_ADDR addr
, int len
, int type
)
351 struct watch_area
*area
, **parea
;
353 for (parea
= &watch_base
; *parea
; parea
= &(*parea
)->next
)
354 if ((*parea
)->lo_addr
== addr
355 && (*parea
)->hi_addr
== addr
+ len
- 1)
360 fprintf_unfiltered (gdb_stderr
,
361 "Attempt to remove nonexistent watchpoint.\n");
370 s390_fix_watch_points (ptid
);
375 s390_can_use_hw_breakpoint (int type
, int cnt
, int othertype
)
381 s390_region_ok_for_hw_watchpoint (CORE_ADDR addr
, int cnt
)
387 void _initialize_s390_nat (void);
390 _initialize_s390_nat (void)
392 struct target_ops
*t
;
394 /* Fill in the generic GNU/Linux methods. */
397 /* Add our register access methods. */
398 t
->to_fetch_registers
= s390_linux_fetch_inferior_registers
;
399 t
->to_store_registers
= s390_linux_store_inferior_registers
;
401 /* Add our watchpoint methods. */
402 t
->to_can_use_hw_breakpoint
= s390_can_use_hw_breakpoint
;
403 t
->to_region_ok_for_hw_watchpoint
= s390_region_ok_for_hw_watchpoint
;
404 t
->to_have_continuable_watchpoint
= 1;
405 t
->to_stopped_by_watchpoint
= s390_stopped_by_watchpoint
;
406 t
->to_insert_watchpoint
= s390_insert_watchpoint
;
407 t
->to_remove_watchpoint
= s390_remove_watchpoint
;
409 /* Register the target. */
410 linux_nat_add_target (t
);
411 linux_nat_set_new_thread (t
, s390_fix_watch_points
);