S/390: Disassemble 31-bit binaries with "zarch" opcode set by default
[deliverable/binutils-gdb.git] / gdb / s390-nat.c
index 732cf94451a33a002be6b9eb190bba8f5b72c048..19bc607a83dda6d655ffb48121234b0d04b2a241 100644 (file)
@@ -1,12 +1,14 @@
 /* S390 native-dependent code for GDB, the GNU debugger.
-   Copyright 2001 Free Software Foundation, Inc
+   Copyright (C) 2001-2013 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 file is part of GDB.
 
    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., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, 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"
+#include "linux-nat.h"
+#include "auxv.h"
+#include "gregset.h"
+
+#include "s390-tdep.h"
+#include "elf/common.h"
+
 #include <asm/ptrace.h>
 #include <sys/ptrace.h>
-#include <asm/processor.h>
 #include <asm/types.h>
 #include <sys/procfs.h>
-#include <sys/user.h>
-#include <value.h>
 #include <sys/ucontext.h>
-#ifndef offsetof
-#define offsetof(type,member) ((size_t) &((type *)0)->member)
+#include <elf.h>
+
+#ifndef PTRACE_GETREGSET
+#define PTRACE_GETREGSET 0x4204
 #endif
 
+#ifndef PTRACE_SETREGSET
+#define PTRACE_SETREGSET 0x4205
+#endif
 
-int
-s390_register_u_addr (int blockend, int regnum)
-{
-  int retval;
-
-  if (regnum >= S390_GP0_REGNUM && regnum <= S390_GP_LAST_REGNUM)
-    retval = PT_GPR0 + ((regnum - S390_GP0_REGNUM) * S390_GPR_SIZE);
-  else if (regnum >= S390_PSWM_REGNUM && regnum <= S390_PC_REGNUM)
-    retval = PT_PSWMASK + ((regnum - S390_PSWM_REGNUM) * S390_PSW_MASK_SIZE);
-  else if (regnum == S390_FPC_REGNUM)
-    retval = PT_FPC;
-  else if (regnum >= S390_FP0_REGNUM && regnum <= S390_FPLAST_REGNUM)
-    retval =
-#if CONFIG_ARCH_S390X
-      PT_FPR0
+static int have_regset_last_break = 0;
+static int have_regset_system_call = 0;
+static int have_regset_tdb = 0;
+
+/* Map registers to gregset/ptrace offsets.
+   These arrays are defined in s390-tdep.c.  */
+
+#ifdef __s390x__
+#define regmap_gregset s390x_regmap_gregset
 #else
-      PT_FPR0_HI
+#define regmap_gregset s390_regmap_gregset
 #endif
-      + ((regnum - S390_FP0_REGNUM) * S390_FPR_SIZE);
-  else if (regnum >= S390_FIRST_ACR && regnum <= S390_LAST_ACR)
-    retval = PT_ACR0 + ((regnum - S390_FIRST_ACR) * S390_ACR_SIZE);
-  else if (regnum >= (S390_FIRST_CR + 9) && regnum <= (S390_FIRST_CR + 11))
-    retval = PT_CR_9 + ((regnum - (S390_FIRST_CR + 9)) * S390_CR_SIZE);
-  else
+
+#define regmap_fpregset s390_regmap_fpregset
+
+/* Fill the regset described by MAP into REGCACHE, using the values
+   from REGP.  The MAP array represents each register as a pair
+   (offset, regno) of short integers and is terminated with -1. */
+
+static void
+s390_native_supply (struct regcache *regcache, const short *map,
+                   const gdb_byte *regp)
+{
+  for (; map[0] >= 0; map += 2)
+    regcache_raw_supply (regcache, map[1], regp ? regp + map[0] : NULL);
+}
+
+/* Collect the register REGNO out of the regset described by MAP from
+   REGCACHE into REGP.  If REGNO == -1, do this for all registers in
+   this regset. */
+
+static void
+s390_native_collect (const struct regcache *regcache, const short *map,
+                    int regno, gdb_byte *regp)
+{
+  for (; map[0] >= 0; map += 2)
+    if (regno == -1 || regno == map[1])
+      regcache_raw_collect (regcache, map[1], regp + map[0]);
+}
+
+/* Fill GDB's register array with the general-purpose register values
+   in *REGP.
+
+   When debugging a 32-bit executable running under a 64-bit kernel,
+   we have to fix up the 64-bit registers we get from the kernel to
+   make them look like 32-bit registers.  */
+
+void
+supply_gregset (struct regcache *regcache, const gregset_t *regp)
+{
+#ifdef __s390x__
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  if (gdbarch_ptr_bit (gdbarch) == 32)
+    {
+      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+      ULONGEST pswm = 0, pswa = 0;
+      gdb_byte buf[4];
+      const short *map;
+
+      for (map = regmap_gregset; map[0] >= 0; map += 2)
+       {
+         const gdb_byte *p = (const gdb_byte *) regp + map[0];
+         int regno = map[1];
+
+         if (regno == S390_PSWM_REGNUM)
+           pswm = extract_unsigned_integer (p, 8, byte_order);
+         else if (regno == S390_PSWA_REGNUM)
+           pswa = extract_unsigned_integer (p, 8, byte_order);
+         else
+           {
+             if ((regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM)
+                 || regno == S390_ORIG_R2_REGNUM)
+               p += 4;
+             regcache_raw_supply (regcache, regno, p);
+           }
+       }
+
+      store_unsigned_integer (buf, 4, byte_order, (pswm >> 32) | 0x80000);
+      regcache_raw_supply (regcache, S390_PSWM_REGNUM, buf);
+      store_unsigned_integer (buf, 4, byte_order,
+                             (pswa & 0x7fffffff) | (pswm & 0x80000000));
+      regcache_raw_supply (regcache, S390_PSWA_REGNUM, buf);
+      return;
+    }
+#endif
+
+  s390_native_supply (regcache, regmap_gregset, (const gdb_byte *) regp);
+}
+
+/* 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 (const struct regcache *regcache, gregset_t *regp, int regno)
+{
+#ifdef __s390x__
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  if (gdbarch_ptr_bit (gdbarch) == 32)
+    {
+      gdb_byte *psw_p[2];
+      const short *map;
+
+      for (map = regmap_gregset; map[0] >= 0; map += 2)
+       {
+         gdb_byte *p = (gdb_byte *) regp + map[0];
+         int reg = map[1];
+
+         if (reg >= S390_PSWM_REGNUM && reg <= S390_PSWA_REGNUM)
+           psw_p[reg - S390_PSWM_REGNUM] = p;
+
+         else if (regno == -1 || regno == reg)
+           {
+             if ((reg >= S390_R0_REGNUM && reg <= S390_R15_REGNUM)
+                 || reg == S390_ORIG_R2_REGNUM)
+               {
+                 memset (p, 0, 4);
+                 p += 4;
+               }
+             regcache_raw_collect (regcache, reg, p + 4);
+           }
+       }
+
+      if (regno == -1
+         || regno == S390_PSWM_REGNUM || regno == S390_PSWA_REGNUM)
+       {
+         enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+         ULONGEST pswa, pswm;
+         gdb_byte buf[4];
+
+         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);
+
+         if (regno == -1 || regno == S390_PSWM_REGNUM)
+           store_unsigned_integer (psw_p[0], 8, byte_order,
+                                   ((pswm & 0xfff7ffff) << 32) |
+                                   (pswa & 0x80000000));
+         if (regno == -1 || regno == S390_PSWA_REGNUM)
+           store_unsigned_integer (psw_p[1], 8, byte_order,
+                                   pswa & 0x7fffffff);
+       }
+      return;
+    }
+#endif
+
+  s390_native_collect (regcache, regmap_gregset, regno, (gdb_byte *) regp);
+}
+
+/* Fill GDB's register array with the floating-point register values
+   in *REGP.  */
+void
+supply_fpregset (struct regcache *regcache, const fpregset_t *regp)
+{
+  s390_native_supply (regcache, regmap_fpregset, (const gdb_byte *) regp);
+}
+
+/* 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 (const struct regcache *regcache, fpregset_t *regp, int regno)
+{
+  s390_native_collect (regcache, regmap_fpregset, regno, (gdb_byte *) regp);
+}
+
+/* Find the TID for the current inferior thread to use with ptrace.  */
+static int
+s390_inferior_tid (void)
+{
+  /* GNU/Linux LWP ID's are process ID's.  */
+  int tid = ptid_get_lwp (inferior_ptid);
+  if (tid == 0)
+    tid = ptid_get_pid (inferior_ptid); /* Not a threaded program.  */
+
+  return tid;
+}
+
+/* Fetch all general-purpose registers from process/thread TID and
+   store their values in GDB's register cache.  */
+static void
+fetch_regs (struct regcache *regcache, int tid)
+{
+  gregset_t regs;
+  ptrace_area parea;
+
+  parea.len = sizeof (regs);
+  parea.process_addr = (addr_t) &regs;
+  parea.kernel_addr = offsetof (struct user_regs_struct, psw);
+  if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
+    perror_with_name (_("Couldn't get registers"));
+
+  supply_gregset (regcache, (const gregset_t *) &regs);
+}
+
+/* Store all valid general-purpose registers in GDB's register cache
+   into the process/thread specified by TID.  */
+static void
+store_regs (const struct regcache *regcache, int tid, int regnum)
+{
+  gregset_t regs;
+  ptrace_area parea;
+
+  parea.len = sizeof (regs);
+  parea.process_addr = (addr_t) &regs;
+  parea.kernel_addr = offsetof (struct user_regs_struct, psw);
+  if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
+    perror_with_name (_("Couldn't get registers"));
+
+  fill_gregset (regcache, &regs, 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 (struct regcache *regcache, int tid)
+{
+  fpregset_t fpregs;
+  ptrace_area parea;
+
+  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)
+    perror_with_name (_("Couldn't get floating point status"));
+
+  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 (const struct regcache *regcache, int tid, int regnum)
+{
+  fpregset_t fpregs;
+  ptrace_area parea;
+
+  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)
+    perror_with_name (_("Couldn't get floating point status"));
+
+  fill_fpregset (regcache, &fpregs, regnum);
+
+  if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
+    perror_with_name (_("Couldn't write floating point status"));
+}
+
+/* Fetch all registers in the kernel's register set whose number is REGSET,
+   whose size is REGSIZE, and whose layout is described by REGMAP, from
+   process/thread TID and store their values in GDB's register cache.  */
+static void
+fetch_regset (struct regcache *regcache, int tid,
+             int regset, int regsize, const short *regmap)
+{
+  gdb_byte *buf = alloca (regsize);
+  struct iovec iov;
+
+  iov.iov_base = buf;
+  iov.iov_len = regsize;
+
+  if (ptrace (PTRACE_GETREGSET, tid, (long) regset, (long) &iov) < 0)
     {
-      internal_error (__FILE__, __LINE__,
-                      "s390_register_u_addr invalid regnum regnum=%d",
-                      regnum);
-      retval = 0;
+      if (errno == ENODATA)
+       s390_native_supply (regcache, regmap, NULL);
+      else
+       perror_with_name (_("Couldn't get register set"));
     }
-  return retval + blockend;
+  else
+    s390_native_supply (regcache, regmap, buf);
+}
+
+/* Store all registers in the kernel's register set whose number is REGSET,
+   whose size is REGSIZE, and whose layout is described by REGMAP, from
+   GDB's register cache back to process/thread TID.  */
+static void
+store_regset (struct regcache *regcache, int tid,
+             int regset, int regsize, const short *regmap)
+{
+  gdb_byte *buf = alloca (regsize);
+  struct iovec iov;
+
+  iov.iov_base = buf;
+  iov.iov_len = regsize;
+
+  if (ptrace (PTRACE_GETREGSET, tid, (long) regset, (long) &iov) < 0)
+    perror_with_name (_("Couldn't get register set"));
+
+  s390_native_collect (regcache, regmap, -1, buf);
+
+  if (ptrace (PTRACE_SETREGSET, tid, (long) regset, (long) &iov) < 0)
+    perror_with_name (_("Couldn't set register set"));
+}
+
+/* Check whether the kernel provides a register set with number REGSET
+   of size REGSIZE for process/thread TID.  */
+static int
+check_regset (int tid, int regset, int regsize)
+{
+  gdb_byte *buf = alloca (regsize);
+  struct iovec iov;
+
+  iov.iov_base = buf;
+  iov.iov_len = regsize;
+
+  if (ptrace (PTRACE_GETREGSET, tid, (long) regset, (long) &iov) >= 0
+      || errno == ENODATA)
+    return 1;
+  return 0;
+}
+
+/* Fetch register REGNUM from the child process.  If REGNUM is -1, do
+   this for all registers.  */
+static void
+s390_linux_fetch_inferior_registers (struct target_ops *ops,
+                                    struct regcache *regcache, int regnum)
+{
+  int tid = s390_inferior_tid ();
+
+  if (regnum == -1 || S390_IS_GREGSET_REGNUM (regnum))
+    fetch_regs (regcache, tid);
+
+  if (regnum == -1 || S390_IS_FPREGSET_REGNUM (regnum))
+    fetch_fpregs (regcache, tid);
+
+  if (have_regset_last_break)
+    if (regnum == -1 || regnum == S390_LAST_BREAK_REGNUM)
+      fetch_regset (regcache, tid, NT_S390_LAST_BREAK, 8,
+                   (gdbarch_ptr_bit (get_regcache_arch (regcache)) == 32
+                    ? s390_regmap_last_break : s390x_regmap_last_break));
+
+  if (have_regset_system_call)
+    if (regnum == -1 || regnum == S390_SYSTEM_CALL_REGNUM)
+      fetch_regset (regcache, tid, NT_S390_SYSTEM_CALL, 4,
+                   s390_regmap_system_call);
+
+  if (have_regset_tdb)
+    if (regnum == -1 || S390_IS_TDBREGSET_REGNUM (regnum))
+      fetch_regset (regcache, tid, NT_S390_TDB, s390_sizeof_tdbregset,
+                   s390_regmap_tdb);
 }
 
-/* watch_areas are required if you put 2 or more watchpoints on the same 
-   address or overlapping areas gdb will call us to delete the watchpoint 
-   more than once when we try to delete them.
-   attempted reference counting to reduce the number of areas unfortunately
-   they didn't shrink when areas had to be split overlapping occurs. */
-struct watch_area;
-typedef struct watch_area watch_area;
+/* Store register REGNUM back into the child process.  If REGNUM is
+   -1, do this for all registers.  */
+static void
+s390_linux_store_inferior_registers (struct target_ops *ops,
+                                    struct regcache *regcache, int regnum)
+{
+  int tid = s390_inferior_tid ();
+
+  if (regnum == -1 || S390_IS_GREGSET_REGNUM (regnum))
+    store_regs (regcache, tid, regnum);
+
+  if (regnum == -1 || S390_IS_FPREGSET_REGNUM (regnum))
+    store_fpregs (regcache, tid, regnum);
+
+  /* S390_LAST_BREAK_REGNUM is read-only.  */
+
+  if (have_regset_system_call)
+    if (regnum == -1 || regnum == S390_SYSTEM_CALL_REGNUM)
+      store_regset (regcache, tid, NT_S390_SYSTEM_CALL, 4,
+                   s390_regmap_system_call);
+}
+
+
+/* Hardware-assisted watchpoint handling.  */
+
+/* We maintain a list of all currently active watchpoints in order
+   to properly handle watchpoint removal.
+
+   The only thing we actually need is the total address space area
+   spanned by the watchpoints.  */
+
 struct watch_area
 {
-  watch_area *next;
+  struct watch_area *next;
   CORE_ADDR lo_addr;
   CORE_ADDR hi_addr;
 };
 
-static watch_area *watch_base = NULL;
-int watch_area_cnt = 0;
-static CORE_ADDR watch_lo_addr = 0, watch_hi_addr = 0;
-
+static struct watch_area *watch_base = NULL;
 
-
-CORE_ADDR
-s390_stopped_by_watchpoint (int pid)
+static int
+s390_stopped_by_watchpoint (void)
 {
   per_lowcore_bits per_lowcore;
   ptrace_area parea;
+  int result;
+
+  /* Speed up common case.  */
+  if (!watch_base)
+    return 0;
 
   parea.len = sizeof (per_lowcore);
   parea.process_addr = (addr_t) & per_lowcore;
   parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
-  ptrace (PTRACE_PEEKUSR_AREA, pid, &parea);
-  return ((per_lowcore.perc_storage_alteration == 1) &&
-         (per_lowcore.perc_store_real_address == 0));
-}
+  if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
+    perror_with_name (_("Couldn't retrieve watchpoint status"));
 
+  result = (per_lowcore.perc_storage_alteration == 1
+           && per_lowcore.perc_store_real_address == 0);
 
-void
-s390_fix_watch_points (int pid)
+  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 (struct lwp_info *lp)
 {
+  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 = ptid_get_lwp (lp->ptid);
+  if (tid == 0)
+    tid = ptid_get_pid (lp->ptid);
+
+  for (area = watch_base; area; area = area->next)
+    {
+      watch_lo_addr = min (watch_lo_addr, area->lo_addr);
+      watch_hi_addr = max (watch_hi_addr, area->hi_addr);
+    }
+
   parea.len = sizeof (per_info);
   parea.process_addr = (addr_t) & per_info;
-  parea.kernel_addr = PT_CR_9;
-  ptrace (PTRACE_PEEKUSR_AREA, pid, &parea);
-  /* The kernel automatically sets the psw for per depending */
-  /* on whether the per control registers are set for event recording */
-  /* & sets cr9 & cr10 appropriately also */
-  if (watch_area_cnt)
+  parea.kernel_addr = offsetof (struct user_regs_struct, per_info);
+  if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0)
+    perror_with_name (_("Couldn't retrieve watchpoint status"));
+
+  if (watch_base)
     {
       per_info.control_regs.bits.em_storage_alteration = 1;
       per_info.control_regs.bits.storage_alt_space_ctl = 1;
@@ -128,231 +502,194 @@ s390_fix_watch_points (int pid)
     }
   per_info.starting_addr = watch_lo_addr;
   per_info.ending_addr = watch_hi_addr;
-  ptrace (PTRACE_POKEUSR_AREA, pid, &parea);
+
+  if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0)
+    perror_with_name (_("Couldn't modify watchpoint status"));
 }
 
-int
-s390_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
+static int
+s390_insert_watchpoint (CORE_ADDR addr, int len, int type,
+                       struct expression *cond)
 {
-  CORE_ADDR hi_addr = addr + len - 1;
-  watch_area *newarea = (watch_area *) xmalloc (sizeof (watch_area));
+  struct lwp_info *lp;
+  struct watch_area *area = xmalloc (sizeof (struct watch_area));
 
+  if (!area)
+    return -1; 
 
-  if (newarea)
-    {
-      newarea->next = watch_base;
-      watch_base = newarea;
-      watch_lo_addr = min (watch_lo_addr, addr);
-      watch_hi_addr = max (watch_hi_addr, hi_addr);
-      newarea->lo_addr = addr;
-      newarea->hi_addr = hi_addr;
-      if (watch_area_cnt == 0)
-       {
-         watch_lo_addr = newarea->lo_addr;
-         watch_hi_addr = newarea->hi_addr;
-       }
-      watch_area_cnt++;
-      s390_fix_watch_points (pid);
-    }
-  return newarea ? 0 : -1;
-}
+  area->lo_addr = addr;
+  area->hi_addr = addr + len - 1;
+  area->next = watch_base;
+  watch_base = area;
 
+  ALL_LWPS (lp)
+    s390_fix_watch_points (lp);
+  return 0;
+}
 
-int
-s390_remove_watchpoint (int pid, CORE_ADDR addr, int len)
+static int
+s390_remove_watchpoint (CORE_ADDR addr, int len, int type,
+                       struct expression *cond)
 {
-  watch_area *curr = watch_base, *prev, *matchCurr;
-  CORE_ADDR hi_addr = addr + len - 1;
-  CORE_ADDR watch_second_lo_addr = 0xffffffffUL, watch_second_hi_addr = 0;
-  int lo_addr_ref_cnt, hi_addr_ref_cnt;
-  prev = matchCurr = NULL;
-  lo_addr_ref_cnt = (addr == watch_lo_addr);
-  hi_addr_ref_cnt = (addr == watch_hi_addr);
-  while (curr)
-    {
-      if (matchCurr == NULL)
-       {
-         if (curr->lo_addr == addr && curr->hi_addr == hi_addr)
-           {
-             matchCurr = curr;
-             if (prev)
-               prev->next = curr->next;
-             else
-               watch_base = curr->next;
-           }
-         prev = curr;
-       }
-      if (lo_addr_ref_cnt)
-       {
-         if (watch_lo_addr == curr->lo_addr)
-           lo_addr_ref_cnt++;
-         if (curr->lo_addr > watch_lo_addr &&
-             curr->lo_addr < watch_second_lo_addr)
-           watch_second_lo_addr = curr->lo_addr;
-       }
-      if (hi_addr_ref_cnt)
-       {
-         if (watch_hi_addr == curr->hi_addr)
-           hi_addr_ref_cnt++;
-         if (curr->hi_addr < watch_hi_addr &&
-             curr->hi_addr > watch_second_hi_addr)
-           watch_second_hi_addr = curr->hi_addr;
-       }
-      curr = curr->next;
-    }
-  if (matchCurr)
-    {
-      xfree (matchCurr);
-      watch_area_cnt--;
-      if (watch_area_cnt)
-       {
-         if (lo_addr_ref_cnt == 2)
-           watch_lo_addr = watch_second_lo_addr;
-         if (hi_addr_ref_cnt == 2)
-           watch_hi_addr = watch_second_hi_addr;
-       }
-      else
-       {
-         watch_lo_addr = watch_hi_addr = 0;
-       }
-      s390_fix_watch_points (pid);
-      return 0;
-    }
-  else
+  struct lwp_info *lp;
+  struct watch_area *area, **parea;
+
+  for (parea = &watch_base; *parea; parea = &(*parea)->next)
+    if ((*parea)->lo_addr == addr
+       && (*parea)->hi_addr == addr + len - 1)
+      break;
+
+  if (!*parea)
     {
       fprintf_unfiltered (gdb_stderr,
-                         "Attempt to remove nonexistent watchpoint in s390_remove_watchpoint\n");
+                         "Attempt to remove nonexistent watchpoint.\n");
       return -1;
     }
+
+  area = *parea;
+  *parea = area->next;
+  xfree (area);
+
+  ALL_LWPS (lp)
+    s390_fix_watch_points (lp);
+  return 0;
 }
 
-int
-kernel_u_size (void)
+static int
+s390_can_use_hw_breakpoint (int type, int cnt, int othertype)
 {
-  return sizeof (struct user);
+  return type == bp_hardware_watchpoint;
 }
 
+static int
+s390_region_ok_for_hw_watchpoint (CORE_ADDR addr, int cnt)
+{
+  return 1;
+}
 
-#if  (defined (S390_FP0_REGNUM) && defined (HAVE_FPREGSET_T) && defined(HAVE_SYS_PROCFS_H) && defined (HAVE_GREGSET_T))
-void
-supply_gregset (gregset_t * gregsetp)
+static int
+s390_target_wordsize (void)
 {
-  int regi;
-  greg_t *gregp = (greg_t *) gregsetp;
-
-  supply_register (S390_PSWM_REGNUM, (char *) &gregp[S390_PSWM_REGNUM]);
-  supply_register (S390_PC_REGNUM, (char *) &gregp[S390_PC_REGNUM]);
-  for (regi = 0; regi < S390_NUM_GPRS; regi++)
-    supply_register (S390_GP0_REGNUM + regi,
-                    (char *) &gregp[S390_GP0_REGNUM + regi]);
-
-#if defined (CONFIG_ARCH_S390X)
-  /* On the s390x, each element of gregset_t is 8 bytes long, but
-     each access register is still only 32 bits long.  So they're
-     packed two per element.  It's apparently traditional that
-     gregset_t must be an array, so when the registers it provides
-     have different sizes, something has to get strange
-     somewhere.  */
-  {
-    unsigned int *acrs = (unsigned int *) &gregp[S390_FIRST_ACR];
-
-    for (regi = 0; regi < S390_NUM_ACRS; regi++)
-      supply_register (S390_FIRST_ACR + regi, (char *) &acrs[regi]);
-  }
-#else
-  for (regi = 0; regi < S390_NUM_ACRS; regi++)
-    supply_register (S390_FIRST_ACR + regi,
-                     (char *) &gregp[S390_FIRST_ACR + regi]);
+  int wordsize = 4;
+
+  /* Check for 64-bit inferior process.  This is the case when the host is
+     64-bit, and in addition bit 32 of the PSW mask is set.  */
+#ifdef __s390x__
+  long pswm;
+
+  errno = 0;
+  pswm = (long) ptrace (PTRACE_PEEKUSER, s390_inferior_tid (), PT_PSWMASK, 0);
+  if (errno == 0 && (pswm & 0x100000000ul) != 0)
+    wordsize = 8;
 #endif
 
-  /* unfortunately this isn't in gregsetp */
-  for (regi = 0; regi < S390_NUM_CRS; regi++)
-    supply_register (S390_FIRST_CR + regi, NULL);
+  return wordsize;
 }
 
-
-void
-supply_fpregset (fpregset_t * fpregsetp)
+static int
+s390_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
+                gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
 {
-  int regi;
+  int sizeof_auxv_field = s390_target_wordsize ();
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
+  gdb_byte *ptr = *readptr;
 
-  supply_register (S390_FPC_REGNUM, (char *) &fpregsetp->fpc);
-  for (regi = 0; regi < S390_NUM_FPRS; regi++)
-    supply_register (S390_FP0_REGNUM + regi, (char *) &fpregsetp->fprs[regi]);
+  if (endptr == ptr)
+    return 0;
 
+  if (endptr - ptr < sizeof_auxv_field * 2)
+    return -1;
+
+  *typep = extract_unsigned_integer (ptr, sizeof_auxv_field, byte_order);
+  ptr += sizeof_auxv_field;
+  *valp = extract_unsigned_integer (ptr, sizeof_auxv_field, byte_order);
+  ptr += sizeof_auxv_field;
+
+  *readptr = ptr;
+  return 1;
 }
 
-void
-fill_gregset (gregset_t * gregsetp, int regno)
+#ifdef __s390x__
+static unsigned long
+s390_get_hwcap (void)
 {
-  int regi;
-  greg_t *gregp = (greg_t *) gregsetp;
+  CORE_ADDR field;
 
-  if (regno < 0) 
-    {
-      regcache_collect (S390_PSWM_REGNUM, &gregp[S390_PSWM_REGNUM]);
-      regcache_collect (S390_PC_REGNUM, &gregp[S390_PC_REGNUM]);
-      for (regi = 0; regi < S390_NUM_GPRS; regi++)
-        regcache_collect (S390_GP0_REGNUM + regi,
-                         &gregp[S390_GP0_REGNUM + regi]);
-#if defined (CONFIG_ARCH_S390X)
-      /* See the comments about the access registers in
-         supply_gregset, above.  */
-      {
-        unsigned int *acrs = (unsigned int *) &gregp[S390_FIRST_ACR];
-        
-        for (regi = 0; regi < S390_NUM_ACRS; regi++)
-          regcache_collect (S390_FIRST_ACR + regi, &acrs[regi]);
-      }
-#else
-      for (regi = 0; regi < S390_NUM_ACRS; regi++)
-        regcache_collect (S390_FIRST_ACR + regi,
-                         &gregp[S390_FIRST_ACR + regi]);
+  if (target_auxv_search (&current_target, AT_HWCAP, &field))
+    return (unsigned long) field;
+
+  return 0;
+}
 #endif
-    }
-  else if (regno >= S390_PSWM_REGNUM && regno < S390_FIRST_ACR)
-    regcache_collect (regno, &gregp[regno]);
-  else if (regno >= S390_FIRST_ACR && regno <= S390_LAST_ACR)
-    {
-#if defined (CONFIG_ARCH_S390X)
-      /* See the comments about the access registers in
-         supply_gregset, above.  */
-      unsigned int *acrs = (unsigned int *) &gregp[S390_FIRST_ACR];
-        
-      regcache_collect (regno, &acrs[regno - S390_FIRST_ACR]);
-#else
-      regcache_collect (regno, &gregp[regno]);
+
+static const struct target_desc *
+s390_read_description (struct target_ops *ops)
+{
+  int tid = s390_inferior_tid ();
+
+  have_regset_last_break
+    = check_regset (tid, NT_S390_LAST_BREAK, 8);
+  have_regset_system_call
+    = check_regset (tid, NT_S390_SYSTEM_CALL, 4);
+  have_regset_tdb
+    = check_regset (tid, NT_S390_TDB, s390_sizeof_tdbregset);
+
+#ifdef __s390x__
+  /* If GDB itself is compiled as 64-bit, we are running on a machine in
+     z/Architecture mode.  If the target is running in 64-bit addressing
+     mode, report s390x architecture.  If the target is running in 31-bit
+     addressing mode, but the kernel supports using 64-bit registers in
+     that mode, report s390 architecture with 64-bit GPRs.  */
+
+  if (s390_target_wordsize () == 8)
+    return (have_regset_tdb ? tdesc_s390x_te_linux64 :
+           have_regset_system_call? tdesc_s390x_linux64v2 :
+           have_regset_last_break? tdesc_s390x_linux64v1 :
+           tdesc_s390x_linux64);
+
+  if (s390_get_hwcap () & HWCAP_S390_HIGH_GPRS)
+    return (have_regset_tdb ? tdesc_s390_te_linux64 :
+           have_regset_system_call? tdesc_s390_linux64v2 :
+           have_regset_last_break? tdesc_s390_linux64v1 :
+           tdesc_s390_linux64);
 #endif
-    }
+
+  /* If GDB itself is compiled as 31-bit, or if we're running a 31-bit inferior
+     on a 64-bit kernel that does not support using 64-bit registers in 31-bit
+     mode, report s390 architecture with 32-bit GPRs.  */
+  return (have_regset_system_call? tdesc_s390_linux32v2 :
+         have_regset_last_break? tdesc_s390_linux32v1 :
+         tdesc_s390_linux32);
 }
 
-/*  Given a pointer to a floating point register set in /proc format
-   (fpregset_t *), update the register specified by REGNO from gdb's idea
-   of the current floating point register set.  If REGNO is -1, update
-   them all. */
+void _initialize_s390_nat (void);
 
 void
-fill_fpregset (fpregset_t * fpregsetp, int regno)
+_initialize_s390_nat (void)
 {
-  int regi;
-
-  if (regno < 0) 
-    {
-      regcache_collect (S390_FPC_REGNUM, &fpregsetp->fpc);
-      for (regi = 0; regi < S390_NUM_FPRS; regi++)
-        regcache_collect (S390_FP0_REGNUM + regi, &fpregsetp->fprs[regi]);
-    }
-  else if (regno == S390_FPC_REGNUM)
-    regcache_collect (S390_FPC_REGNUM, &fpregsetp->fpc);
-  else if (regno >= S390_FP0_REGNUM && regno <= S390_FPLAST_REGNUM)
-    regcache_collect (regno, &fpregsetp->fprs[regno - S390_FP0_REGNUM]);
+  struct target_ops *t;
+
+  /* Fill in the generic GNU/Linux methods.  */
+  t = linux_target ();
+
+  /* Add our register access methods.  */
+  t->to_fetch_registers = s390_linux_fetch_inferior_registers;
+  t->to_store_registers = s390_linux_store_inferior_registers;
+
+  /* Add our watchpoint methods.  */
+  t->to_can_use_hw_breakpoint = s390_can_use_hw_breakpoint;
+  t->to_region_ok_for_hw_watchpoint = s390_region_ok_for_hw_watchpoint;
+  t->to_have_continuable_watchpoint = 1;
+  t->to_stopped_by_watchpoint = s390_stopped_by_watchpoint;
+  t->to_insert_watchpoint = s390_insert_watchpoint;
+  t->to_remove_watchpoint = s390_remove_watchpoint;
+
+  /* Detect target architecture.  */
+  t->to_read_description = s390_read_description;
+  t->to_auxv_parse = s390_auxv_parse;
+
+  /* Register the target.  */
+  linux_nat_add_target (t);
+  linux_nat_set_new_thread (t, s390_fix_watch_points);
 }
-
-
-#else
-#error "There are a few possibilities here"
-#error "1) You aren't compiling for linux & don't need a core dumps to work."
-#error "2) The header files sys/elf.h sys/user.h sys/ptrace.h & sys/procfs.h"
-#error "libc files are inconsistent with linux/include/asm-s390/"
-#error "3) you didn't do a completely clean build & delete config.cache."
-#endif
This page took 0.034599 seconds and 4 git commands to generate.