Make GDB -Wpointer-sign clean on MinGW too.
[deliverable/binutils-gdb.git] / gdb / s390-nat.c
index c1eec1cc1dcdf7183061bcac15ec039e6a4c1f2a..de9934881e2678b058a92245a771c4d0e317adbb 100644 (file)
@@ -1,6 +1,5 @@
 /* S390 native-dependent code for GDB, the GNU debugger.
-   Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007, 2009
-   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.
 #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>
 #define HWCAP_S390_HIGH_GPRS 512
 #endif
 
+#ifndef PTRACE_GETREGSET
+#define PTRACE_GETREGSET 0x4204
+#endif
+
+#ifndef PTRACE_SETREGSET
+#define PTRACE_SETREGSET 0x4205
+#endif
+
+static int have_regset_last_break = 0;
+static int have_regset_system_call = 0;
 
 /* Map registers to gregset/ptrace offsets.
    These arrays are defined in s390-tdep.c.  */
@@ -97,7 +108,8 @@ s390_native_supply (struct regcache *regcache, int regno,
          return;
        }
 
-      if (regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM)
+      if ((regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM)
+         || regno == S390_ORIG_R2_REGNUM)
        offset += 4;
     }
 #endif
@@ -151,7 +163,8 @@ s390_native_collect (const struct regcache *regcache, int regno,
          return;
        }
 
-      if (regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM)
+      if ((regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM)
+         || regno == S390_ORIG_R2_REGNUM)
        {
          memset (regp + offset, 0, 4);
          offset += 4;
@@ -293,6 +306,70 @@ store_fpregs (const struct regcache *regcache, int tid, int regnum)
     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, int *regmap)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  gdb_byte *buf = alloca (regsize);
+  struct iovec iov;
+  int i;
+
+  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"));
+
+  for (i = 0; i < S390_NUM_REGS; i++)
+    s390_native_supply (regcache, i, buf, regmap);
+}
+
+/* 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, int *regmap)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  gdb_byte *buf = alloca (regsize);
+  struct iovec iov;
+  int i;
+
+  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"));
+
+  for (i = 0; i < S390_NUM_REGS; i++)
+    s390_native_collect (regcache, i, buf, regmap);
+
+  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)
+    return 0;
+  else
+    return 1;
+}
+
 /* Fetch register REGNUM from the child process.  If REGNUM is -1, do
    this for all registers.  */
 static void
@@ -308,6 +385,17 @@ s390_linux_fetch_inferior_registers (struct target_ops *ops,
   if (regnum == -1 
       || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
     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);
 }
 
 /* Store register REGNUM back into the child process.  If REGNUM is
@@ -325,6 +413,13 @@ s390_linux_store_inferior_registers (struct target_ops *ops,
   if (regnum == -1 
       || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
     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);
 }
 
 
@@ -377,7 +472,7 @@ s390_stopped_by_watchpoint (void)
 }
 
 static void
-s390_fix_watch_points (ptid_t ptid)
+s390_fix_watch_points (struct lwp_info *lp)
 {
   int tid;
 
@@ -387,9 +482,9 @@ s390_fix_watch_points (ptid_t ptid)
   CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0;
   struct watch_area *area;
 
-  tid = TIDGET (ptid);
+  tid = TIDGET (lp->ptid);
   if (tid == 0)
-    tid = PIDGET (ptid);
+    tid = PIDGET (lp->ptid);
 
   for (area = watch_base; area; area = area->next)
     {
@@ -437,7 +532,7 @@ s390_insert_watchpoint (CORE_ADDR addr, int len, int type,
   watch_base = area;
 
   ALL_LWPS (lp)
-    s390_fix_watch_points (lp->ptid);
+    s390_fix_watch_points (lp);
   return 0;
 }
 
@@ -465,7 +560,7 @@ s390_remove_watchpoint (CORE_ADDR addr, int len, int type,
   xfree (area);
 
   ALL_LWPS (lp)
-    s390_fix_watch_points (lp->ptid);
+    s390_fix_watch_points (lp);
   return 0;
 }
 
@@ -505,7 +600,7 @@ s390_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
                 gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
 {
   int sizeof_auxv_field = s390_target_wordsize ();
-  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
   gdb_byte *ptr = *readptr;
 
   if (endptr == ptr)
@@ -539,6 +634,13 @@ s390_get_hwcap (void)
 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);
+
 #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
@@ -547,16 +649,22 @@ s390_read_description (struct target_ops *ops)
      that mode, report s390 architecture with 64-bit GPRs.  */
 
   if (s390_target_wordsize () == 8)
-    return tdesc_s390x_linux64;
+    return (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 tdesc_s390_linux64;
+    return (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 tdesc_s390_linux32;
+  return (have_regset_system_call? tdesc_s390_linux32v2 :
+         have_regset_last_break? tdesc_s390_linux32v1 :
+         tdesc_s390_linux32);
 }
 
 void _initialize_s390_nat (void);
This page took 0.036478 seconds and 4 git commands to generate.