/* S390 native-dependent code for GDB, the GNU debugger.
- Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc
+ Copyright (C) 2001, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc
Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
for IBM Deutschland Entwicklung GmbH, IBM Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
-#include "tm.h"
#include "regcache.h"
#include "inferior.h"
#include "target.h"
we have to fix up the 64-bit registers we get from the kernel
to make them look like 32-bit registers. */
#ifdef __s390x__
-#define SUBOFF(i) \
- ((TARGET_PTR_BIT == 32 \
+#define SUBOFF(gdbarch, i) \
+ ((gdbarch_ptr_bit (gdbarch) == 32 \
&& ((i) == S390_PSWA_REGNUM \
|| ((i) >= S390_R0_REGNUM && (i) <= S390_R15_REGNUM)))? 4 : 0)
#else
-#define SUBOFF(i) 0
+#define SUBOFF(gdbarch, i) 0
#endif
/* Fill GDB's register array with the general-purpose register values
in *REGP. */
void
-supply_gregset (gregset_t *regp)
+supply_gregset (struct regcache *regcache, const gregset_t *regp)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
int i;
for (i = 0; i < S390_NUM_REGS; i++)
if (regmap_gregset[i] != -1)
- regcache_raw_supply (current_regcache, i,
- (char *)regp + regmap_gregset[i] + SUBOFF (i));
+ regcache_raw_supply (regcache, i,
+ (const char *)regp + regmap_gregset[i]
+ + SUBOFF (gdbarch, i));
}
/* Fill register REGNO (if it is a general-purpose register) in
*REGP with the value in GDB's register array. If REGNO is -1,
do this for all registers. */
void
-fill_gregset (gregset_t *regp, int regno)
+fill_gregset (const struct regcache *regcache, gregset_t *regp, int regno)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
int i;
for (i = 0; i < S390_NUM_REGS; i++)
if (regmap_gregset[i] != -1)
if (regno == -1 || regno == i)
- regcache_raw_collect (current_regcache, i,
- (char *)regp + regmap_gregset[i] + SUBOFF (i));
+ regcache_raw_collect (regcache, i,
+ (char *)regp + regmap_gregset[i]
+ + SUBOFF (gdbarch, i));
}
/* Fill GDB's register array with the floating-point register values
in *REGP. */
void
-supply_fpregset (fpregset_t *regp)
+supply_fpregset (struct regcache *regcache, const fpregset_t *regp)
{
int i;
for (i = 0; i < S390_NUM_REGS; i++)
if (regmap_fpregset[i] != -1)
- regcache_raw_supply (current_regcache, i,
- ((char *)regp) + regmap_fpregset[i]);
+ regcache_raw_supply (regcache, i,
+ (const char *)regp + regmap_fpregset[i]);
}
/* Fill register REGNO (if it is a general-purpose register) in
*REGP with the value in GDB's register array. If REGNO is -1,
do this for all registers. */
void
-fill_fpregset (fpregset_t *regp, int regno)
+fill_fpregset (const struct regcache *regcache, fpregset_t *regp, int regno)
{
int i;
for (i = 0; i < S390_NUM_REGS; i++)
if (regmap_fpregset[i] != -1)
if (regno == -1 || regno == i)
- regcache_raw_collect (current_regcache, i,
- ((char *)regp) + regmap_fpregset[i]);
+ regcache_raw_collect (regcache, i,
+ (char *)regp + regmap_fpregset[i]);
}
/* Find the TID for the current inferior thread to use with ptrace. */
/* Fetch all general-purpose registers from process/thread TID and
store their values in GDB's register cache. */
static void
-fetch_regs (int tid)
+fetch_regs (struct regcache *regcache, int tid)
{
gregset_t regs;
ptrace_area parea;
if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
perror_with_name (_("Couldn't get registers"));
- supply_gregset (®s);
+ supply_gregset (regcache, (const gregset_t *) ®s);
}
/* Store all valid general-purpose registers in GDB's register cache
into the process/thread specified by TID. */
static void
-store_regs (int tid, int regnum)
+store_regs (const struct regcache *regcache, int tid, int regnum)
{
gregset_t regs;
ptrace_area parea;
if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
perror_with_name (_("Couldn't get registers"));
- fill_gregset (®s, regnum);
+ fill_gregset (regcache, ®s, regnum);
if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
perror_with_name (_("Couldn't write registers"));
/* Fetch all floating-point registers from process/thread TID and store
their values in GDB's register cache. */
static void
-fetch_fpregs (int tid)
+fetch_fpregs (struct regcache *regcache, int tid)
{
fpregset_t fpregs;
ptrace_area parea;
if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
perror_with_name (_("Couldn't get floating point status"));
- supply_fpregset (&fpregs);
+ supply_fpregset (regcache, (const fpregset_t *) &fpregs);
}
/* Store all valid floating-point registers in GDB's register cache
into the process/thread specified by TID. */
static void
-store_fpregs (int tid, int regnum)
+store_fpregs (const struct regcache *regcache, int tid, int regnum)
{
fpregset_t fpregs;
ptrace_area parea;
if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
perror_with_name (_("Couldn't get floating point status"));
- fill_fpregset (&fpregs, regnum);
+ fill_fpregset (regcache, &fpregs, regnum);
if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
perror_with_name (_("Couldn't write floating point status"));
/* Fetch register REGNUM from the child process. If REGNUM is -1, do
this for all registers. */
static void
-s390_linux_fetch_inferior_registers (int regnum)
+s390_linux_fetch_inferior_registers (struct target_ops *ops,
+ struct regcache *regcache, int regnum)
{
int tid = s390_inferior_tid ();
if (regnum == -1
|| (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
- fetch_regs (tid);
+ fetch_regs (regcache, tid);
if (regnum == -1
|| (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
- fetch_fpregs (tid);
+ fetch_fpregs (regcache, tid);
}
/* Store register REGNUM back into the child process. If REGNUM is
-1, do this for all registers. */
static void
-s390_linux_store_inferior_registers (int regnum)
+s390_linux_store_inferior_registers (struct target_ops *ops,
+ struct regcache *regcache, int regnum)
{
int tid = s390_inferior_tid ();
if (regnum == -1
|| (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
- store_regs (tid, regnum);
+ store_regs (regcache, tid, regnum);
if (regnum == -1
|| (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
- store_fpregs (tid, regnum);
+ store_fpregs (regcache, tid, regnum);
}
{
per_lowcore_bits per_lowcore;
ptrace_area parea;
+ int result;
/* Speed up common case. */
if (!watch_base)
if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
perror_with_name (_("Couldn't retrieve watchpoint status"));
- return per_lowcore.perc_storage_alteration == 1
- && per_lowcore.perc_store_real_address == 0;
+ result = (per_lowcore.perc_storage_alteration == 1
+ && per_lowcore.perc_store_real_address == 0);
+
+ if (result)
+ {
+ /* Do not report this watchpoint again. */
+ memset (&per_lowcore, 0, sizeof (per_lowcore));
+ if (ptrace (PTRACE_POKEUSR_AREA, s390_inferior_tid (), &parea) < 0)
+ perror_with_name (_("Couldn't clear watchpoint status"));
+ }
+
+ return result;
}
static void
-s390_fix_watch_points (void)
+s390_fix_watch_points (ptid_t ptid)
{
- int tid = s390_inferior_tid ();
+ int tid;
per_struct per_info;
ptrace_area parea;
CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0;
struct watch_area *area;
+ tid = TIDGET (ptid);
+ if (tid == 0)
+ tid = PIDGET (ptid);
+
for (area = watch_base; area; area = area->next)
{
watch_lo_addr = min (watch_lo_addr, area->lo_addr);
}
static int
-s390_insert_watchpoint (CORE_ADDR addr, int len)
+s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
{
+ struct lwp_info *lp;
+ ptid_t ptid;
struct watch_area *area = xmalloc (sizeof (struct watch_area));
+
if (!area)
return -1;
area->next = watch_base;
watch_base = area;
- s390_fix_watch_points ();
+ ALL_LWPS (lp, ptid)
+ s390_fix_watch_points (ptid);
return 0;
}
static int
-s390_remove_watchpoint (CORE_ADDR addr, int len)
+s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
{
+ struct lwp_info *lp;
+ ptid_t ptid;
struct watch_area *area, **parea;
for (parea = &watch_base; *parea; parea = &(*parea)->next)
*parea = area->next;
xfree (area);
- s390_fix_watch_points ();
+ ALL_LWPS (lp, ptid)
+ s390_fix_watch_points (ptid);
return 0;
}
t->to_remove_watchpoint = s390_remove_watchpoint;
/* Register the target. */
- add_target (t);
+ linux_nat_add_target (t);
+ linux_nat_set_new_thread (t, s390_fix_watch_points);
}