/* S390 native-dependent code for GDB, the GNU debugger.
- Copyright (C) 2001-2015 Free Software Foundation, Inc.
+ Copyright (C) 2001-2016 Free Software Foundation, Inc.
Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
for IBM Deutschland Entwicklung GmbH, IBM Corporation.
#include "auxv.h"
#include "gregset.h"
#include "regset.h"
+#include "nat/linux-ptrace.h"
#include "s390-linux-tdep.h"
#include "elf/common.h"
#include <asm/ptrace.h>
-#include <sys/ptrace.h>
+#include "nat/gdb_ptrace.h"
#include <asm/types.h>
#include <sys/procfs.h>
#include <sys/ucontext.h>
#include <elf.h>
-#ifndef PTRACE_GETREGSET
-#define PTRACE_GETREGSET 0x4204
-#endif
+/* Per-thread arch-specific data. */
-#ifndef PTRACE_SETREGSET
-#define PTRACE_SETREGSET 0x4205
-#endif
+struct arch_lwp_info
+{
+ /* Non-zero if the thread's PER info must be re-written. */
+ int per_info_changed;
+};
static int have_regset_last_break = 0;
static int have_regset_system_call = 0;
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
ULONGEST pswa, pswm;
gdb_byte buf[4];
+ gdb_byte *pswm_p = (gdb_byte *) regp + S390_PSWM_OFFSET;
+ gdb_byte *pswa_p = (gdb_byte *) regp + S390_PSWA_OFFSET;
- regcache_raw_collect (regcache, S390_PSWM_REGNUM, buf);
- pswm = extract_unsigned_integer (buf, 4, byte_order);
- regcache_raw_collect (regcache, S390_PSWA_REGNUM, buf);
- pswa = extract_unsigned_integer (buf, 4, byte_order);
+ pswm = extract_unsigned_integer (pswm_p, 8, byte_order);
if (regno == -1 || regno == S390_PSWM_REGNUM)
- store_unsigned_integer ((gdb_byte *) regp + S390_PSWM_OFFSET, 8,
- byte_order, ((pswm & 0xfff7ffff) << 32) |
- (pswa & 0x80000000));
+ {
+ pswm &= 0x80000000;
+ regcache_raw_collect (regcache, S390_PSWM_REGNUM, buf);
+ pswm |= (extract_unsigned_integer (buf, 4, byte_order)
+ & 0xfff7ffff) << 32;
+ }
+
if (regno == -1 || regno == S390_PSWA_REGNUM)
- store_unsigned_integer ((gdb_byte *) regp + S390_PSWA_OFFSET, 8,
- byte_order, pswa & 0x7fffffff);
+ {
+ regcache_raw_collect (regcache, S390_PSWA_REGNUM, buf);
+ pswa = extract_unsigned_integer (buf, 4, byte_order);
+ pswm ^= (pswm ^ pswa) & 0x80000000;
+ pswa &= 0x7fffffff;
+ store_unsigned_integer (pswa_p, 8, byte_order, pswa);
+ }
+
+ store_unsigned_integer (pswm_p, 8, byte_order, pswm);
}
return;
}
parea.len = sizeof (regs);
parea.process_addr = (addr_t) ®s;
parea.kernel_addr = offsetof (struct user_regs_struct, psw);
- if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
+ if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea, 0) < 0)
perror_with_name (_("Couldn't get registers"));
supply_gregset (regcache, (const gregset_t *) ®s);
parea.len = sizeof (regs);
parea.process_addr = (addr_t) ®s;
parea.kernel_addr = offsetof (struct user_regs_struct, psw);
- if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
+ if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea, 0) < 0)
perror_with_name (_("Couldn't get registers"));
fill_gregset (regcache, ®s, regnum);
- if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
+ if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea, 0) < 0)
perror_with_name (_("Couldn't write registers"));
}
parea.len = sizeof (fpregs);
parea.process_addr = (addr_t) &fpregs;
parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
- if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
+ if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea, 0) < 0)
perror_with_name (_("Couldn't get floating point status"));
supply_fpregset (regcache, (const fpregset_t *) &fpregs);
parea.len = sizeof (fpregs);
parea.process_addr = (addr_t) &fpregs;
parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
- if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
+ if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea, 0) < 0)
perror_with_name (_("Couldn't get floating point status"));
fill_fpregset (regcache, &fpregs, regnum);
- if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
+ if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea, 0) < 0)
perror_with_name (_("Couldn't write floating point status"));
}
fetch_regset (struct regcache *regcache, int tid,
int regset_id, int regsize, const struct regset *regset)
{
- gdb_byte *buf = alloca (regsize);
+ void *buf = alloca (regsize);
struct iovec iov;
iov.iov_base = buf;
store_regset (struct regcache *regcache, int tid,
int regset_id, int regsize, const struct regset *regset)
{
- gdb_byte *buf = alloca (regsize);
+ void *buf = alloca (regsize);
struct iovec iov;
iov.iov_base = buf;
static int
check_regset (int tid, int regset, int regsize)
{
- gdb_byte *buf = alloca (regsize);
+ void *buf = alloca (regsize);
struct iovec iov;
iov.iov_base = buf;
parea.len = sizeof (per_lowcore);
parea.process_addr = (addr_t) & per_lowcore;
parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
- if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
+ if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea, 0) < 0)
perror_with_name (_("Couldn't retrieve watchpoint status"));
result = (per_lowcore.perc_storage_alteration == 1
{
/* Do not report this watchpoint again. */
memset (&per_lowcore, 0, sizeof (per_lowcore));
- if (ptrace (PTRACE_POKEUSR_AREA, s390_inferior_tid (), &parea) < 0)
+ if (ptrace (PTRACE_POKEUSR_AREA, s390_inferior_tid (), &parea, 0) < 0)
perror_with_name (_("Couldn't clear watchpoint status"));
}
return result;
}
+/* Each time before resuming a thread, update its PER info. */
+
static void
-s390_fix_watch_points (struct lwp_info *lp)
+s390_prepare_to_resume (struct lwp_info *lp)
{
int tid;
CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0;
struct watch_area *area;
+ if (lp->arch_private == NULL
+ || !lp->arch_private->per_info_changed)
+ return;
+
+ lp->arch_private->per_info_changed = 0;
+
tid = ptid_get_lwp (lp->ptid);
if (tid == 0)
tid = ptid_get_pid (lp->ptid);
parea.len = sizeof (per_info);
parea.process_addr = (addr_t) & per_info;
parea.kernel_addr = offsetof (struct user_regs_struct, per_info);
- if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0)
+ if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea, 0) < 0)
perror_with_name (_("Couldn't retrieve watchpoint status"));
if (watch_base)
per_info.starting_addr = watch_lo_addr;
per_info.ending_addr = watch_hi_addr;
- if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0)
+ if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea, 0) < 0)
perror_with_name (_("Couldn't modify watchpoint status"));
}
+/* Make sure that LP is stopped and mark its PER info as changed, so
+ the next resume will update it. */
+
+static void
+s390_refresh_per_info (struct lwp_info *lp)
+{
+ if (lp->arch_private == NULL)
+ lp->arch_private = XCNEW (struct arch_lwp_info);
+
+ lp->arch_private->per_info_changed = 1;
+
+ if (!lp->stopped)
+ linux_stop_lwp (lp);
+}
+
+/* When attaching to a new thread, mark its PER info as changed. */
+
+static void
+s390_new_thread (struct lwp_info *lp)
+{
+ lp->arch_private = XCNEW (struct arch_lwp_info);
+ lp->arch_private->per_info_changed = 1;
+}
+
static int
s390_insert_watchpoint (struct target_ops *self,
- CORE_ADDR addr, int len, int type,
+ CORE_ADDR addr, int len, enum target_hw_bp_type type,
struct expression *cond)
{
struct lwp_info *lp;
- struct watch_area *area = xmalloc (sizeof (struct watch_area));
+ struct watch_area *area = XNEW (struct watch_area);
if (!area)
return -1;
watch_base = area;
ALL_LWPS (lp)
- s390_fix_watch_points (lp);
+ s390_refresh_per_info (lp);
return 0;
}
static int
s390_remove_watchpoint (struct target_ops *self,
- CORE_ADDR addr, int len, int type,
+ CORE_ADDR addr, int len, enum target_hw_bp_type type,
struct expression *cond)
{
struct lwp_info *lp;
xfree (area);
ALL_LWPS (lp)
- s390_fix_watch_points (lp);
+ s390_refresh_per_info (lp);
return 0;
}
static int
s390_can_use_hw_breakpoint (struct target_ops *self,
- int type, int cnt, int othertype)
+ enum bptype type, int cnt, int othertype)
{
return type == bp_hardware_watchpoint;
}
/* Register the target. */
linux_nat_add_target (t);
- linux_nat_set_new_thread (t, s390_fix_watch_points);
+ linux_nat_set_new_thread (t, s390_new_thread);
+ linux_nat_set_prepare_to_resume (t, s390_prepare_to_resume);
}