public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [RFA/RFT PATCH 0/3] Add TDB regset support
@ 2013-06-07 13:44 Andreas Arnez
  2013-06-07 13:50 ` [PATCH 1/3] S/390 regmap rework Andreas Arnez
                   ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: Andreas Arnez @ 2013-06-07 13:44 UTC (permalink / raw)
  To: gdb-patches, Ulrich Weigand

The new z/Architecture introduces restricted hardware transactional
memory with the "transactional-execution facility".  Diagnostic
capabilities of this feature include the "program interruption
transaction diagnostic block" (TDB), which is written by the hardware
whenever a transaction is aborted due to a program interruption.

This patch set makes the TDB accessible from GDB as a new register set.
The first patch reworks the S/390 register map handling without any
functional changes, the second adds the new TDB register set, and the
third implements "dynamic regset" support.

The third patch changes GDB's approach for enumerating core file
register note sections: Instead of a static array, an iterator function
is now provided by the target-dependent code.  This allows for
dynamically selecting a register set for inclusion in a core file
(written with gcore), and making the selection dependent on the current
register values.  This is needed for correct treatment of the TDB
register set, because its register values are unavailable when the
inferior was interrupted outside transactions, and then the TDB should
*not* be written into the core file.

This last patch affects multiple architectures, specifically:

- GNU/Linux ARM
- GNU/Linux PowerPC
- GNU/Linux S/390
- GNU/Linux x86

In most cases the patch simplifies the target-dependent logic.  I've
tested on S/390 and x86 and did not find any regressions.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/3] S/390 regmap rework
  2013-06-07 13:44 [RFA/RFT PATCH 0/3] Add TDB regset support Andreas Arnez
@ 2013-06-07 13:50 ` Andreas Arnez
  2015-05-05 19:17   ` Regression on gdb.base/checkpoint.exp on S/390 (was: Re: [PATCH 1/3] S/390 regmap rework) Sergio Durigan Junior
  2013-06-07 13:51 ` [PATCH 2/3] Add TDB regset Andreas Arnez
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 15+ messages in thread
From: Andreas Arnez @ 2013-06-07 13:50 UTC (permalink / raw)
  To: gdb-patches; +Cc: Ulrich Weigand

S/390 regmap rework: Represent register maps in a less redundant and
more readable way.  Also remove some code repetition.

2013-06-07  Andreas Arnez  <arnez@linux.vnet.ibm.com>

	* s390-tdep.h (S390_IS_GREGSET_REGNUM): New macro.
	(S390_IS_FPREGSET_REGNUM): New macro.

	* s390-tdep.c (s390_dwarf_regmap): Make const.
	(regnum_is_gpr_full): New function for replacing repeated code.
	(s390_pseudo_register_name): Use it.
	(s390_pseudo_register_type): Likewise.
	(s390_pseudo_register_read): Likewise.
	(s390_pseudo_register_write): Likewise.
	(s390_unwind_pseudo_register): Likewise.
	(s390_regmap_gregset): New format for regmap.
	(s390x_regmap_gregset): Likewise.
	(s390_regmap_fpregset): Likewise.
	(s390_regmap_upper): Likewise.
	(s390_regmap_last_break): Likewise.
	(s390_regmap_system_call): Likewise.
	(s390_supply_regset): Adjust to new regmap format.
	(s390_collect_regset): Likewise.

	* s390-nat.c (s390_native_supply): Adjust to new regmap format.
	(s390_native_collect): Likewise.
	(supply_gregset): Likewise.
	(fill_gregset): Likewise.
	(supply_fpregset): Likewise.
	(fill_fpregset): Likewise.
	(fetch_regset): Likewise.
	(store_regset): Likewise.
	(s390_linux_fetch_inferior_registers): Likewise.
	(s390_linux_fetch_inferior_registers): Likewise.

Index: gdb/gdb/s390-tdep.h
===================================================================
--- gdb.orig/gdb/s390-tdep.h
+++ gdb/gdb/s390-tdep.h
@@ -106,16 +106,24 @@
 #define S390_RETADDR_REGNUM S390_R14_REGNUM
 #define S390_FRAME_REGNUM S390_R11_REGNUM
 
+#define S390_IS_GREGSET_REGNUM(i)					\
+  (((i) >= S390_PSWM_REGNUM && (i) <= S390_A15_REGNUM)			\
+   || ((i) >= S390_R0_UPPER_REGNUM && (i) <= S390_R15_UPPER_REGNUM)	\
+   || (i) == S390_ORIG_R2_REGNUM)
+
+#define S390_IS_FPREGSET_REGNUM(i)			\
+  ((i) >= S390_FPC_REGNUM && (i) <= S390_F15_REGNUM)
+
 /* Core file register sets, defined in s390-tdep.c.  */
 #define s390_sizeof_gregset 0x90
-extern int s390_regmap_gregset[S390_NUM_REGS];
+extern const short s390_regmap_gregset[];
 #define s390x_sizeof_gregset 0xd8
-extern int s390x_regmap_gregset[S390_NUM_REGS];
+extern const short s390x_regmap_gregset[];
 #define s390_sizeof_fpregset 0x88
-extern int s390_regmap_fpregset[S390_NUM_REGS];
-extern int s390_regmap_last_break[S390_NUM_REGS];
-extern int s390x_regmap_last_break[S390_NUM_REGS];
-extern int s390_regmap_system_call[S390_NUM_REGS];
+extern const short s390_regmap_fpregset[];
+extern const short s390_regmap_last_break[];
+extern const short s390x_regmap_last_break[];
+extern const short s390_regmap_system_call[];
 
 /* GNU/Linux target descriptions.  */
 extern struct target_desc *tdesc_s390_linux32;
Index: gdb/gdb/s390-nat.c
===================================================================
--- gdb.orig/gdb/s390-nat.c
+++ gdb/gdb/s390-nat.c
@@ -63,139 +63,129 @@ static int have_regset_system_call = 0;
 
 #define regmap_fpregset s390_regmap_fpregset
 
-/* 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.  */
+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 + map[0]);
+}
 
 static void
-s390_native_supply (struct regcache *regcache, int regno,
-		    const gdb_byte *regp, int *regmap)
+s390_native_collect (const struct regcache *regcache, const short *map,
+		     int regno, gdb_byte *regp)
 {
-  int offset = regmap[regno];
+  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 (offset != -1 && gdbarch_ptr_bit (gdbarch) == 32)
+  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;
 
-      if (regno == S390_PSWM_REGNUM)
-	{
-	  ULONGEST pswm;
-	  gdb_byte buf[4];
-
-	  pswm = extract_unsigned_integer (regp + regmap[S390_PSWM_REGNUM],
-					   8, byte_order);
-
-	  store_unsigned_integer (buf, 4, byte_order, (pswm >> 32) | 0x80000);
-	  regcache_raw_supply (regcache, regno, buf);
-	  return;
-	}
-
-      if (regno == S390_PSWA_REGNUM)
+      for (map = regmap_gregset; map[0] >= 0; map += 2)
 	{
-	  ULONGEST pswm, pswa;
-	  gdb_byte buf[4];
+	  const gdb_byte *p = (const gdb_byte *) regp + map[0];
+	  int regno = map[1];
 
-	  pswa = extract_unsigned_integer (regp + regmap[S390_PSWA_REGNUM],
-					   8, byte_order);
-	  pswm = extract_unsigned_integer (regp + regmap[S390_PSWM_REGNUM],
-					   8, byte_order);
-
-	  store_unsigned_integer (buf, 4, byte_order,
-				  (pswa & 0x7fffffff) | (pswm & 0x80000000));
-	  regcache_raw_supply (regcache, regno, buf);
-	  return;
+	  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);
+	    }
 	}
 
-      if ((regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM)
-	  || regno == S390_ORIG_R2_REGNUM)
-	offset += 4;
+      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
 
-  if (offset != -1)
-    regcache_raw_supply (regcache, regno, regp + offset);
+  s390_native_supply (regcache, regmap_gregset, (const gdb_byte *) regp);
 }
 
-static void
-s390_native_collect (const struct regcache *regcache, int regno,
-		     gdb_byte *regp, int *regmap)
+/* 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)
 {
-  int offset = regmap[regno];
-
 #ifdef __s390x__
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
-  if (offset != -1 && gdbarch_ptr_bit (gdbarch) == 32)
+  if (gdbarch_ptr_bit (gdbarch) == 32)
     {
-      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+      gdb_byte *psw_p[2];
+      const short *map;
 
-      if (regno == S390_PSWM_REGNUM)
+      for (map = regmap_gregset; map[0] >= 0; map += 2)
 	{
-	  ULONGEST pswm;
-	  gdb_byte buf[4];
+	  gdb_byte *p = (gdb_byte *) regp + map[0];
+	  int reg = map[1];
 
-	  regcache_raw_collect (regcache, regno, buf);
-	  pswm = extract_unsigned_integer (buf, 4, byte_order);
+	  if (reg >= S390_PSWM_REGNUM && reg <= S390_PSWA_REGNUM)
+	    psw_p[reg - S390_PSWM_REGNUM] = p;
 
-	  /* We don't know the final addressing mode until the PSW address
-	     is known, so leave it as-is.  When the PSW address is collected
-	     (below), the addressing mode will be updated.  */
-	  store_unsigned_integer (regp + regmap[S390_PSWM_REGNUM],
-				  4, byte_order, pswm & 0xfff7ffff);
-	  return;
+	  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 == S390_PSWA_REGNUM)
+      if (regno == -1
+	  || regno == S390_PSWM_REGNUM || regno == S390_PSWA_REGNUM)
 	{
-	  ULONGEST pswa;
+	  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+	  ULONGEST pswa, pswm;
 	  gdb_byte buf[4];
 
-	  regcache_raw_collect (regcache, regno, buf);
+	  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);
 
-	  store_unsigned_integer (regp + regmap[S390_PSWA_REGNUM],
-				  8, byte_order, pswa & 0x7fffffff);
-
-	  /* Update basic addressing mode bit in PSW mask, see above.  */
-	  store_unsigned_integer (regp + regmap[S390_PSWM_REGNUM] + 4,
-				  4, byte_order, pswa & 0x80000000);
-	  return;
-	}
-
-      if ((regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM)
-	  || regno == S390_ORIG_R2_REGNUM)
-	{
-	  memset (regp + offset, 0, 4);
-	  offset += 4;
+	  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
 
-  if (offset != -1)
-    regcache_raw_collect (regcache, regno, regp + offset);
-}
-
-/* Fill GDB's register array with the general-purpose register values
-   in *REGP.  */
-void
-supply_gregset (struct regcache *regcache, const gregset_t *regp)
-{
-  int i;
-  for (i = 0; i < S390_NUM_REGS; i++)
-    s390_native_supply (regcache, i, (const gdb_byte *) regp, regmap_gregset);
-}
-
-/* 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)
-{
-  int i;
-  for (i = 0; i < S390_NUM_REGS; i++)
-    if (regno == -1 || regno == i)
-      s390_native_collect (regcache, i, (gdb_byte *) regp, regmap_gregset);
+  s390_native_collect (regcache, regmap_gregset, regno, (gdb_byte *) regp);
 }
 
 /* Fill GDB's register array with the floating-point register values
@@ -203,9 +193,7 @@ fill_gregset (const struct regcache *reg
 void
 supply_fpregset (struct regcache *regcache, const fpregset_t *regp)
 {
-  int i;
-  for (i = 0; i < S390_NUM_REGS; i++)
-    s390_native_supply (regcache, i, (const gdb_byte *) regp, regmap_fpregset);
+  s390_native_supply (regcache, regmap_fpregset, (const gdb_byte *) regp);
 }
 
 /* Fill register REGNO (if it is a general-purpose register) in
@@ -214,10 +202,7 @@ supply_fpregset (struct regcache *regcac
 void
 fill_fpregset (const struct regcache *regcache, fpregset_t *regp, int regno)
 {
-  int i;
-  for (i = 0; i < S390_NUM_REGS; i++)
-    if (regno == -1 || regno == i)
-      s390_native_collect (regcache, i, (gdb_byte *) regp, regmap_fpregset);
+  s390_native_collect (regcache, regmap_fpregset, regno, (gdb_byte *) regp);
 }
 
 /* Find the TID for the current inferior thread to use with ptrace.  */
@@ -311,12 +296,10 @@ store_fpregs (const struct regcache *reg
    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)
+	      int regset, int regsize, const short *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;
@@ -324,8 +307,7 @@ fetch_regset (struct regcache *regcache,
   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);
+  s390_native_supply (regcache, regmap, buf);
 }
 
 /* Store all registers in the kernel's register set whose number is REGSET,
@@ -333,12 +315,10 @@ fetch_regset (struct regcache *regcache,
    GDB's register cache back to process/thread TID.  */
 static void
 store_regset (struct regcache *regcache, int tid,
-	      int regset, int regsize, int *regmap)
+	      int regset, int regsize, const short *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;
@@ -346,8 +326,7 @@ store_regset (struct regcache *regcache,
   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);
+  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"));
@@ -378,12 +357,10 @@ s390_linux_fetch_inferior_registers (str
 {
   int tid = s390_inferior_tid ();
 
-  if (regnum == -1 
-      || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
+  if (regnum == -1 || S390_IS_GREGSET_REGNUM (regnum))
     fetch_regs (regcache, tid);
 
-  if (regnum == -1 
-      || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
+  if (regnum == -1 || S390_IS_FPREGSET_REGNUM (regnum))
     fetch_fpregs (regcache, tid);
 
   if (have_regset_last_break)
@@ -406,12 +383,10 @@ s390_linux_store_inferior_registers (str
 {
   int tid = s390_inferior_tid ();
 
-  if (regnum == -1 
-      || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
+  if (regnum == -1 || S390_IS_GREGSET_REGNUM (regnum))
     store_regs (regcache, tid, regnum);
 
-  if (regnum == -1 
-      || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
+  if (regnum == -1 || S390_IS_FPREGSET_REGNUM (regnum))
     store_fpregs (regcache, tid, regnum);
 
   /* S390_LAST_BREAK_REGNUM is read-only.  */
Index: gdb/gdb/s390-tdep.c
===================================================================
--- gdb.orig/gdb/s390-tdep.c
+++ gdb/gdb/s390-tdep.c
@@ -141,7 +141,7 @@ s390_write_pc (struct regcache *regcache
 
 /* DWARF Register Mapping.  */
 
-static int s390_dwarf_regmap[] =
+static const short s390_dwarf_regmap[] =
 {
   /* General Purpose Registers.  */
   S390_R0_REGNUM, S390_R1_REGNUM, S390_R2_REGNUM, S390_R3_REGNUM,
@@ -212,6 +212,14 @@ s390_adjust_frame_regnum (struct gdbarch
 
 /* Pseudo registers.  */
 
+static int
+regnum_is_gpr_full (struct gdbarch_tdep *tdep, int regnum)
+{
+  return (tdep->gpr_full_regnum != -1
+	  && regnum >= tdep->gpr_full_regnum
+	  && regnum <= tdep->gpr_full_regnum + 15);
+}
+
 static const char *
 s390_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
 {
@@ -223,9 +231,7 @@ s390_pseudo_register_name (struct gdbarc
   if (regnum == tdep->cc_regnum)
     return "cc";
 
-  if (tdep->gpr_full_regnum != -1
-      && regnum >= tdep->gpr_full_regnum
-      && regnum < tdep->gpr_full_regnum + 16)
+  if (regnum_is_gpr_full (tdep, regnum))
     {
       static const char *full_name[] = {
 	"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
@@ -248,9 +254,7 @@ s390_pseudo_register_type (struct gdbarc
   if (regnum == tdep->cc_regnum)
     return builtin_type (gdbarch)->builtin_int;
 
-  if (tdep->gpr_full_regnum != -1
-      && regnum >= tdep->gpr_full_regnum
-      && regnum < tdep->gpr_full_regnum + 16)
+  if (regnum_is_gpr_full (tdep, regnum))
     return builtin_type (gdbarch)->builtin_uint64;
 
   internal_error (__FILE__, __LINE__, _("invalid regnum"));
@@ -295,9 +299,7 @@ s390_pseudo_register_read (struct gdbarc
       return status;
     }
 
-  if (tdep->gpr_full_regnum != -1
-      && regnum >= tdep->gpr_full_regnum
-      && regnum < tdep->gpr_full_regnum + 16)
+  if (regnum_is_gpr_full (tdep, regnum))
     {
       enum register_status status;
       ULONGEST val_upper;
@@ -352,9 +354,7 @@ s390_pseudo_register_write (struct gdbar
       return;
     }
 
-  if (tdep->gpr_full_regnum != -1
-      && regnum >= tdep->gpr_full_regnum
-      && regnum < tdep->gpr_full_regnum + 16)
+  if (regnum_is_gpr_full (tdep, regnum))
     {
       regnum -= tdep->gpr_full_regnum;
       val = extract_unsigned_integer (buf, regsize, byte_order);
@@ -409,175 +409,166 @@ s390_pseudo_register_reggroup_p (struct
 }
 
 
-/* Core file register sets.  */
+/* Maps for register sets.  */
 
-int s390_regmap_gregset[S390_NUM_REGS] =
-{
-  /* Program Status Word.  */
-  0x00, 0x04,
-  /* General Purpose Registers.  */
-  0x08, 0x0c, 0x10, 0x14,
-  0x18, 0x1c, 0x20, 0x24,
-  0x28, 0x2c, 0x30, 0x34,
-  0x38, 0x3c, 0x40, 0x44,
-  /* Access Registers.  */
-  0x48, 0x4c, 0x50, 0x54,
-  0x58, 0x5c, 0x60, 0x64,
-  0x68, 0x6c, 0x70, 0x74,
-  0x78, 0x7c, 0x80, 0x84,
-  /* Floating Point Control Word.  */
-  -1,
-  /* Floating Point Registers.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* GPR Uppper Halves.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* GNU/Linux-specific optional "registers".  */
-  0x88, -1, -1,
-};
+const short s390_regmap_gregset[] =
+  {
+    0x00, S390_PSWM_REGNUM,
+    0x04, S390_PSWA_REGNUM,
+    0x08, S390_R0_REGNUM,
+    0x0c, S390_R1_REGNUM,
+    0x10, S390_R2_REGNUM,
+    0x14, S390_R3_REGNUM,
+    0x18, S390_R4_REGNUM,
+    0x1c, S390_R5_REGNUM,
+    0x20, S390_R6_REGNUM,
+    0x24, S390_R7_REGNUM,
+    0x28, S390_R8_REGNUM,
+    0x2c, S390_R9_REGNUM,
+    0x30, S390_R10_REGNUM,
+    0x34, S390_R11_REGNUM,
+    0x38, S390_R12_REGNUM,
+    0x3c, S390_R13_REGNUM,
+    0x40, S390_R14_REGNUM,
+    0x44, S390_R15_REGNUM,
+    0x48, S390_A0_REGNUM,
+    0x4c, S390_A1_REGNUM,
+    0x50, S390_A2_REGNUM,
+    0x54, S390_A3_REGNUM,
+    0x58, S390_A4_REGNUM,
+    0x5c, S390_A5_REGNUM,
+    0x60, S390_A6_REGNUM,
+    0x64, S390_A7_REGNUM,
+    0x68, S390_A8_REGNUM,
+    0x6c, S390_A9_REGNUM,
+    0x70, S390_A10_REGNUM,
+    0x74, S390_A11_REGNUM,
+    0x78, S390_A12_REGNUM,
+    0x7c, S390_A13_REGNUM,
+    0x80, S390_A14_REGNUM,
+    0x84, S390_A15_REGNUM,
+    0x88, S390_ORIG_R2_REGNUM,
+    -1, -1
+  };
 
-int s390x_regmap_gregset[S390_NUM_REGS] =
-{
-  /* Program Status Word.  */
-  0x00, 0x08,
-  /* General Purpose Registers.  */
-  0x10, 0x18, 0x20, 0x28,
-  0x30, 0x38, 0x40, 0x48,
-  0x50, 0x58, 0x60, 0x68,
-  0x70, 0x78, 0x80, 0x88,
-  /* Access Registers.  */
-  0x90, 0x94, 0x98, 0x9c,
-  0xa0, 0xa4, 0xa8, 0xac,
-  0xb0, 0xb4, 0xb8, 0xbc,
-  0xc0, 0xc4, 0xc8, 0xcc,
-  /* Floating Point Control Word.  */
-  -1,
-  /* Floating Point Registers.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* GPR Uppper Halves.  */
-  0x10, 0x18, 0x20, 0x28,
-  0x30, 0x38, 0x40, 0x48,
-  0x50, 0x58, 0x60, 0x68,
-  0x70, 0x78, 0x80, 0x88,
-  /* GNU/Linux-specific optional "registers".  */
-  0xd0, -1, -1,
-};
+const short s390x_regmap_gregset[] =
+  {
+    0x00, S390_PSWM_REGNUM,
+    0x08, S390_PSWA_REGNUM,
+    0x10, S390_R0_REGNUM,
+    0x18, S390_R1_REGNUM,
+    0x20, S390_R2_REGNUM,
+    0x28, S390_R3_REGNUM,
+    0x30, S390_R4_REGNUM,
+    0x38, S390_R5_REGNUM,
+    0x40, S390_R6_REGNUM,
+    0x48, S390_R7_REGNUM,
+    0x50, S390_R8_REGNUM,
+    0x58, S390_R9_REGNUM,
+    0x60, S390_R10_REGNUM,
+    0x68, S390_R11_REGNUM,
+    0x70, S390_R12_REGNUM,
+    0x78, S390_R13_REGNUM,
+    0x80, S390_R14_REGNUM,
+    0x88, S390_R15_REGNUM,
+    0x90, S390_A0_REGNUM,
+    0x94, S390_A1_REGNUM,
+    0x98, S390_A2_REGNUM,
+    0x9c, S390_A3_REGNUM,
+    0xa0, S390_A4_REGNUM,
+    0xa4, S390_A5_REGNUM,
+    0xa8, S390_A6_REGNUM,
+    0xac, S390_A7_REGNUM,
+    0xb0, S390_A8_REGNUM,
+    0xb4, S390_A9_REGNUM,
+    0xb8, S390_A10_REGNUM,
+    0xbc, S390_A11_REGNUM,
+    0xc0, S390_A12_REGNUM,
+    0xc4, S390_A13_REGNUM,
+    0xc8, S390_A14_REGNUM,
+    0xcc, S390_A15_REGNUM,
+    0x10, S390_R0_UPPER_REGNUM,
+    0x18, S390_R1_UPPER_REGNUM,
+    0x20, S390_R2_UPPER_REGNUM,
+    0x28, S390_R3_UPPER_REGNUM,
+    0x30, S390_R4_UPPER_REGNUM,
+    0x38, S390_R5_UPPER_REGNUM,
+    0x40, S390_R6_UPPER_REGNUM,
+    0x48, S390_R7_UPPER_REGNUM,
+    0x50, S390_R8_UPPER_REGNUM,
+    0x58, S390_R9_UPPER_REGNUM,
+    0x60, S390_R10_UPPER_REGNUM,
+    0x68, S390_R11_UPPER_REGNUM,
+    0x70, S390_R12_UPPER_REGNUM,
+    0x78, S390_R13_UPPER_REGNUM,
+    0x80, S390_R14_UPPER_REGNUM,
+    0x88, S390_R15_UPPER_REGNUM,
+    0xd0, S390_ORIG_R2_REGNUM,
+    -1, -1
+  };
 
-int s390_regmap_fpregset[S390_NUM_REGS] =
-{
-  /* Program Status Word.  */
-  -1, -1,
-  /* General Purpose Registers.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* Access Registers.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* Floating Point Control Word.  */
-  0x00,
-  /* Floating Point Registers.  */
-  0x08, 0x10, 0x18, 0x20,
-  0x28, 0x30, 0x38, 0x40,
-  0x48, 0x50, 0x58, 0x60,
-  0x68, 0x70, 0x78, 0x80,
-  /* GPR Uppper Halves.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* GNU/Linux-specific optional "registers".  */
-  -1, -1, -1,
-};
+const short s390_regmap_fpregset[] =
+  {
+    0x00, S390_FPC_REGNUM,
+    0x08, S390_F0_REGNUM,
+    0x10, S390_F1_REGNUM,
+    0x18, S390_F2_REGNUM,
+    0x20, S390_F3_REGNUM,
+    0x28, S390_F4_REGNUM,
+    0x30, S390_F5_REGNUM,
+    0x38, S390_F6_REGNUM,
+    0x40, S390_F7_REGNUM,
+    0x48, S390_F8_REGNUM,
+    0x50, S390_F9_REGNUM,
+    0x58, S390_F10_REGNUM,
+    0x60, S390_F11_REGNUM,
+    0x68, S390_F12_REGNUM,
+    0x70, S390_F13_REGNUM,
+    0x78, S390_F14_REGNUM,
+    0x80, S390_F15_REGNUM,
+    -1, -1
+  };
 
-int s390_regmap_upper[S390_NUM_REGS] =
-{
-  /* Program Status Word.  */
-  -1, -1,
-  /* General Purpose Registers.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* Access Registers.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* Floating Point Control Word.  */
-  -1,
-  /* Floating Point Registers.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* GPR Uppper Halves.  */
-  0x00, 0x04, 0x08, 0x0c,
-  0x10, 0x14, 0x18, 0x1c,
-  0x20, 0x24, 0x28, 0x2c,
-  0x30, 0x34, 0x38, 0x3c,
-  /* GNU/Linux-specific optional "registers".  */
-  -1, -1, -1,
-};
+const short s390_regmap_upper[] =
+  {
+    0x00, S390_R0_UPPER_REGNUM,
+    0x04, S390_R1_UPPER_REGNUM,
+    0x08, S390_R2_UPPER_REGNUM,
+    0x0c, S390_R3_UPPER_REGNUM,
+    0x10, S390_R4_UPPER_REGNUM,
+    0x14, S390_R5_UPPER_REGNUM,
+    0x18, S390_R6_UPPER_REGNUM,
+    0x1c, S390_R7_UPPER_REGNUM,
+    0x20, S390_R8_UPPER_REGNUM,
+    0x24, S390_R9_UPPER_REGNUM,
+    0x28, S390_R10_UPPER_REGNUM,
+    0x2c, S390_R11_UPPER_REGNUM,
+    0x30, S390_R12_UPPER_REGNUM,
+    0x34, S390_R13_UPPER_REGNUM,
+    0x38, S390_R14_UPPER_REGNUM,
+    0x3c, S390_R15_UPPER_REGNUM,
+    -1, -1
+  };
 
-int s390_regmap_last_break[S390_NUM_REGS] =
-{
-  /* Program Status Word.  */
-  -1, -1,
-  /* General Purpose Registers.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* Access Registers.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* Floating Point Control Word.  */
-  -1,
-  /* Floating Point Registers.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* GPR Uppper Halves.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* GNU/Linux-specific optional "registers".  */
-  -1, 4, -1,
-};
+const short s390_regmap_last_break[] =
+  {
+    0x04, S390_LAST_BREAK_REGNUM,
+    -1, -1
+  };
+
+const short s390x_regmap_last_break[] =
+  {
+    0x00, S390_LAST_BREAK_REGNUM,
+    -1, -1
+  };
+
+const short s390_regmap_system_call[] =
+  {
+    0x00, S390_SYSTEM_CALL_REGNUM,
+    -1, -1
+  };
 
-int s390x_regmap_last_break[S390_NUM_REGS] =
-{
-  /* Program Status Word.  */
-  -1, -1,
-  /* General Purpose Registers.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* Access Registers.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* Floating Point Control Word.  */
-  -1,
-  /* Floating Point Registers.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* GPR Uppper Halves.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* GNU/Linux-specific optional "registers".  */
-  -1, 0, -1,
-};
 
-int s390_regmap_system_call[S390_NUM_REGS] =
-{
-  /* Program Status Word.  */
-  -1, -1,
-  /* General Purpose Registers.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* Access Registers.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* Floating Point Control Word.  */
-  -1,
-  /* Floating Point Registers.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* GPR Uppper Halves.  */
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1,
-  /* GNU/Linux-specific optional "registers".  */
-  -1, -1, 0,
-};
 
 /* Supply register REGNUM from the register set REGSET to register cache 
    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
@@ -585,14 +576,10 @@ static void
 s390_supply_regset (const struct regset *regset, struct regcache *regcache,
 		    int regnum, const void *regs, size_t len)
 {
-  const int *offset = regset->descr;
-  int i;
-
-  for (i = 0; i < S390_NUM_REGS; i++)
-    {
-      if ((regnum == i || regnum == -1) && offset[i] != -1)
-	regcache_raw_supply (regcache, i, (const char *)regs + offset[i]);
-    }
+  const short *map;
+  for (map = regset->descr; map[0] >= 0; map += 2)
+    if (regnum == -1 || regnum == map[1])
+      regcache_raw_supply (regcache, map[1], (const char *)regs + map[0]);
 }
 
 /* Collect register REGNUM from the register cache REGCACHE and store
@@ -604,14 +591,10 @@ s390_collect_regset (const struct regset
 		     const struct regcache *regcache,
 		     int regnum, void *regs, size_t len)
 {
-  const int *offset = regset->descr;
-  int i;
-
-  for (i = 0; i < S390_NUM_REGS; i++)
-    {
-      if ((regnum == i || regnum == -1) && offset[i] != -1)
-	regcache_raw_collect (regcache, i, (char *)regs + offset[i]);
-    }
+  const short *map;
+  for (map = regset->descr; map[0] >= 0; map += 2)
+    if (regnum == -1 || regnum == map[1])
+      regcache_raw_collect (regcache, map[1], (char *)regs + map[0]);
 }
 
 static const struct regset s390_gregset = {
@@ -1718,9 +1701,7 @@ s390_unwind_pseudo_register (struct fram
 
   /* Unwind full GPRs to show at least the lower halves (as the
      upper halves are undefined).  */
-  if (tdep->gpr_full_regnum != -1
-      && regnum >= tdep->gpr_full_regnum
-      && regnum < tdep->gpr_full_regnum + 16)
+  if (regnum_is_gpr_full (tdep, regnum))
     {
       int reg = regnum - tdep->gpr_full_regnum;
       struct value *val;

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 2/3] Add TDB regset
  2013-06-07 13:44 [RFA/RFT PATCH 0/3] Add TDB regset support Andreas Arnez
  2013-06-07 13:50 ` [PATCH 1/3] S/390 regmap rework Andreas Arnez
@ 2013-06-07 13:51 ` Andreas Arnez
  2013-06-07 13:53 ` [PATCH 3/3] Dynamic core regset sections support Andreas Arnez
  2013-06-07 15:03 ` [RFA/RFT PATCH 0/3] Add TDB regset support Pedro Alves
  3 siblings, 0 replies; 15+ messages in thread
From: Andreas Arnez @ 2013-06-07 13:51 UTC (permalink / raw)
  To: gdb-patches; +Cc: Ulrich Weigand

The z/Architecture transactional-execution facility includes support
for a "transaction diagnostic block" (TDB) that is written by the
hardware upon interrupted transactions.  From a running inferior the
TDB can be retrieved via PTRACE_GETREGSET, but ENODATA is returned if
the inferior was interrupted outside transactions.  Analogously, a
core file conditionally contains the TDB, depending on whether the
process died within a transaction or not.  This patch represents the
TDB as a new regset in GDB.

gdb/ChangeLog:
2013-06-07  Andreas Arnez  <arnez@linux.vnet.ibm.com>

	* features/s390-tdb.xml: New file.

	* features/s390x-linux64v2.xml: Include s390-tdb.xml.

	* s390-tdep.h (S390_TDB_DWORD0_REGNUM): Define.
	(S390_TDB_DWORD0_REGNUM): Likewise.
	(S390_TDB_ABORT_CODE_REGNUM): Likewise.
	(S390_TDB_CONFLICT_TOKEN_REGNUM): Likewise.
	(S390_TDB_ATIA_REGNUM): Likewise.
	(S390_TDB_R0_REGNUM): Likewise.
	(S390_TDB_R1_REGNUM): Likewise.
	(S390_TDB_R2_REGNUM): Likewise.
	(S390_TDB_R3_REGNUM): Likewise.
	(S390_TDB_R4_REGNUM): Likewise.
	(S390_TDB_R5_REGNUM): Likewise.
	(S390_TDB_R6_REGNUM): Likewise.
	(S390_TDB_R7_REGNUM): Likewise.
	(S390_TDB_R8_REGNUM): Likewise.
	(S390_TDB_R9_REGNUM): Likewise.
	(S390_TDB_R10_REGNUM): Likewise.
	(S390_TDB_R11_REGNUM): Likewise.
	(S390_TDB_R12_REGNUM): Likewise.
	(S390_TDB_R13_REGNUM): Likewise.
	(S390_TDB_R14_REGNUM): Likewise.
	(S390_TDB_R15_REGNUM): Likewise.
	(S390_NUM_REGS): Increase.
	(S390_IS_TDBREGSET_REGNUM): New macro.

	* s390-tdep.c (s390_regmap_tdb): New regmap.
	(s390_tdb_regset): New regset.
	(s390_linux64v2_regset_sections): Add TDB regset to list.
	(s390x_linux64v2_regset_sections): Likewise.
	(s390_regset_from_core_section): Recognize TDB core note section.
	(s390_gdbarch_init): Handle TDB regset.

	* s390-nat.c (have_regset_tdb): New variable.
	(s390_native_supply): Support register invalidation.
	(fetch_regset): Invalidate registers if ptrace yields ENODATA.
	(check_regset): Treat ENODATA as "regset exists".
	(s390_linux_fetch_inferior_registers): Add TDB.
	(s390_read_description): Check for TDB existence.

	* regformats/s390x-linux64v2.dat: Regenerate.

	* features/s390x-linux64v2.c: Regenerate.

gdb/testsuite/ChangeLog:
2013-06-07  Andreas Arnez  <arnez@linux.vnet.ibm.com>

	* gdb.arch/s390-tdbregs.c: New file.

	* gdb.arch/s390-tdbregs.exp: New file.

Index: gdb/gdb/features/s390-tdb.xml
===================================================================
--- /dev/null
+++ gdb/gdb/features/s390-tdb.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010-2013 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.s390.tdb">
+  <reg name="tdb0" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tac" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tct" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="atia" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tr0" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tr1" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tr2" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tr3" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tr4" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tr5" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tr6" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tr7" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tr8" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tr9" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tr10" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tr11" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tr12" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tr13" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tr14" bitsize="64" type="uint64" group="tdb"/>
+  <reg name="tr15" bitsize="64" type="uint64" group="tdb"/>
+</feature>
Index: gdb/gdb/s390-tdep.c
===================================================================
--- gdb.orig/gdb/s390-tdep.c
+++ gdb/gdb/s390-tdep.c
@@ -568,6 +568,30 @@ const short s390_regmap_system_call[] =
     -1, -1
   };
 
+const short s390_regmap_tdb[] =
+  {
+    0x00, S390_TDB_DWORD0_REGNUM,
+    0x08, S390_TDB_ABORT_CODE_REGNUM,
+    0x10, S390_TDB_CONFLICT_TOKEN_REGNUM,
+    0x18, S390_TDB_ATIA_REGNUM,
+    0x80, S390_TDB_R0_REGNUM,
+    0x88, S390_TDB_R1_REGNUM,
+    0x90, S390_TDB_R2_REGNUM,
+    0x98, S390_TDB_R3_REGNUM,
+    0xa0, S390_TDB_R4_REGNUM,
+    0xa8, S390_TDB_R5_REGNUM,
+    0xb0, S390_TDB_R6_REGNUM,
+    0xb8, S390_TDB_R7_REGNUM,
+    0xc0, S390_TDB_R8_REGNUM,
+    0xc8, S390_TDB_R9_REGNUM,
+    0xd0, S390_TDB_R10_REGNUM,
+    0xd8, S390_TDB_R11_REGNUM,
+    0xe0, S390_TDB_R12_REGNUM,
+    0xe8, S390_TDB_R13_REGNUM,
+    0xf0, S390_TDB_R14_REGNUM,
+    0xf8, S390_TDB_R15_REGNUM,
+    -1, -1
+  };
 
 
 /* Supply register REGNUM from the register set REGSET to register cache 
@@ -639,6 +663,12 @@ static const struct regset s390_system_c
   s390_collect_regset
 };
 
+static const struct regset s390_tdb_regset = {
+  s390_regmap_tdb,
+  s390_supply_regset,
+  s390_collect_regset
+};
+
 static struct core_regset_section s390_linux32_regset_sections[] =
 {
   { ".reg", s390_sizeof_gregset, "general-purpose" },
@@ -687,6 +717,7 @@ static struct core_regset_section s390_l
   { ".reg-s390-high-gprs", 16*4, "s390 GPR upper halves" },
   { ".reg-s390-last-break", 8, "s930 last-break address" },
   { ".reg-s390-system-call", 4, "s390 system-call" },
+  { ".reg-s390-tdb", s390_sizeof_tdbregset, "s390 TDB" },
   { NULL, 0}
 };
 
@@ -711,6 +742,7 @@ static struct core_regset_section s390x_
   { ".reg2", s390_sizeof_fpregset, "floating-point" },
   { ".reg-s390-last-break", 8, "s930 last-break address" },
   { ".reg-s390-system-call", 4, "s390 system-call" },
+  { ".reg-s390-tdb", s390_sizeof_tdbregset, "s390 TDB" },
   { NULL, 0}
 };
 
@@ -739,6 +771,9 @@ s390_regset_from_core_section (struct gd
   if (strcmp (sect_name, ".reg-s390-system-call") == 0 && sect_size >= 4)
     return &s390_system_call_regset;
 
+  if (strcmp (sect_name, ".reg-s390-tdb") == 0 && sect_size >= 256)
+    return &s390_tdb_regset;
+
   return NULL;
 }
 
@@ -3011,6 +3046,11 @@ s390_gdbarch_init (struct gdbarch_info i
 	"r0h", "r1h", "r2h", "r3h", "r4h", "r5h", "r6h", "r7h",
 	"r8h", "r9h", "r10h", "r11h", "r12h", "r13h", "r14h", "r15h"
       };
+      static const char *const tdb_regs[] = {
+	"tdb0", "tac", "tct", "atia",
+	"tr0", "tr1", "tr2", "tr3", "tr4", "tr5", "tr6", "tr7",
+	"tr8", "tr9", "tr10", "tr11", "tr12", "tr13", "tr14", "tr15"
+      };
       const struct tdesc_feature *feature;
       int i, valid_p = 1;
 
@@ -3088,6 +3128,16 @@ s390_gdbarch_init (struct gdbarch_info i
 	    valid_p = 0;
 	}
 
+      /* Transaction diagnostic block.  */
+      feature = tdesc_find_feature (tdesc, "org.gnu.gdb.s390.tdb");
+      if (feature)
+	{
+	  for (i = 0; i < ARRAY_SIZE (tdb_regs); i++)
+	    valid_p &= tdesc_numbered_register (feature, tdesc_data,
+						S390_TDB_DWORD0_REGNUM + i,
+						tdb_regs[i]);
+	}
+
       if (!valid_p)
 	{
 	  tdesc_data_cleanup (tdesc_data);
Index: gdb/gdb/features/s390x-linux64v2.xml
===================================================================
--- gdb.orig/gdb/features/s390x-linux64v2.xml
+++ gdb/gdb/features/s390x-linux64v2.xml
@@ -19,4 +19,6 @@
     <reg name="last_break" bitsize="64" type="code_ptr" group="system" save-restore="no"/>
     <reg name="system_call" bitsize="32" type="uint32" group="system"/>
   </feature>
+
+  <xi:include href="s390-tdb.xml"/>
 </target>
Index: gdb/gdb/s390-tdep.h
===================================================================
--- gdb.orig/gdb/s390-tdep.h
+++ gdb/gdb/s390-tdep.h
@@ -98,8 +98,29 @@
 #define S390_ORIG_R2_REGNUM 67
 #define S390_LAST_BREAK_REGNUM 68
 #define S390_SYSTEM_CALL_REGNUM 69
+/* Transaction diagnostic block.  */
+#define S390_TDB_DWORD0_REGNUM 70
+#define S390_TDB_ABORT_CODE_REGNUM 71
+#define S390_TDB_CONFLICT_TOKEN_REGNUM 72
+#define S390_TDB_ATIA_REGNUM 73
+#define S390_TDB_R0_REGNUM 74
+#define S390_TDB_R1_REGNUM 75
+#define S390_TDB_R2_REGNUM 76
+#define S390_TDB_R3_REGNUM 77
+#define S390_TDB_R4_REGNUM 78
+#define S390_TDB_R5_REGNUM 79
+#define S390_TDB_R6_REGNUM 80
+#define S390_TDB_R7_REGNUM 81
+#define S390_TDB_R8_REGNUM 82
+#define S390_TDB_R9_REGNUM 83
+#define S390_TDB_R10_REGNUM 84
+#define S390_TDB_R11_REGNUM 85
+#define S390_TDB_R12_REGNUM 86
+#define S390_TDB_R13_REGNUM 87
+#define S390_TDB_R14_REGNUM 88
+#define S390_TDB_R15_REGNUM 89
 /* Total.  */
-#define S390_NUM_REGS 70
+#define S390_NUM_REGS 90
 
 /* Special register usage.  */
 #define S390_SP_REGNUM S390_R15_REGNUM
@@ -114,6 +135,9 @@
 #define S390_IS_FPREGSET_REGNUM(i)			\
   ((i) >= S390_FPC_REGNUM && (i) <= S390_F15_REGNUM)
 
+#define S390_IS_TDBREGSET_REGNUM(i)				\
+  ((i) >= S390_TDB_DWORD0_REGNUM && (i) <= S390_TDB_R15_REGNUM)
+
 /* Core file register sets, defined in s390-tdep.c.  */
 #define s390_sizeof_gregset 0x90
 extern const short s390_regmap_gregset[];
@@ -124,6 +148,8 @@ extern const short s390_regmap_fpregset[
 extern const short s390_regmap_last_break[];
 extern const short s390x_regmap_last_break[];
 extern const short s390_regmap_system_call[];
+extern const short s390_regmap_tdb[];
+#define s390_sizeof_tdbregset 0x100
 
 /* GNU/Linux target descriptions.  */
 extern struct target_desc *tdesc_s390_linux32;
Index: gdb/gdb/s390-nat.c
===================================================================
--- gdb.orig/gdb/s390-nat.c
+++ gdb/gdb/s390-nat.c
@@ -51,6 +51,7 @@
 
 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.  */
@@ -68,7 +69,7 @@ s390_native_supply (struct regcache *reg
 		    const gdb_byte *regp)
 {
   for (; map[0] >= 0; map += 2)
-    regcache_raw_supply (regcache, map[1], regp + map[0]);
+    regcache_raw_supply (regcache, map[1], regp ? regp + map[0] : NULL);
 }
 
 static void
@@ -305,9 +306,12 @@ fetch_regset (struct regcache *regcache,
   iov.iov_len = regsize;
 
   if (ptrace (PTRACE_GETREGSET, tid, (long) regset, (long) &iov) < 0)
-    perror_with_name (_("Couldn't get register set"));
-
-  s390_native_supply (regcache, regmap, buf);
+    if (errno == ENODATA)
+      s390_native_supply (regcache, regmap, NULL);
+    else
+      perror_with_name (_("Couldn't get register set"));
+  else
+    s390_native_supply (regcache, regmap, buf);
 }
 
 /* Store all registers in the kernel's register set whose number is REGSET,
@@ -343,10 +347,10 @@ check_regset (int tid, int regset, int r
   iov.iov_base = buf;
   iov.iov_len = regsize;
 
-  if (ptrace (PTRACE_GETREGSET, tid, (long) regset, (long) &iov) < 0)
-    return 0;
-  else
+  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
@@ -373,6 +377,11 @@ s390_linux_fetch_inferior_registers (str
     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);
 }
 
 /* Store register REGNUM back into the child process.  If REGNUM is
@@ -615,6 +624,8 @@ s390_read_description (struct target_ops
     = 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
Index: gdb/gdb/features/s390x-linux64v2.c
===================================================================
--- gdb.orig/gdb/features/s390x-linux64v2.c
+++ gdb/gdb/features/s390x-linux64v2.c
@@ -76,5 +76,27 @@ initialize_tdesc_s390x_linux64v2 (void)
   tdesc_create_reg (feature, "last_break", 52, 0, "system", 64, "code_ptr");
   tdesc_create_reg (feature, "system_call", 53, 1, "system", 32, "uint32");
 
+  feature = tdesc_create_feature (result, "org.gnu.gdb.s390.tdb");
+  tdesc_create_reg (feature, "tdb0", 54, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tac", 55, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tct", 56, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "atia", 57, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr0", 58, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr1", 59, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr2", 60, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr3", 61, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr4", 62, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr5", 63, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr6", 64, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr7", 65, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr8", 66, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr9", 67, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr10", 68, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr11", 69, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr12", 70, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr13", 71, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr14", 72, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr15", 73, 1, "tdb", 64, "uint64");
+
   tdesc_s390x_linux64v2 = result;
 }
Index: gdb/gdb/regformats/s390x-linux64v2.dat
===================================================================
--- gdb.orig/gdb/regformats/s390x-linux64v2.dat
+++ gdb/gdb/regformats/s390x-linux64v2.dat
@@ -56,3 +56,23 @@ expedite:r14,r15,pswa
 64:orig_r2
 64:last_break
 32:system_call
+64:tdb0
+64:tac
+64:tct
+64:atia
+64:tr0
+64:tr1
+64:tr2
+64:tr3
+64:tr4
+64:tr5
+64:tr6
+64:tr7
+64:tr8
+64:tr9
+64:tr10
+64:tr11
+64:tr12
+64:tr13
+64:tr14
+64:tr15
Index: gdb/gdb/testsuite/gdb.arch/s390-tdbregs.c
===================================================================
--- /dev/null
+++ gdb/gdb/testsuite/gdb.arch/s390-tdbregs.c
@@ -0,0 +1,62 @@
+/* Copyright 2008-2013 Free Software Foundation, Inc.
+
+   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 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+
+static void
+my_tbegin ()
+{
+  asm volatile ( "1:  tbegin 0, 0xff00\n"
+		 "    jnz 1b"
+		 : /* no return value */
+		 : /* no inputs */
+		 : "cc", "memory" );
+}
+
+static void
+my_tend ()
+{
+  asm volatile ( "    tend"
+		 : /* no return value */
+		 : /* no inputs */
+		 : "cc");
+}
+
+void
+try_transaction (void)
+{
+  my_tbegin ();
+  my_tend ();
+}
+
+void
+crash_in_transaction (void)
+{
+  volatile char *p = 0;
+
+  my_tbegin ();
+  *p = 5;			/* FAULT */
+  my_tend ();
+}
+
+int
+main (int argc, char *argv[])
+{
+  try_transaction ();
+  crash_in_transaction ();
+  return 0;
+}
Index: gdb/gdb/testsuite/gdb.arch/s390-tdbregs.exp
===================================================================
--- /dev/null
+++ gdb/gdb/testsuite/gdb.arch/s390-tdbregs.exp
@@ -0,0 +1,75 @@
+# Copyright 2004-2013 Free Software Foundation, Inc.
+
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# 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, see <http://www.gnu.org/licenses/>.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@gnu.org
+
+# This file is part of the gdb testsuite.
+
+
+if { ![istarget s390-*-*] && ![istarget s390x-*-* ] } {
+    verbose "Skipping s390 TDB register tests."
+    return
+}
+
+set testfile "s390-tdbregs"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+if { [get_compiler_info] } {
+    return -1
+}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
+      executable [list debug additional_flags=-march=zEC12]] != "" } {
+    unsupported "No TE support (compile failed)."
+    return
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if { ![runto_main] } then {
+    gdb_suppress_tests
+}
+
+gdb_test_multiple "next" "check for TE support" {
+    -re "Program received signal SIGILL,.*\r\n$gdb_prompt $" {
+	unsupported "No TE support."
+	return
+    }
+    -re "\[0-9\]+.*\r\n$gdb_prompt $" {
+	pass "TE support available"
+    }
+    -re "$gdb_prompt $" {
+	unsupported "No TE support (unknown error)."
+	return
+    }
+}
+
+set crashline [gdb_get_line_number "FAULT"]
+
+gdb_test "print \$tdb0" "\\\$\[0-9\]+ = <unavailable>" "tdb0 unavailable"
+gdb_test "print \$tr0" "\\\$\[0-9\]+ = <unavailable>" "tr0 unavailable"
+gdb_test "next" \
+    "Program received signal SIGSEGV, .*" \
+    "crash in transaction"
+gdb_test "print/x \$tdb0" "\\\$\[0-9\]+ = 0x1.*" "tdb0 available"
+gdb_test "set print symbol-filename" "" "set print symbol-filename"
+gdb_test "print/a \$atia" \
+    "<crash_in_transaction.*:$crashline>" \
+    "ATIA points to crash"
Index: gdb/gdb/features/s390-linux64v2.xml
===================================================================
--- gdb.orig/gdb/features/s390-linux64v2.xml
+++ gdb/gdb/features/s390-linux64v2.xml
@@ -20,4 +20,6 @@
     <reg name="last_break" bitsize="32" type="code_ptr" group="system" save-restore="no"/>
     <reg name="system_call" bitsize="32" type="uint32" group="system"/>
   </feature>
+
+  <xi:include href="s390-tdb.xml"/>
 </target>
Index: gdb/gdb/features/s390-linux64v2.c
===================================================================
--- gdb.orig/gdb/features/s390-linux64v2.c
+++ gdb/gdb/features/s390-linux64v2.c
@@ -92,5 +92,27 @@ initialize_tdesc_s390_linux64v2 (void)
   tdesc_create_reg (feature, "last_break", 68, 0, "system", 32, "code_ptr");
   tdesc_create_reg (feature, "system_call", 69, 1, "system", 32, "uint32");
 
+  feature = tdesc_create_feature (result, "org.gnu.gdb.s390.tdb");
+  tdesc_create_reg (feature, "tdb0", 70, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tac", 71, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tct", 72, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "atia", 73, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr0", 74, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr1", 75, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr2", 76, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr3", 77, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr4", 78, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr5", 79, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr6", 80, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr7", 81, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr8", 82, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr9", 83, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr10", 84, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr11", 85, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr12", 86, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr13", 87, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr14", 88, 1, "tdb", 64, "uint64");
+  tdesc_create_reg (feature, "tr15", 89, 1, "tdb", 64, "uint64");
+
   tdesc_s390_linux64v2 = result;
 }
Index: gdb/gdb/regformats/s390-linux64v2.dat
===================================================================
--- gdb.orig/gdb/regformats/s390-linux64v2.dat
+++ gdb/gdb/regformats/s390-linux64v2.dat
@@ -72,3 +72,23 @@ expedite:r14l,r15l,pswa
 32:orig_r2
 32:last_break
 32:system_call
+64:tdb0
+64:tac
+64:tct
+64:atia
+64:tr0
+64:tr1
+64:tr2
+64:tr3
+64:tr4
+64:tr5
+64:tr6
+64:tr7
+64:tr8
+64:tr9
+64:tr10
+64:tr11
+64:tr12
+64:tr13
+64:tr14
+64:tr15

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 3/3] Dynamic core regset sections support
  2013-06-07 13:44 [RFA/RFT PATCH 0/3] Add TDB regset support Andreas Arnez
  2013-06-07 13:50 ` [PATCH 1/3] S/390 regmap rework Andreas Arnez
  2013-06-07 13:51 ` [PATCH 2/3] Add TDB regset Andreas Arnez
@ 2013-06-07 13:53 ` Andreas Arnez
  2013-06-07 14:43   ` Luis Machado
  2013-06-07 15:03 ` [RFA/RFT PATCH 0/3] Add TDB regset support Pedro Alves
  3 siblings, 1 reply; 15+ messages in thread
From: Andreas Arnez @ 2013-06-07 13:53 UTC (permalink / raw)
  To: gdb-patches; +Cc: Ulrich Weigand

Rework the handling of core file register note sections.  So far the
target-dependent code provided a static list of supported register
note sections via set_gdbarch_core_regset_sections.  This patch
replaces the static list by a target-dependent iterator function which
can be set with set_gdbarch_iterate_over_regset_sections.  Only those
architectures that have been using set_gdbarch_core_regset_sections
are affected by this change.

The patch is needed on newer z/Architecture systems for correct gcore
handling.  With the static approach, gcore always writes the TDB
regset into the core file, even if the TDB registers are currently
invalid.  The new iterator omits the TDB in this case.

2013-06-07  Andreas Arnez  <arnez@linux.vnet.ibm.com>

	* regset.h (struct core_regset_section): Remove structure
	declaration.

	* gdbarch.sh: Add typedef for iterate_over_regset_sections_cb.
	(function_list): Remove core_regset_sections.  Add
	iterate_over_regset_sections.

	* gdbarch.h: Regenerate.

	* gdbarch.c: Regenerate.

	* linux-tdep.c (linux_collect_regset_section_cb_data): New
	structure.
	(linux_collect_regset_section_cb): New function.
	(linux_collect_thread_registers): Replace loop by iteration
	through gdbarch_iterate_over_regset_sections.
	(linux_make_corefile_notes_1): Adjust check.

	* amd64-linux-tdep.c (amd64_linux_regset_sections): Remove array.
	(amd64_linux_iterate_over_regset_sections): New function.
	(amd64_linux_init_abi_common): Remove invocation of
	set_gdbarch_core_regset_sections; instead, call
	set_gdbarch_iterate_over_regset_sections.

	* arm-linux-tdep.c (arm_linux_fpa_regset_sections): Remove array.
	(arm_linux_vfp_regset_sections): Likewise.
	(arm_linux_iterate_over_regset_sections): New function.
	(arm_linux_init_abi): Remove invocations of
	set_gdbarch_core_regset_sections; instead, call
	set_gdbarch_iterate_over_regset_sections.

	* i386-linux-tdep.c (i386_linux_regset_sections): Remove array.
	(i386_linux_sse_regset_sections): Likewise.
	(i386_linux_avx_regset_sections): Likewise.
	(i386_linux_iterate_over_regset_sections): New function.
	(i386_linux_init_abi): Remove invocations of
	set_gdbarch_core_regset_sections; instead, call
	set_gdbarch_iterate_over_regset_sections.

	* ppc-linux-tdep.c (ppc_linux_vsx_regset_sections): Remove array.
	(ppc_linux_vmx_regset_sections): Likewise.
	(ppc64_linux_vsx_regset_sections): Likewise.
	(ppc64_linux_vmx_regset_sections): Likewise.
	(ppc64_linux_fp_regset_sections): Likewise.
	(ppc_linux_iterate_over_regset_sections): New function.
	(ppc_linux_init_abi): Remove invocations of
	set_gdbarch_core_regset_sections; instead, call
	set_gdbarch_iterate_over_regset_sections.

	* s390-tdep.c (gdbarch_tdep): New fields "have_linux_v1" and
	"have_linux_v2".
	(s390_linux32_regset_sections): Remove array.
	(s390_linux32v1_regset_sections): Likewise.
	(s390_linux32v2_regset_sections): Likewise.
	(s390_linux64_regset_sections): Likewise.
	(s390_linux64v1_regset_sections): Likewise.
	(s390_linux64v2_regset_sections): Likewise.
	(s390x_linux64_regset_sections): Likewise.
	(s390x_linux64v1_regset_sections): Likewise.
	(s390x_linux64v2_regset_sections): Likewise.
	(s390_iterate_over_regset_sections ): New function.
	(s390_gdbarch_init): Initialize new tdep fields "have_linux_v1"
	and "have_linux_v2".  Remove all invocations of
	set_gdbarch_core_regset_sections; instead, call
	set_gdbarch_iterate_over_regset_sections.

	* corelow.c (get_core_registers_cb): New function.
	(get_core_registers): Instead of looping through the list returned
	by gdbarch_core_regset_sections, iterate get_core_registers_cb via
	gdbarch_iterate_over_regset_sections.

Index: gdb/gdb/gdbarch.sh
===================================================================
--- gdb.orig/gdb/gdbarch.sh
+++ gdb/gdb/gdbarch.sh
@@ -635,8 +635,13 @@ F:CORE_ADDR:fetch_pointer_argument:struc
 # name SECT_NAME and size SECT_SIZE.
 M:const struct regset *:regset_from_core_section:const char *sect_name, size_t sect_size:sect_name, sect_size
 
-# Supported register notes in a core file.
-v:struct core_regset_section *:core_regset_sections:const char *name, int len::::::host_address_to_string (gdbarch->core_regset_sections)
+# Iterate over all supported register notes in a core file.  For each
+# supported register note section, the iterator must call CB and pass
+# CB_DATA unchanged.  If CB returns non-zero, the iterator must stop.
+# If REGCACHE is not NULL, the iterator can limit the supported
+# register note sections based on the current register values.
+# Otherwise it should enumerate all supported register note sections.
+M:void:iterate_over_regset_sections:iterate_over_regset_sections_cb *cb, void *cb_data, const struct regcache *regcache:cb, cb_data, regcache
 
 # Create core file notes
 M:char *:make_corefile_notes:bfd *obfd, int *note_size:obfd, note_size
@@ -1116,6 +1121,9 @@ extern struct gdbarch startup_gdbarch;
 
 typedef int (iterate_over_objfiles_in_search_order_cb_ftype)
   (struct objfile *objfile, void *cb_data);
+
+typedef int (iterate_over_regset_sections_cb)
+  (const char *sect_name, int size, const char *human_name, void *cb_data);
 EOF
 
 # function typedef's
Index: gdb/gdb/linux-tdep.c
===================================================================
--- gdb.orig/gdb/linux-tdep.c
+++ gdb/gdb/linux-tdep.c
@@ -1010,6 +1010,54 @@ linux_make_mappings_corefile_notes (stru
   return note_data;
 }
 
+/* Structure for passing information from
+   linux_collect_thread_registers via an iterator to
+   linux_collect_regset_section_cb. */
+
+struct linux_collect_regset_section_cb_data
+{
+  struct gdbarch *gdbarch;
+  const struct regcache *regcache;
+  bfd *obfd;
+  char *note_data;
+  int *note_size;
+  unsigned long lwp;
+  enum gdb_signal stop_signal;
+};
+
+/* Callback for iterate_over_regset_sections that records a single
+   regset in the corefile note section.  */
+
+static int
+linux_collect_regset_section_cb (const char *sect_name, int size,
+				 const char *human_name, void *cb_data)
+{
+  const struct regset *regset;
+  char *buf;
+  struct linux_collect_regset_section_cb_data *data = cb_data;
+
+  regset = gdbarch_regset_from_core_section (data->gdbarch, sect_name, size);
+  gdb_assert (regset && regset->collect_regset);
+
+  buf = xmalloc (size);
+  regset->collect_regset (regset, data->regcache, -1, buf, size);
+
+  /* PRSTATUS still needs to be treated specially.  */
+  if (strcmp (sect_name, ".reg") == 0)
+    data->note_data = (char *) elfcore_write_prstatus
+      (data->obfd, data->note_data, data->note_size, data->lwp,
+       gdb_signal_to_host (data->stop_signal), buf);
+  else
+    data->note_data = (char *) elfcore_write_register_note
+      (data->obfd, data->note_data, data->note_size,
+       sect_name, buf, size);
+  xfree (buf);
+
+  if (!data->note_data)
+    return 1;			/* Abort iteration. */
+  return 0;
+}
+
 /* Records the thread's register state for the corefile note
    section.  */
 
@@ -1020,47 +1068,24 @@ linux_collect_thread_registers (const st
 				enum gdb_signal stop_signal)
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
-  struct core_regset_section *sect_list;
-  unsigned long lwp;
+  struct linux_collect_regset_section_cb_data data;
 
-  sect_list = gdbarch_core_regset_sections (gdbarch);
-  gdb_assert (sect_list);
+  data.gdbarch = gdbarch;
+  data.regcache = regcache;
+  data.obfd = obfd;
+  data.note_data = note_data;
+  data.note_size = note_size;
+  data.stop_signal = stop_signal;
 
   /* For remote targets the LWP may not be available, so use the TID.  */
-  lwp = ptid_get_lwp (ptid);
-  if (!lwp)
-    lwp = ptid_get_tid (ptid);
-
-  while (sect_list->sect_name != NULL)
-    {
-      const struct regset *regset;
-      char *buf;
-
-      regset = gdbarch_regset_from_core_section (gdbarch,
-						 sect_list->sect_name,
-						 sect_list->size);
-      gdb_assert (regset && regset->collect_regset);
-
-      buf = xmalloc (sect_list->size);
-      regset->collect_regset (regset, regcache, -1, buf, sect_list->size);
-
-      /* PRSTATUS still needs to be treated specially.  */
-      if (strcmp (sect_list->sect_name, ".reg") == 0)
-	note_data = (char *) elfcore_write_prstatus
-			       (obfd, note_data, note_size, lwp,
-				gdb_signal_to_host (stop_signal), buf);
-      else
-	note_data = (char *) elfcore_write_register_note
-			       (obfd, note_data, note_size,
-				sect_list->sect_name, buf, sect_list->size);
-      xfree (buf);
-      sect_list++;
-
-      if (!note_data)
-	return NULL;
-    }
-
-  return note_data;
+  data.lwp = ptid_get_lwp (ptid);
+  if (!data.lwp)
+    data.lwp = ptid_get_tid (ptid);
+
+  gdbarch_iterate_over_regset_sections (gdbarch,
+					linux_collect_regset_section_cb,
+					&data, regcache);
+  return data.note_data;
 }
 
 /* Fetch the siginfo data for the current thread, if it exists.  If
@@ -1440,7 +1465,7 @@ linux_make_corefile_notes_1 (struct gdba
      converted to gdbarch_core_regset_sections, we no longer need to fall back
      to the target method at this point.  */
 
-  if (!gdbarch_core_regset_sections (gdbarch))
+  if (!gdbarch_iterate_over_regset_sections_p (gdbarch))
     return target_make_corefile_notes (obfd, note_size);
   else
     return linux_make_corefile_notes (gdbarch, obfd, note_size,
Index: gdb/gdb/s390-tdep.c
===================================================================
--- gdb.orig/gdb/s390-tdep.c
+++ gdb/gdb/s390-tdep.c
@@ -80,6 +80,9 @@ struct gdbarch_tdep
 
   const struct regset *fpregset;
   int sizeof_fpregset;
+
+  int have_linux_v1;
+  int have_linux_v2;
 };
 
 
@@ -669,83 +672,37 @@ static const struct regset s390_tdb_regs
   s390_collect_regset
 };
 
-static struct core_regset_section s390_linux32_regset_sections[] =
-{
-  { ".reg", s390_sizeof_gregset, "general-purpose" },
-  { ".reg2", s390_sizeof_fpregset, "floating-point" },
-  { NULL, 0}
-};
-
-static struct core_regset_section s390_linux32v1_regset_sections[] =
-{
-  { ".reg", s390_sizeof_gregset, "general-purpose" },
-  { ".reg2", s390_sizeof_fpregset, "floating-point" },
-  { ".reg-s390-last-break", 8, "s390 last-break address" },
-  { NULL, 0}
-};
-
-static struct core_regset_section s390_linux32v2_regset_sections[] =
-{
-  { ".reg", s390_sizeof_gregset, "general-purpose" },
-  { ".reg2", s390_sizeof_fpregset, "floating-point" },
-  { ".reg-s390-last-break", 8, "s390 last-break address" },
-  { ".reg-s390-system-call", 4, "s390 system-call" },
-  { NULL, 0}
-};
-
-static struct core_regset_section s390_linux64_regset_sections[] =
-{
-  { ".reg", s390_sizeof_gregset, "general-purpose" },
-  { ".reg2", s390_sizeof_fpregset, "floating-point" },
-  { ".reg-s390-high-gprs", 16*4, "s390 GPR upper halves" },
-  { NULL, 0}
-};
-
-static struct core_regset_section s390_linux64v1_regset_sections[] =
-{
-  { ".reg", s390_sizeof_gregset, "general-purpose" },
-  { ".reg2", s390_sizeof_fpregset, "floating-point" },
-  { ".reg-s390-high-gprs", 16*4, "s390 GPR upper halves" },
-  { ".reg-s390-last-break", 8, "s930 last-break address" },
-  { NULL, 0}
-};
-
-static struct core_regset_section s390_linux64v2_regset_sections[] =
-{
-  { ".reg", s390_sizeof_gregset, "general-purpose" },
-  { ".reg2", s390_sizeof_fpregset, "floating-point" },
-  { ".reg-s390-high-gprs", 16*4, "s390 GPR upper halves" },
-  { ".reg-s390-last-break", 8, "s930 last-break address" },
-  { ".reg-s390-system-call", 4, "s390 system-call" },
-  { ".reg-s390-tdb", s390_sizeof_tdbregset, "s390 TDB" },
-  { NULL, 0}
-};
-
-static struct core_regset_section s390x_linux64_regset_sections[] =
-{
-  { ".reg", s390x_sizeof_gregset, "general-purpose" },
-  { ".reg2", s390_sizeof_fpregset, "floating-point" },
-  { NULL, 0}
-};
-
-static struct core_regset_section s390x_linux64v1_regset_sections[] =
-{
-  { ".reg", s390x_sizeof_gregset, "general-purpose" },
-  { ".reg2", s390_sizeof_fpregset, "floating-point" },
-  { ".reg-s390-last-break", 8, "s930 last-break address" },
-  { NULL, 0}
-};
-
-static struct core_regset_section s390x_linux64v2_regset_sections[] =
+/* Iterate over supported core file register note sections. */
+static void
+s390_iterate_over_regset_sections (struct gdbarch *gdbarch,
+				   iterate_over_regset_sections_cb *cb,
+				   void *cb_data,
+				   const struct regcache *regcache)
 {
-  { ".reg", s390x_sizeof_gregset, "general-purpose" },
-  { ".reg2", s390_sizeof_fpregset, "floating-point" },
-  { ".reg-s390-last-break", 8, "s930 last-break address" },
-  { ".reg-s390-system-call", 4, "s390 system-call" },
-  { ".reg-s390-tdb", s390_sizeof_tdbregset, "s390 TDB" },
-  { NULL, 0}
-};
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int is_32_bit = tdep->abi == ABI_LINUX_S390 && tdep->gpr_full_regnum == -1;
 
+  if ((*cb) (".reg", is_32_bit ? s390_sizeof_gregset : s390x_sizeof_gregset,
+	     "general-purpose", cb_data))
+    return;
+  if ((*cb) (".reg2", s390_sizeof_fpregset, "floating-point", cb_data))
+    return;
+  if (tdep->abi == ABI_LINUX_S390 && tdep->gpr_full_regnum != -1)
+    if ((*cb) (".reg-s390-high-gprs", 16*4, "s390 GPR upper halves", cb_data))
+      return;
+  if (tdep->have_linux_v1)
+    if ((*cb) (".reg-s390-last-break", 8, "s930 last-break address", cb_data))
+      return;
+  if (tdep->have_linux_v2)
+    {
+      if ((*cb) (".reg-s390-system-call", 4, "s390 system-call", cb_data))
+	return;
+      if (regcache == NULL
+	  || REG_VALID == regcache_register_status (regcache,
+						    S390_TDB_DWORD0_REGNUM))
+	(*cb) (".reg-s390-tdb", s390_sizeof_tdbregset, "s390 TDB", cb_data);
+    }
+}
 
 /* Return the appropriate register set for the core section identified
    by SECT_NAME and SECT_SIZE.  */
@@ -3151,20 +3108,23 @@ s390_gdbarch_init (struct gdbarch_info i
        arches = gdbarch_list_lookup_by_info (arches->next, &info))
     {
       tdep = gdbarch_tdep (arches->gdbarch);
-      if (!tdep)
-	continue;
-      if (tdep->abi != tdep_abi)
-	continue;
-      if ((tdep->gpr_full_regnum != -1) != have_upper)
-	continue;
-      if (tdesc_data != NULL)
-	tdesc_data_cleanup (tdesc_data);
-      return arches->gdbarch;
+      if (tdep
+	  && tdep->abi == tdep_abi
+	  && (tdep->gpr_full_regnum != -1) == have_upper
+	  && tdep->have_linux_v1 == have_linux_v1
+	  && tdep->have_linux_v2 == have_linux_v2)
+	{
+	  if (tdesc_data != NULL)
+	    tdesc_data_cleanup (tdesc_data);
+	  return arches->gdbarch;
+	}
     }
 
   /* Otherwise create a new gdbarch for the specified machine type.  */
   tdep = XCALLOC (1, struct gdbarch_tdep);
   tdep->abi = tdep_abi;
+  tdep->have_linux_v1 = have_linux_v1;
+  tdep->have_linux_v2 = have_linux_v2;
   gdbarch = gdbarch_alloc (&info, tdep);
 
   set_gdbarch_believe_pcc_promotion (gdbarch, 0);
@@ -3195,6 +3155,8 @@ s390_gdbarch_init (struct gdbarch_info i
   set_gdbarch_regset_from_core_section (gdbarch,
                                         s390_regset_from_core_section);
   set_gdbarch_core_read_description (gdbarch, s390_core_read_description);
+  set_gdbarch_iterate_over_regset_sections (gdbarch,
+					    s390_iterate_over_regset_sections);
   set_gdbarch_cannot_store_register (gdbarch, s390_cannot_store_register);
   set_gdbarch_write_pc (gdbarch, s390_write_pc);
   set_gdbarch_pseudo_register_read (gdbarch, s390_pseudo_register_read);
@@ -3262,31 +3224,6 @@ s390_gdbarch_init (struct gdbarch_info i
       set_gdbarch_addr_bits_remove (gdbarch, s390_addr_bits_remove);
       set_solib_svr4_fetch_link_map_offsets
 	(gdbarch, svr4_ilp32_fetch_link_map_offsets);
-
-      if (have_upper)
-	{
-	  if (have_linux_v2)
-	    set_gdbarch_core_regset_sections (gdbarch,
-					      s390_linux64v2_regset_sections);
-	  else if (have_linux_v1)
-	    set_gdbarch_core_regset_sections (gdbarch,
-					      s390_linux64v1_regset_sections);
-	  else
-	    set_gdbarch_core_regset_sections (gdbarch,
-					      s390_linux64_regset_sections);
-	}
-      else
-	{
-	  if (have_linux_v2)
-	    set_gdbarch_core_regset_sections (gdbarch,
-					      s390_linux32v2_regset_sections);
-	  else if (have_linux_v1)
-	    set_gdbarch_core_regset_sections (gdbarch,
-					      s390_linux32v1_regset_sections);
-	  else
-	    set_gdbarch_core_regset_sections (gdbarch,
-					      s390_linux32_regset_sections);
-	}
       break;
 
     case ABI_LINUX_ZSERIES:
@@ -3306,16 +3243,6 @@ s390_gdbarch_init (struct gdbarch_info i
                                                     s390_address_class_type_flags_to_name);
       set_gdbarch_address_class_name_to_type_flags (gdbarch,
                                                     s390_address_class_name_to_type_flags);
-
-      if (have_linux_v2)
-	set_gdbarch_core_regset_sections (gdbarch,
-					  s390x_linux64v2_regset_sections);
-      else if (have_linux_v1)
-	set_gdbarch_core_regset_sections (gdbarch,
-					  s390x_linux64v1_regset_sections);
-      else
-	set_gdbarch_core_regset_sections (gdbarch,
-					  s390x_linux64_regset_sections);
       break;
     }
 
Index: gdb/gdb/gdbarch.c
===================================================================
--- gdb.orig/gdb/gdbarch.c
+++ gdb/gdb/gdbarch.c
@@ -236,7 +236,7 @@ struct gdbarch
   gdbarch_register_reggroup_p_ftype *register_reggroup_p;
   gdbarch_fetch_pointer_argument_ftype *fetch_pointer_argument;
   gdbarch_regset_from_core_section_ftype *regset_from_core_section;
-  struct core_regset_section * core_regset_sections;
+  gdbarch_iterate_over_regset_sections_ftype *iterate_over_regset_sections;
   gdbarch_make_corefile_notes_ftype *make_corefile_notes;
   gdbarch_elfcore_write_linux_prpsinfo_ftype *elfcore_write_linux_prpsinfo;
   gdbarch_find_memory_regions_ftype *find_memory_regions;
@@ -407,7 +407,7 @@ struct gdbarch startup_gdbarch =
   default_register_reggroup_p,  /* register_reggroup_p */
   0,  /* fetch_pointer_argument */
   0,  /* regset_from_core_section */
-  0,  /* core_regset_sections */
+  0,  /* iterate_over_regset_sections */
   0,  /* make_corefile_notes */
   0,  /* elfcore_write_linux_prpsinfo */
   0,  /* find_memory_regions */
@@ -710,6 +710,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of register_reggroup_p, invalid_p == 0 */
   /* Skip verify of fetch_pointer_argument, has predicate.  */
   /* Skip verify of regset_from_core_section, has predicate.  */
+  /* Skip verify of iterate_over_regset_sections, has predicate.  */
   /* Skip verify of make_corefile_notes, has predicate.  */
   /* Skip verify of elfcore_write_linux_prpsinfo, has predicate.  */
   /* Skip verify of find_memory_regions, has predicate.  */
@@ -895,9 +896,6 @@ gdbarch_dump (struct gdbarch *gdbarch, s
                       "gdbarch_dump: core_read_description = <%s>\n",
                       host_address_to_string (gdbarch->core_read_description));
   fprintf_unfiltered (file,
-                      "gdbarch_dump: core_regset_sections = %s\n",
-                      host_address_to_string (gdbarch->core_regset_sections));
-  fprintf_unfiltered (file,
                       "gdbarch_dump: gdbarch_core_xfer_shared_libraries_p() = %d\n",
                       gdbarch_core_xfer_shared_libraries_p (gdbarch));
   fprintf_unfiltered (file,
@@ -1093,6 +1091,12 @@ gdbarch_dump (struct gdbarch *gdbarch, s
                       "gdbarch_dump: iterate_over_objfiles_in_search_order = <%s>\n",
                       host_address_to_string (gdbarch->iterate_over_objfiles_in_search_order));
   fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_iterate_over_regset_sections_p() = %d\n",
+                      gdbarch_iterate_over_regset_sections_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: iterate_over_regset_sections = <%s>\n",
+                      host_address_to_string (gdbarch->iterate_over_regset_sections));
+  fprintf_unfiltered (file,
                       "gdbarch_dump: long_bit = %s\n",
                       plongest (gdbarch->long_bit));
   fprintf_unfiltered (file,
@@ -3336,20 +3340,28 @@ set_gdbarch_regset_from_core_section (st
   gdbarch->regset_from_core_section = regset_from_core_section;
 }
 
-struct core_regset_section *
-gdbarch_core_regset_sections (struct gdbarch *gdbarch)
+int
+gdbarch_iterate_over_regset_sections_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->iterate_over_regset_sections != NULL;
+}
+
+void
+gdbarch_iterate_over_regset_sections (struct gdbarch *gdbarch, iterate_over_regset_sections_cb *cb, void *cb_data, const struct regcache *regcache)
 {
   gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->iterate_over_regset_sections != NULL);
   if (gdbarch_debug >= 2)
-    fprintf_unfiltered (gdb_stdlog, "gdbarch_core_regset_sections called\n");
-  return gdbarch->core_regset_sections;
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_iterate_over_regset_sections called\n");
+  gdbarch->iterate_over_regset_sections (gdbarch, cb, cb_data, regcache);
 }
 
 void
-set_gdbarch_core_regset_sections (struct gdbarch *gdbarch,
-                                  struct core_regset_section * core_regset_sections)
+set_gdbarch_iterate_over_regset_sections (struct gdbarch *gdbarch,
+                                          gdbarch_iterate_over_regset_sections_ftype iterate_over_regset_sections)
 {
-  gdbarch->core_regset_sections = core_regset_sections;
+  gdbarch->iterate_over_regset_sections = iterate_over_regset_sections;
 }
 
 int
Index: gdb/gdb/gdbarch.h
===================================================================
--- gdb.orig/gdb/gdbarch.h
+++ gdb/gdb/gdbarch.h
@@ -85,6 +85,9 @@ extern struct gdbarch startup_gdbarch;
 typedef int (iterate_over_objfiles_in_search_order_cb_ftype)
   (struct objfile *objfile, void *cb_data);
 
+typedef int (iterate_over_regset_sections_cb)
+  (const char *sect_name, int size, const char *human_name, void *cb_data);
+
 
 /* The following are pre-initialized by GDBARCH.  */
 
@@ -724,10 +727,18 @@ typedef const struct regset * (gdbarch_r
 extern const struct regset * gdbarch_regset_from_core_section (struct gdbarch *gdbarch, const char *sect_name, size_t sect_size);
 extern void set_gdbarch_regset_from_core_section (struct gdbarch *gdbarch, gdbarch_regset_from_core_section_ftype *regset_from_core_section);
 
-/* Supported register notes in a core file. */
-
-extern struct core_regset_section * gdbarch_core_regset_sections (struct gdbarch *gdbarch);
-extern void set_gdbarch_core_regset_sections (struct gdbarch *gdbarch, struct core_regset_section * core_regset_sections);
+/* Iterate over all supported register notes in a core file.  For each
+   supported register note section, the iterator must call CB and pass
+   CB_DATA unchanged.  If CB returns non-zero, the iterator must stop.
+   If REGCACHE is not NULL, the iterator can limit the supported
+   register note sections based on the current register values.
+   Otherwise it should enumerate all supported register note sections. */
+
+extern int gdbarch_iterate_over_regset_sections_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_iterate_over_regset_sections_ftype) (struct gdbarch *gdbarch, iterate_over_regset_sections_cb *cb, void *cb_data, const struct regcache *regcache);
+extern void gdbarch_iterate_over_regset_sections (struct gdbarch *gdbarch, iterate_over_regset_sections_cb *cb, void *cb_data, const struct regcache *regcache);
+extern void set_gdbarch_iterate_over_regset_sections (struct gdbarch *gdbarch, gdbarch_iterate_over_regset_sections_ftype *iterate_over_regset_sections);
 
 /* Create core file notes */
 
Index: gdb/gdb/arm-linux-tdep.c
===================================================================
--- gdb.orig/gdb/arm-linux-tdep.c
+++ gdb/gdb/arm-linux-tdep.c
@@ -724,21 +724,25 @@ arm_linux_regset_from_core_section (stru
   return NULL;
 }
 
-/* Core file register set sections.  */
+/* Iterate over core file register note sections.  */
 
-static struct core_regset_section arm_linux_fpa_regset_sections[] =
+static void
+arm_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
+					iterate_over_regset_sections_cb *cb,
+					void *cb_data,
+					const struct regcache *regcache)
 {
-  { ".reg", ARM_LINUX_SIZEOF_GREGSET, "general-purpose" },
-  { ".reg2", ARM_LINUX_SIZEOF_NWFPE, "FPA floating-point" },
-  { NULL, 0}
-};
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-static struct core_regset_section arm_linux_vfp_regset_sections[] =
-{
-  { ".reg", ARM_LINUX_SIZEOF_GREGSET, "general-purpose" },
-  { ".reg-arm-vfp", ARM_LINUX_SIZEOF_VFP, "VFP floating-point" },
-  { NULL, 0}
-};
+  if ((*cb) (".reg", ARM_LINUX_SIZEOF_GREGSET, "general-purpose", cb_data))
+    return;
+
+  if (tdep->have_vfp_registers)
+    (*cb) (".reg-arm-vfp", ARM_LINUX_SIZEOF_VFP, "VFP floating-point",
+	  cb_data);
+  else if (tdep->have_fpa_registers)
+    (*cb) (".reg2", ARM_LINUX_SIZEOF_NWFPE, "FPA floating-point", cb_data);
+}
 
 /* Determine target description from core file.  */
 
@@ -1262,13 +1266,10 @@ arm_linux_init_abi (struct gdbarch_info
   /* Core file support.  */
   set_gdbarch_regset_from_core_section (gdbarch,
 					arm_linux_regset_from_core_section);
+  set_gdbarch_iterate_over_regset_sections
+    (gdbarch, arm_linux_iterate_over_regset_sections);
   set_gdbarch_core_read_description (gdbarch, arm_linux_core_read_description);
 
-  if (tdep->have_vfp_registers)
-    set_gdbarch_core_regset_sections (gdbarch, arm_linux_vfp_regset_sections);
-  else if (tdep->have_fpa_registers)
-    set_gdbarch_core_regset_sections (gdbarch, arm_linux_fpa_regset_sections);
-
   set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
 
   /* Displaced stepping.  */
Index: gdb/gdb/regset.h
===================================================================
--- gdb.orig/gdb/regset.h
+++ gdb/gdb/regset.h
@@ -23,14 +23,6 @@
 struct gdbarch;
 struct regcache;
 
-/* Data structure for the supported register notes in a core file.  */
-struct core_regset_section
-{
-  const char *sect_name;
-  int size;
-  const char *human_name;
-};
-
 /* Data structure describing a register set.  */
 
 typedef void (supply_regset_ftype) (const struct regset *, struct regcache *,
Index: gdb/gdb/i386-linux-tdep.c
===================================================================
--- gdb.orig/gdb/i386-linux-tdep.c
+++ gdb/gdb/i386-linux-tdep.c
@@ -52,27 +52,27 @@
 #include "features/i386/i386-mmx-linux.c"
 #include "features/i386/i386-avx-linux.c"
 
-/* Supported register note sections.  */
-static struct core_regset_section i386_linux_regset_sections[] =
-{
-  { ".reg", 68, "general-purpose" },
-  { ".reg2", 108, "floating-point" },
-  { NULL, 0 }
-};
+/* Iterate over core file register note sections.  */
 
-static struct core_regset_section i386_linux_sse_regset_sections[] =
+static void
+i386_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
+					 iterate_over_regset_sections_cb *cb,
+					 void *cb_data,
+					 const struct regcache *regcache)
 {
-  { ".reg", 68, "general-purpose" },
-  { ".reg-xfp", 512, "extended floating-point" },
-  { NULL, 0 }
-};
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-static struct core_regset_section i386_linux_avx_regset_sections[] =
-{
-  { ".reg", 68, "general-purpose" },
-  { ".reg-xstate", I386_XSTATE_MAX_SIZE, "XSAVE extended state" },
-  { NULL, 0 }
-};
+  if ((*cb) (".reg", 68, "general-purpose", cb_data))
+    return;
+
+  if (tdep->xstateregset)
+    (*cb) (".reg-xstate", I386_XSTATE_MAX_SIZE, "XSAVE extended state",
+	   cb_data);
+  else if (I387_NUM_XMM_REGS (tdep))
+    (*cb) (".reg-xfp", 512, "extended floating-point", cb_data);
+  else
+    (*cb) (".reg2", 108, "floating-point", cb_data);
+}
 
 /* Return non-zero, when the register is in the corresponding register
    group.  Put the LINUX_ORIG_EAX register in the system group.  */
@@ -939,14 +939,9 @@ i386_linux_init_abi (struct gdbarch_info
   set_gdbarch_fetch_tls_load_module_address (gdbarch,
                                              svr4_fetch_objfile_link_map);
 
-  /* Install supported register note sections.  */
-  if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.avx"))
-    set_gdbarch_core_regset_sections (gdbarch, i386_linux_avx_regset_sections);
-  else if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.sse"))
-    set_gdbarch_core_regset_sections (gdbarch, i386_linux_sse_regset_sections);
-  else
-    set_gdbarch_core_regset_sections (gdbarch, i386_linux_regset_sections);
-
+  /* Core file support.  */
+  set_gdbarch_iterate_over_regset_sections
+    (gdbarch, i386_linux_iterate_over_regset_sections);
   set_gdbarch_core_read_description (gdbarch,
 				     i386_linux_core_read_description);
 
Index: gdb/gdb/ppc-linux-tdep.c
===================================================================
--- gdb.orig/gdb/ppc-linux-tdep.c
+++ gdb/gdb/ppc-linux-tdep.c
@@ -256,53 +256,26 @@ ppc_linux_return_value (struct gdbarch *
 				      readbuf, writebuf);
 }
 
-static struct core_regset_section ppc_linux_vsx_regset_sections[] =
-{
-  { ".reg", 48 * 4, "general-purpose" },
-  { ".reg2", 264, "floating-point" },
-  { ".reg-ppc-vmx", 544, "ppc Altivec" },
-  { ".reg-ppc-vsx", 256, "POWER7 VSX" },
-  { NULL, 0}
-};
-
-static struct core_regset_section ppc_linux_vmx_regset_sections[] =
-{
-  { ".reg", 48 * 4, "general-purpose" },
-  { ".reg2", 264, "floating-point" },
-  { ".reg-ppc-vmx", 544, "ppc Altivec" },
-  { NULL, 0}
-};
-
-static struct core_regset_section ppc_linux_fp_regset_sections[] =
-{
-  { ".reg", 48 * 4, "general-purpose" },
-  { ".reg2", 264, "floating-point" },
-  { NULL, 0}
-};
-
-static struct core_regset_section ppc64_linux_vsx_regset_sections[] =
-{
-  { ".reg", 48 * 8, "general-purpose" },
-  { ".reg2", 264, "floating-point" },
-  { ".reg-ppc-vmx", 544, "ppc Altivec" },
-  { ".reg-ppc-vsx", 256, "POWER7 VSX" },
-  { NULL, 0}
-};
-
-static struct core_regset_section ppc64_linux_vmx_regset_sections[] =
+static void
+ppc_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
+					 iterate_over_regset_sections_cb *cb,
+					 void *cb_data,
+					 const struct regcache *regcache)
 {
-  { ".reg", 48 * 8, "general-purpose" },
-  { ".reg2", 264, "floating-point" },
-  { ".reg-ppc-vmx", 544, "ppc Altivec" },
-  { NULL, 0}
-};
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int have_vsx = tdep->ppc_vr0_regnum != -1;
+  int have_altivec = tdep->ppc_vsr0_upper_regnum != -1;
 
-static struct core_regset_section ppc64_linux_fp_regset_sections[] =
-{
-  { ".reg", 48 * 8, "general-purpose" },
-  { ".reg2", 264, "floating-point" },
-  { NULL, 0}
-};
+  if ((*cb) (".reg", 48 * 4, "general-purpose", cb_data))
+    return;
+  if ((*cb) (".reg2", 264, "floating-point", cb_data))
+    return;
+  if (have_altivec)
+    if ((*cb) (".reg-ppc-vmx", 544, "ppc Altivec", cb_data))
+      return;
+  if (have_vsx)
+    (*cb) (".reg-ppc-vsx", 256, "POWER7 VSX", cb_data);
+}
 
 /* PLT stub in executable.  */
 static struct ppc_insn_pattern powerpc32_plt_stub[] =
@@ -1305,18 +1278,9 @@ ppc_linux_init_abi (struct gdbarch_info
       else
 	set_gdbarch_gcore_bfd_target (gdbarch, "elf32-powerpc");
 
-      /* Supported register sections.  */
-      if (tdesc_find_feature (info.target_desc,
-			      "org.gnu.gdb.power.vsx"))
-	set_gdbarch_core_regset_sections (gdbarch,
-					  ppc_linux_vsx_regset_sections);
-      else if (tdesc_find_feature (info.target_desc,
-			       "org.gnu.gdb.power.altivec"))
-	set_gdbarch_core_regset_sections (gdbarch,
-					  ppc_linux_vmx_regset_sections);
-      else
-	set_gdbarch_core_regset_sections (gdbarch,
-					  ppc_linux_fp_regset_sections);
+      /* Iterator for supported register sections.  */
+      set_gdbarch_iterate_over_regset_sections
+	(gdbarch, ppc_linux_iterate_over_regset_sections);
 
       if (powerpc_so_ops.in_dynsym_resolve_code == NULL)
 	{
@@ -1360,18 +1324,9 @@ ppc_linux_init_abi (struct gdbarch_info
       else
 	set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpc");
 
-      /* Supported register sections.  */
-      if (tdesc_find_feature (info.target_desc,
-			      "org.gnu.gdb.power.vsx"))
-	set_gdbarch_core_regset_sections (gdbarch,
-					  ppc64_linux_vsx_regset_sections);
-      else if (tdesc_find_feature (info.target_desc,
-			       "org.gnu.gdb.power.altivec"))
-	set_gdbarch_core_regset_sections (gdbarch,
-					  ppc64_linux_vmx_regset_sections);
-      else
-	set_gdbarch_core_regset_sections (gdbarch,
-					  ppc64_linux_fp_regset_sections);
+      /* Iterator for supported register sections.  */
+      set_gdbarch_iterate_over_regset_sections
+	(gdbarch, ppc_linux_iterate_over_regset_sections);
     }
 
   /* PPC32 uses a different prpsinfo32 compared to most other Linux
Index: gdb/gdb/amd64-linux-tdep.c
===================================================================
--- gdb.orig/gdb/amd64-linux-tdep.c
+++ gdb/gdb/amd64-linux-tdep.c
@@ -51,15 +51,6 @@
 #include "record-full.h"
 #include "linux-record.h"
 
-/* Supported register note sections.  */
-static struct core_regset_section amd64_linux_regset_sections[] =
-{
-  { ".reg", 27 * 8, "general-purpose" },
-  { ".reg2", 512, "floating-point" },
-  { ".reg-xstate", I386_XSTATE_MAX_SIZE, "XSAVE extended state" },
-  { NULL, 0 }
-};
-
 /* Mapping between the general-purpose registers in `struct user'
    format and GDB's register cache layout.  */
 
@@ -1278,6 +1269,23 @@ amd64_linux_record_signal (struct gdbarc
   return 0;
 }
 
+/* Iterate over supported core file register note sections.  */
+
+static void
+amd64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
+					  iterate_over_regset_sections_cb *cb,
+					  void *cb_data,
+					  const struct regcache *regcache)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if ((*cb) (".reg", 27 * 8, "general-purpose", cb_data))
+    return;
+  if ((*cb) (".reg2", 512, "floating-point", cb_data))
+    return;
+  (*cb) (".reg-xstate", I386_XSTATE_MAX_SIZE, "XSAVE extended state", cb_data);
+}
+
 /* Get Linux/x86 target description from core dump.  */
 
 static const struct target_desc *
@@ -1336,9 +1344,9 @@ amd64_linux_init_abi_common(struct gdbar
   /* GNU/Linux uses the dynamic linker included in the GNU C Library.  */
   set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
 
-  /* Install supported register note sections.  */
-  set_gdbarch_core_regset_sections (gdbarch, amd64_linux_regset_sections);
-
+  /* Core file support.  */
+  set_gdbarch_iterate_over_regset_sections
+    (gdbarch, amd64_linux_iterate_over_regset_sections);
   set_gdbarch_core_read_description (gdbarch,
 				     amd64_linux_core_read_description);
 
Index: gdb/gdb/corelow.c
===================================================================
--- gdb.orig/gdb/corelow.c
+++ gdb/gdb/corelow.c
@@ -547,6 +547,24 @@ get_core_register_section (struct regcac
 				  bfd_section_vma (core_bfd, section)));
 }
 
+/* Callback for get_core_registers that handles a single core file
+   register note section. */
+
+static int
+get_core_registers_cb (const char *sect_name, int size,
+		       const char *human_name, void *cb_data)
+{
+  struct regcache *regcache = (struct regcache *) cb_data;
+
+  if (strcmp (sect_name, ".reg") == 0)
+    get_core_register_section (regcache, sect_name, 0, human_name, 1);
+  else if (strcmp (sect_name, ".reg2") == 0)
+    get_core_register_section (regcache, sect_name, 2, human_name, 0);
+  else
+    get_core_register_section (regcache, sect_name, 3, human_name, 0);
+
+  return 0;
+}
 
 /* Get the registers out of a core file.  This is the machine-
    independent part.  Fetch_core_registers is the machine-dependent
@@ -559,8 +577,8 @@ static void
 get_core_registers (struct target_ops *ops,
 		    struct regcache *regcache, int regno)
 {
-  struct core_regset_section *sect_list;
   int i;
+  struct gdbarch *gdbarch;
 
   if (!(core_gdbarch && gdbarch_regset_from_core_section_p (core_gdbarch))
       && (core_vec == NULL || core_vec->core_read_registers == NULL))
@@ -570,23 +588,11 @@ get_core_registers (struct target_ops *o
       return;
     }
 
-  sect_list = gdbarch_core_regset_sections (get_regcache_arch (regcache));
-  if (sect_list)
-    while (sect_list->sect_name != NULL)
-      {
-        if (strcmp (sect_list->sect_name, ".reg") == 0)
-	  get_core_register_section (regcache, sect_list->sect_name,
-				     0, sect_list->human_name, 1);
-        else if (strcmp (sect_list->sect_name, ".reg2") == 0)
-	  get_core_register_section (regcache, sect_list->sect_name,
-				     2, sect_list->human_name, 0);
-	else
-	  get_core_register_section (regcache, sect_list->sect_name,
-				     3, sect_list->human_name, 0);
-
-	sect_list++;
-      }
-
+  gdbarch = get_regcache_arch (regcache);
+  if (gdbarch_iterate_over_regset_sections_p (gdbarch))
+    gdbarch_iterate_over_regset_sections (gdbarch,
+					  get_core_registers_cb,
+					  (void *) regcache, NULL);
   else
     {
       get_core_register_section (regcache,

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 3/3] Dynamic core regset sections support
  2013-06-07 13:53 ` [PATCH 3/3] Dynamic core regset sections support Andreas Arnez
@ 2013-06-07 14:43   ` Luis Machado
  2013-06-07 16:40     ` Andreas Arnez
  0 siblings, 1 reply; 15+ messages in thread
From: Luis Machado @ 2013-06-07 14:43 UTC (permalink / raw)
  To: Andreas Arnez; +Cc: gdb-patches, Ulrich Weigand

H Andreas,

Thanks for the patch.

Just a general thought. If a core file section must not always be 
generated, would it make more sense to use dynamic section information 
for s390 instead of forcing all the other targets to use a mechanism 
that is not required for them?

I'm not necessarily against this modification, but i was wondering about 
other options.

See comments below...

 > Index: gdb/gdb/ppc-linux-tdep.c
> ===================================================================
> --- gdb.orig/gdb/ppc-linux-tdep.c
> +++ gdb/gdb/ppc-linux-tdep.c
> @@ -256,53 +256,26 @@ ppc_linux_return_value (struct gdbarch *
>   				      readbuf, writebuf);
>   }
>
> -static struct core_regset_section ppc_linux_vsx_regset_sections[] =
> -{
> -  { ".reg", 48 * 4, "general-purpose" },
> -  { ".reg2", 264, "floating-point" },
> -  { ".reg-ppc-vmx", 544, "ppc Altivec" },
> -  { ".reg-ppc-vsx", 256, "POWER7 VSX" },
> -  { NULL, 0}
> -};
> -
> -static struct core_regset_section ppc_linux_vmx_regset_sections[] =
> -{
> -  { ".reg", 48 * 4, "general-purpose" },
> -  { ".reg2", 264, "floating-point" },
> -  { ".reg-ppc-vmx", 544, "ppc Altivec" },
> -  { NULL, 0}
> -};
> -
> -static struct core_regset_section ppc_linux_fp_regset_sections[] =
> -{
> -  { ".reg", 48 * 4, "general-purpose" },
> -  { ".reg2", 264, "floating-point" },
> -  { NULL, 0}
> -};
> -
> -static struct core_regset_section ppc64_linux_vsx_regset_sections[] =
> -{
> -  { ".reg", 48 * 8, "general-purpose" },
> -  { ".reg2", 264, "floating-point" },
> -  { ".reg-ppc-vmx", 544, "ppc Altivec" },
> -  { ".reg-ppc-vsx", 256, "POWER7 VSX" },
> -  { NULL, 0}
> -};
> -
> -static struct core_regset_section ppc64_linux_vmx_regset_sections[] =
> +static void
> +ppc_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
> +					 iterate_over_regset_sections_cb *cb,
> +					 void *cb_data,
> +					 const struct regcache *regcache)
>   {
> -  { ".reg", 48 * 8, "general-purpose" },
> -  { ".reg2", 264, "floating-point" },
> -  { ".reg-ppc-vmx", 544, "ppc Altivec" },
> -  { NULL, 0}
> -};
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +  int have_vsx = tdep->ppc_vr0_regnum != -1;
> +  int have_altivec = tdep->ppc_vsr0_upper_regnum != -1;
>
> -static struct core_regset_section ppc64_linux_fp_regset_sections[] =
> -{
> -  { ".reg", 48 * 8, "general-purpose" },
> -  { ".reg2", 264, "floating-point" },
> -  { NULL, 0}
> -};
> +  if ((*cb) (".reg", 48 * 4, "general-purpose", cb_data))
> +    return;
> +  if ((*cb) (".reg2", 264, "floating-point", cb_data))
> +    return;
> +  if (have_altivec)
> +    if ((*cb) (".reg-ppc-vmx", 544, "ppc Altivec", cb_data))
> +      return;
> +  if (have_vsx)
> +    (*cb) (".reg-ppc-vsx", 256, "POWER7 VSX", cb_data);
> +}
>
>   /* PLT stub in executable.  */
>   static struct ppc_insn_pattern powerpc32_plt_stub[] =
> @@ -1305,18 +1278,9 @@ ppc_linux_init_abi (struct gdbarch_info
>         else
>   	set_gdbarch_gcore_bfd_target (gdbarch, "elf32-powerpc");
>
> -      /* Supported register sections.  */
> -      if (tdesc_find_feature (info.target_desc,
> -			      "org.gnu.gdb.power.vsx"))
> -	set_gdbarch_core_regset_sections (gdbarch,
> -					  ppc_linux_vsx_regset_sections);
> -      else if (tdesc_find_feature (info.target_desc,
> -			       "org.gnu.gdb.power.altivec"))
> -	set_gdbarch_core_regset_sections (gdbarch,
> -					  ppc_linux_vmx_regset_sections);
> -      else
> -	set_gdbarch_core_regset_sections (gdbarch,
> -					  ppc_linux_fp_regset_sections);
> +      /* Iterator for supported register sections.  */
> +      set_gdbarch_iterate_over_regset_sections
> +	(gdbarch, ppc_linux_iterate_over_regset_sections);
>
>         if (powerpc_so_ops.in_dynsym_resolve_code == NULL)
>   	{
> @@ -1360,18 +1324,9 @@ ppc_linux_init_abi (struct gdbarch_info
>         else
>   	set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpc");
>
> -      /* Supported register sections.  */
> -      if (tdesc_find_feature (info.target_desc,
> -			      "org.gnu.gdb.power.vsx"))
> -	set_gdbarch_core_regset_sections (gdbarch,
> -					  ppc64_linux_vsx_regset_sections);
> -      else if (tdesc_find_feature (info.target_desc,
> -			       "org.gnu.gdb.power.altivec"))
> -	set_gdbarch_core_regset_sections (gdbarch,
> -					  ppc64_linux_vmx_regset_sections);
> -      else
> -	set_gdbarch_core_regset_sections (gdbarch,
> -					  ppc64_linux_fp_regset_sections);
> +      /* Iterator for supported register sections.  */
> +      set_gdbarch_iterate_over_regset_sections
> +	(gdbarch, ppc_linux_iterate_over_regset_sections);
>       }
>
>     /* PPC32 uses a different prpsinfo32 compared to most other Linux


I am commenting explicitly for the ppc bits, but this may apply to the 
other backends as well.

Did you maybe forget to handle ppc64 core file sections in this change? 
I see a core file register set entry for ppc64 being removed, like so:

-  { ".reg", 48 * 8, "general-purpose" },

... but it is not being checked by the new code. Though the name is the 
same, the size of the section is different compared to ppc32.

-  { ".reg", 48 * 4, "general-purpose" },

Another general comment/suggestion. Removing static definitions of core 
file register sets and replacing them with hardcoded arguments for a 
pointer-based call to a callback function seems to scramble/confuse 
things a little.

It may be nicer to keep the static definitions around, but iterate 
through them in the new iterator function. What do you think?

Regards,
Luis

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA/RFT PATCH 0/3] Add TDB regset support
  2013-06-07 13:44 [RFA/RFT PATCH 0/3] Add TDB regset support Andreas Arnez
                   ` (2 preceding siblings ...)
  2013-06-07 13:53 ` [PATCH 3/3] Dynamic core regset sections support Andreas Arnez
@ 2013-06-07 15:03 ` Pedro Alves
  2013-06-07 15:59   ` Andreas Arnez
  3 siblings, 1 reply; 15+ messages in thread
From: Pedro Alves @ 2013-06-07 15:03 UTC (permalink / raw)
  To: Andreas Arnez; +Cc: gdb-patches, Ulrich Weigand

On 06/07/2013 02:44 PM, Andreas Arnez wrote:
> The new z/Architecture introduces restricted hardware transactional
> memory with the "transactional-execution facility".  Diagnostic
> capabilities of this feature include the "program interruption
> transaction diagnostic block" (TDB), which is written by the hardware
> whenever a transaction is aborted due to a program interruption.
> 
> This patch set makes the TDB accessible from GDB as a new register set.
> The first patch reworks the S/390 register map handling without any
> functional changes, the second adds the new TDB register set, and the
> third implements "dynamic regset" support.
> 
> The third patch changes GDB's approach for enumerating core file
> register note sections: Instead of a static array, an iterator function
> is now provided by the target-dependent code.  This allows for
> dynamically selecting a register set for inclusion in a core file
> (written with gcore), and making the selection dependent on the current
> register values.  This is needed for correct treatment of the TDB
> register set, because its register values are unavailable when the
> inferior was interrupted outside transactions, and then the TDB should
> *not* be written into the core file.
> 
> This last patch affects multiple architectures, specifically:
> 
> - GNU/Linux ARM
> - GNU/Linux PowerPC
> - GNU/Linux S/390
> - GNU/Linux x86
> 
> In most cases the patch simplifies the target-dependent logic.  I've
> tested on S/390 and x86 and did not find any regressions.
> 

Why isn't this exposed as a new target description that includes the
new register set?

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA/RFT PATCH 0/3] Add TDB regset support
  2013-06-07 15:03 ` [RFA/RFT PATCH 0/3] Add TDB regset support Pedro Alves
@ 2013-06-07 15:59   ` Andreas Arnez
  2013-06-07 16:44     ` Pedro Alves
  0 siblings, 1 reply; 15+ messages in thread
From: Andreas Arnez @ 2013-06-07 15:59 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Ulrich Weigand

Pedro Alves <palves@redhat.com> writes:

> Why isn't this exposed as a new target description that includes the
> new register set?

It would require extracting the hardware capabilities from the core
file's auxiliary vector in order to distinguish between platforms with
and without the transactional-execution facility.  I guess it could be
done, but I didn't consider it that important.  Do you see any problems
with the current approach?

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 3/3] Dynamic core regset sections support
  2013-06-07 14:43   ` Luis Machado
@ 2013-06-07 16:40     ` Andreas Arnez
  0 siblings, 0 replies; 15+ messages in thread
From: Andreas Arnez @ 2013-06-07 16:40 UTC (permalink / raw)
  To: lgustavo; +Cc: gdb-patches, Ulrich Weigand

Luis Machado <lgustavo@codesourcery.com> writes:

> Just a general thought. If a core file section must not always be
> generated, would it make more sense to use dynamic section information
> for s390 instead of forcing all the other targets to use a mechanism
> that is not required for them?

The reason for removing the old interface was to avoid increasing the
number of gdbarch interfaces for this.  In addition, the change reduces
the amount of target-dependent code for most targets, which I consider
beneficial.

> I'm not necessarily against this modification, but i was wondering
> about other options.

Sure, I'm open for suggestions.

> Did you maybe forget to handle ppc64 core file sections in this
> change?

Phew, you're right.  I guess we can use tdep->wordsize instead, like
this (right?):

  if ((*cb) (".reg", 48 * tdep->wordsize, "general-purpose", cb_data))

It would be great if you could verify this change -- I'm providing an
updated patch below.

> Another general comment/suggestion. Removing static definitions of
> core file register sets and replacing them with hardcoded arguments
> for a pointer-based call to a callback function seems to
> scramble/confuse things a little.
>
> It may be nicer to keep the static definitions around, but iterate
> through them in the new iterator function. What do you think?

I thought about something like that as well.  However, my implementation
attempt didn't result in less (or simpler) code.

Updated patch for linux-tdep.c:

--- a/gdb/ppc-linux-tdep.c
+++ b/gdb/ppc-linux-tdep.c
@@ -256,53 +256,26 @@ ppc_linux_return_value (struct gdbarch *gdbarch, struct value *function,
 				      readbuf, writebuf);
 }
 
-static struct core_regset_section ppc_linux_vsx_regset_sections[] =
-{
-  { ".reg", 48 * 4, "general-purpose" },
-  { ".reg2", 264, "floating-point" },
-  { ".reg-ppc-vmx", 544, "ppc Altivec" },
-  { ".reg-ppc-vsx", 256, "POWER7 VSX" },
-  { NULL, 0}
-};
-
-static struct core_regset_section ppc_linux_vmx_regset_sections[] =
-{
-  { ".reg", 48 * 4, "general-purpose" },
-  { ".reg2", 264, "floating-point" },
-  { ".reg-ppc-vmx", 544, "ppc Altivec" },
-  { NULL, 0}
-};
-
-static struct core_regset_section ppc_linux_fp_regset_sections[] =
-{
-  { ".reg", 48 * 4, "general-purpose" },
-  { ".reg2", 264, "floating-point" },
-  { NULL, 0}
-};
-
-static struct core_regset_section ppc64_linux_vsx_regset_sections[] =
-{
-  { ".reg", 48 * 8, "general-purpose" },
-  { ".reg2", 264, "floating-point" },
-  { ".reg-ppc-vmx", 544, "ppc Altivec" },
-  { ".reg-ppc-vsx", 256, "POWER7 VSX" },
-  { NULL, 0}
-};
-
-static struct core_regset_section ppc64_linux_vmx_regset_sections[] =
-{
-  { ".reg", 48 * 8, "general-purpose" },
-  { ".reg2", 264, "floating-point" },
-  { ".reg-ppc-vmx", 544, "ppc Altivec" },
-  { NULL, 0}
-};
-
-static struct core_regset_section ppc64_linux_fp_regset_sections[] =
+static void
+ppc_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
+					 iterate_over_regset_sections_cb *cb,
+					 void *cb_data,
+					 const struct regcache *regcache)
 {
-  { ".reg", 48 * 8, "general-purpose" },
-  { ".reg2", 264, "floating-point" },
-  { NULL, 0}
-};
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int have_vsx = tdep->ppc_vr0_regnum != -1;
+  int have_altivec = tdep->ppc_vsr0_upper_regnum != -1;
+
+  if ((*cb) (".reg", 48 * tdep->wordsize, "general-purpose", cb_data))
+    return;
+  if ((*cb) (".reg2", 264, "floating-point", cb_data))
+    return;
+  if (have_altivec)
+    if ((*cb) (".reg-ppc-vmx", 544, "ppc Altivec", cb_data))
+      return;
+  if (have_vsx)
+    (*cb) (".reg-ppc-vsx", 256, "POWER7 VSX", cb_data);
+}
 
 /* PLT stub in executable.  */
 static struct ppc_insn_pattern powerpc32_plt_stub[] =
@@ -1305,18 +1278,9 @@ ppc_linux_init_abi (struct gdbarch_info info,
       else
 	set_gdbarch_gcore_bfd_target (gdbarch, "elf32-powerpc");
 
-      /* Supported register sections.  */
-      if (tdesc_find_feature (info.target_desc,
-			      "org.gnu.gdb.power.vsx"))
-	set_gdbarch_core_regset_sections (gdbarch,
-					  ppc_linux_vsx_regset_sections);
-      else if (tdesc_find_feature (info.target_desc,
-			       "org.gnu.gdb.power.altivec"))
-	set_gdbarch_core_regset_sections (gdbarch,
-					  ppc_linux_vmx_regset_sections);
-      else
-	set_gdbarch_core_regset_sections (gdbarch,
-					  ppc_linux_fp_regset_sections);
+      /* Iterator for supported register sections.  */
+      set_gdbarch_iterate_over_regset_sections
+	(gdbarch, ppc_linux_iterate_over_regset_sections);
 
       if (powerpc_so_ops.in_dynsym_resolve_code == NULL)
 	{
@@ -1360,18 +1324,9 @@ ppc_linux_init_abi (struct gdbarch_info info,
       else
 	set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpc");
 
-      /* Supported register sections.  */
-      if (tdesc_find_feature (info.target_desc,
-			      "org.gnu.gdb.power.vsx"))
-	set_gdbarch_core_regset_sections (gdbarch,
-					  ppc64_linux_vsx_regset_sections);
-      else if (tdesc_find_feature (info.target_desc,
-			       "org.gnu.gdb.power.altivec"))
-	set_gdbarch_core_regset_sections (gdbarch,
-					  ppc64_linux_vmx_regset_sections);
-      else
-	set_gdbarch_core_regset_sections (gdbarch,
-					  ppc64_linux_fp_regset_sections);
+      /* Iterator for supported register sections.  */
+      set_gdbarch_iterate_over_regset_sections
+	(gdbarch, ppc_linux_iterate_over_regset_sections);
     }
 
   /* PPC32 uses a different prpsinfo32 compared to most other Linux

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA/RFT PATCH 0/3] Add TDB regset support
  2013-06-07 15:59   ` Andreas Arnez
@ 2013-06-07 16:44     ` Pedro Alves
  2013-06-07 18:16       ` Andreas Arnez
  0 siblings, 1 reply; 15+ messages in thread
From: Pedro Alves @ 2013-06-07 16:44 UTC (permalink / raw)
  To: Andreas Arnez; +Cc: gdb-patches, Ulrich Weigand

On 06/07/2013 04:59 PM, Andreas Arnez wrote:
> Pedro Alves <palves@redhat.com> writes:
> 
>> Why isn't this exposed as a new target description that includes the
>> new register set?
> 
> It would require extracting the hardware capabilities from the core
> file's auxiliary vector in order to distinguish between platforms with
> and without the transactional-execution facility.  I guess it could be
> done, but I didn't consider it that important.  

You might not need to look at the auxv.  Return the right tdesc
depending on presence of bfd sections.  See ppc_linux_core_read_description.

> Do you see any problems with the current approach?

> --- gdb.orig/gdb/regformats/s390-linux64v2.dat
> +++ gdb/gdb/regformats/s390-linux64v2.dat
> @@ -72,3 +72,23 @@ expedite:r14l,r15l,pswa
>  32:orig_r2
>  32:last_break
>  32:system_call
> +64:tdb0
> +64:tac
> +64:tct
> +64:atia
> +64:tr0
> +64:tr1
> +64:tr2
> +64:tr3
> +64:tr4
> +64:tr5
> +64:tr6
> +64:tr7
> +64:tr8
> +64:tr9
> +64:tr10
> +64:tr11
> +64:tr12
> +64:tr13
> +64:tr14
> +64:tr15

If you connect a 7.6 GDB without this patch to a new GDBserver that
sends this extended regdat, I believe GDB will complain with
"Remote 'g' packet reply is too long", even if the target actually
doesn't support TDB. You should really add support for TDB to
GDBserver too, before calling all this done.

You're extending the remote register buffer with an optional feature,
and in future when another alternative register set comes along that
replaces this one, we're in trouble, as we won't be able to tell
which is which (without ugly hacks).

See how Ulrich handled this last time:

 http://sourceware.org/ml/gdb-patches/2011-12/msg00005.html

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA/RFT PATCH 0/3] Add TDB regset support
  2013-06-07 16:44     ` Pedro Alves
@ 2013-06-07 18:16       ` Andreas Arnez
  2013-06-07 19:06         ` Pedro Alves
  0 siblings, 1 reply; 15+ messages in thread
From: Andreas Arnez @ 2013-06-07 18:16 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Ulrich Weigand

Pedro Alves <palves@redhat.com> writes:

> On 06/07/2013 04:59 PM, Andreas Arnez wrote:
>> Pedro Alves <palves@redhat.com> writes:
>> 
>>> Why isn't this exposed as a new target description that includes the
>>> new register set?
>> 
>> It would require extracting the hardware capabilities from the core
>> file's auxiliary vector in order to distinguish between platforms with
>> and without the transactional-execution facility.  I guess it could be
>> done, but I didn't consider it that important.  
>
> You might not need to look at the auxv.  Return the right tdesc
> depending on presence of bfd sections.  See ppc_linux_core_read_description.

This doesn't work for the TDB, because the absence of the TDB register
section doesn't mean that the core file target didn't support it.  At
least we'd break the gcore.exp test case.

> If you connect a 7.6 GDB without this patch to a new GDBserver that
> sends this extended regdat, I believe GDB will complain with
> "Remote 'g' packet reply is too long", even if the target actually
> doesn't support TDB.

Hm, didn't realize that.  But if the target does support TDB, we'd be in
trouble either way, right?

> You're extending the remote register buffer with an optional feature,
> and in future when another alternative register set comes along that
> replaces this one, we're in trouble, as we won't be able to tell
> which is which (without ugly hacks).

Well, the patch doesn't treat TDB as an optional feature, does it?  In
the future the TDB would always be included in the target description.
Actually representing n optional register sets with different tdescs
would require 2**n tdescs, right?

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA/RFT PATCH 0/3] Add TDB regset support
  2013-06-07 18:16       ` Andreas Arnez
@ 2013-06-07 19:06         ` Pedro Alves
  2013-06-10 16:59           ` Andreas Arnez
  0 siblings, 1 reply; 15+ messages in thread
From: Pedro Alves @ 2013-06-07 19:06 UTC (permalink / raw)
  To: Andreas Arnez; +Cc: gdb-patches, Ulrich Weigand

On 06/07/2013 07:15 PM, Andreas Arnez wrote:
> Pedro Alves <palves@redhat.com> writes:
>> You might not need to look at the auxv.  Return the right tdesc
>> depending on presence of bfd sections.  See ppc_linux_core_read_description.
> 
> This doesn't work for the TDB, because the absence of the TDB register
> section doesn't mean that the core file target didn't support it.  At
> least we'd break the gcore.exp test case.

Okay.  How are the TDB registers presented to the user (info all-registers,
etc) in the current patchset when the target supports them, but the inferior
is presently interrupted outside a transaction, with live debugging?
(screenshot, please! :-))

> 
>> If you connect a 7.6 GDB without this patch to a new GDBserver that
>> sends this extended regdat, I believe GDB will complain with
>> "Remote 'g' packet reply is too long", even if the target actually
>> doesn't support TDB.
> 
> Hm, didn't realize that.  But if the target does support TDB, we'd be in
> trouble either way, right?

Right.

>> You're extending the remote register buffer with an optional feature,
>> and in future when another alternative register set comes along that
>> replaces this one, we're in trouble, as we won't be able to tell
>> which is which (without ugly hacks).
> 
> Well, the patch doesn't treat TDB as an optional feature, does it?

+      /* Transaction diagnostic block.  */
+      feature = tdesc_find_feature (tdesc, "org.gnu.gdb.s390.tdb");
+      if (feature)

That makes it optional (as it should).

+	{
+	  for (i = 0; i < ARRAY_SIZE (tdb_regs); i++)
+	    valid_p &= tdesc_numbered_register (feature, tdesc_data,
+						S390_TDB_DWORD0_REGNUM + i,
+						tdb_regs[i]);
+	}
+

The new org.gnu.gdb.s390.tdb target feature needs to be documented, btw.

http://sourceware.org/gdb/wiki/ContributionChecklist#Documentation

TDB support should be mentioned in NEWS too.

> In the future the TDB would always be included in the target description.

That's really wrong.  No reason for such a hack when we have a
proper mechanism in place.

> Actually representing n optional register sets with different tdescs
> would require 2**n tdescs, right?

With xi:include, that's really pretty manageable.  Please do
take a look at ppc_linux_read_description and at features/rs6000/,
for example, though there are several others in the tree.
The x86 port has a complex selection of proper description/register
set too, given xsave.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA/RFT PATCH 0/3] Add TDB regset support
  2013-06-07 19:06         ` Pedro Alves
@ 2013-06-10 16:59           ` Andreas Arnez
  2013-06-11 10:48             ` Pedro Alves
  0 siblings, 1 reply; 15+ messages in thread
From: Andreas Arnez @ 2013-06-10 16:59 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Ulrich Weigand

Pedro Alves <palves@redhat.com> writes:

> On 06/07/2013 07:15 PM, Andreas Arnez wrote:
>> Pedro Alves <palves@redhat.com> writes:
>>> You might not need to look at the auxv.  Return the right tdesc
>>> depending on presence of bfd sections.  See
>>> ppc_linux_core_read_description.
>> 
>> This doesn't work for the TDB, because the absence of the TDB
>> register section doesn't mean that the core file target didn't
>> support it.  At least we'd break the gcore.exp test case.
>
> Okay.  How are the TDB registers presented to the user (info
> all-registers, etc) in the current patchset when the target supports
> them, but the inferior is presently interrupted outside a transaction,
> with live debugging?  (screenshot, please! :-))

(gdb) info all-reg
pswm           0x705200180000000	505845723963588608
pswa           0x8000060a	2147485194
--- /snip/ ---
tdb0           *value not available*
tac            *value not available*
tct            *value not available*
atia           *value not available*
tr0            *value not available*
tr1            *value not available*
tr2            *value not available*
tr3            *value not available*
tr4            *value not available*
tr5            *value not available*
tr6            *value not available*
tr7            *value not available*
tr8            *value not available*
tr9            *value not available*
tr10           *value not available*
tr11           *value not available*
tr12           *value not available*
tr13           *value not available*
tr14           *value not available*
tr15           *value not available*
pc             0x8000060a	0x8000060a <terminal_func+10>
cc             0x2	2

When there's no TDB for the current inferior's state, "value not
available" is the closest representation I could find in the current
regcache design.  Or maybe there is a better way?

My assumption was that this representation is even acceptable when the
inferior runs on a target without transactional-execution support,
because there's really no difference between a program that *never uses*
transactions and a program that *can not* use transactions.

But I can certainly take a shot at an alternate version of the patch
which introduces new target descriptions "s390x-linux64v2-tx" and
"s390-linux64v2-tx" and selects one of those if the hardware supports
transactions. That's what's being proposed, right?

> The new org.gnu.gdb.s390.tdb target feature needs to be documented,
> btw.

OK, will do that in my updated patch.

> TDB support should be mentioned in NEWS too.

Will do.

> With xi:include, that's really pretty manageable.  Please do take a
> look at ppc_linux_read_description and at features/rs6000/, for
> example, though there are several others in the tree.  The x86 port
> has a complex selection of proper description/register set too, given
> xsave.

Did you want to hint at anything specific?  Or just how to add a new
tdesc in general (and select it)?

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA/RFT PATCH 0/3] Add TDB regset support
  2013-06-10 16:59           ` Andreas Arnez
@ 2013-06-11 10:48             ` Pedro Alves
  0 siblings, 0 replies; 15+ messages in thread
From: Pedro Alves @ 2013-06-11 10:48 UTC (permalink / raw)
  To: Andreas Arnez; +Cc: gdb-patches, Ulrich Weigand

On 06/10/2013 04:39 PM, Andreas Arnez wrote:
> Pedro Alves <palves@redhat.com> writes:
> 
>> On 06/07/2013 07:15 PM, Andreas Arnez wrote:
>>> Pedro Alves <palves@redhat.com> writes:
>>>> You might not need to look at the auxv.  Return the right tdesc
>>>> depending on presence of bfd sections.  See
>>>> ppc_linux_core_read_description.
>>>
>>> This doesn't work for the TDB, because the absence of the TDB
>>> register section doesn't mean that the core file target didn't
>>> support it.  At least we'd break the gcore.exp test case.
>>
>> Okay.  How are the TDB registers presented to the user (info
>> all-registers, etc) in the current patchset when the target supports
>> them, but the inferior is presently interrupted outside a transaction,
>> with live debugging?  (screenshot, please! :-))
> 
> (gdb) info all-reg
> pswm           0x705200180000000	505845723963588608
> pswa           0x8000060a	2147485194
> --- /snip/ ---
> tdb0           *value not available*
> tac            *value not available*
> tct            *value not available*
> atia           *value not available*
> tr0            *value not available*
> tr1            *value not available*
> tr2            *value not available*
> tr3            *value not available*
> tr4            *value not available*
> tr5            *value not available*
> tr6            *value not available*
> tr7            *value not available*
> tr8            *value not available*
> tr9            *value not available*
> tr10           *value not available*
> tr11           *value not available*
> tr12           *value not available*
> tr13           *value not available*
> tr14           *value not available*
> tr15           *value not available*
> pc             0x8000060a	0x8000060a <terminal_func+10>
> cc             0x2	2
> 
> When there's no TDB for the current inferior's state, "value not
> available" is the closest representation I could find in the current
> regcache design.  Or maybe there is a better way?
> 
> My assumption was that this representation is even acceptable when the
> inferior runs on a target without transactional-execution support,
> because there's really no difference between a program that *never uses*
> transactions and a program that *can not* use transactions.

It's close but not the same.  If the machine doesn't have those
registers, then they should not presented at all.

> 
> But I can certainly take a shot at an alternate version of the patch
> which introduces new target descriptions "s390x-linux64v2-tx" and
> "s390-linux64v2-tx" and selects one of those if the hardware supports
> transactions. That's what's being proposed, right?

Right.  We usually name the descriptions "CPU/PART-ABI/OS.xml",
with cpu/part number being e.g., powerpc-750 for "PowerPC 750".
but I have no idea about S/390 cpu names.  E.g., when
dsp registers get added to mips64-linux.xml, we get
mips64-dsp-linux.xml.  Maybe you should drop the v2 going forward
(I think v1/v2 made sense since the additions were Linux specific, not
a new machine), and make the new one "s390x-tx-linux64" or some other
cpu name that'd make most sense.  Or make that v3, dunno, up to you.

>> The new org.gnu.gdb.s390.tdb target feature needs to be documented,
>> btw.
> 
> OK, will do that in my updated patch.
> 
>> TDB support should be mentioned in NEWS too.
> 
> Will do.
> 
>> With xi:include, that's really pretty manageable.  Please do take a
>> look at ppc_linux_read_description and at features/rs6000/, for
>> example, though there are several others in the tree.  The x86 port
>> has a complex selection of proper description/register set too, given
>> xsave.
> 
> Did you want to hint at anything specific?

With

> Actually representing n optional register sets with different tdescs
> would require 2**n tdescs, right?

you seemed to be worried by the explosion of the number of target
descriptions.  I was pointing out at an example in the tree where
for the same general architecture family we have many target descriptions,
one per each different machine with a different set of register sets,
as an example of that not really being a problem.

> Or just how to add a new tdesc in general (and select it)?

That too.

Thanks,
-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Regression on gdb.base/checkpoint.exp on S/390 (was: Re: [PATCH 1/3] S/390 regmap rework)
  2013-06-07 13:50 ` [PATCH 1/3] S/390 regmap rework Andreas Arnez
@ 2015-05-05 19:17   ` Sergio Durigan Junior
  2015-05-06 18:16     ` Regression on gdb.base/checkpoint.exp on S/390 Andreas Arnez
  0 siblings, 1 reply; 15+ messages in thread
From: Sergio Durigan Junior @ 2015-05-05 19:17 UTC (permalink / raw)
  To: Andreas Arnez; +Cc: gdb-patches, Ulrich Weigand

On Friday, June 07 2013, Andreas Arnez wrote:

> S/390 regmap rework: Represent register maps in a less redundant and
> more readable way.  Also remove some code repetition.

Hey Andreas,

As we discussed on private, this commit has caused the following
regression on S/390 (31-bit):

  $ make check RUNTESTFLAGS='--target_board=unix/-m31 gdb.base/checkpoint.exp'
  Running ../../../gdb/gdb/testsuite/gdb.base/checkpoint.exp ...
  FAIL: gdb.base/checkpoint.exp: restart 1 one
  FAIL: gdb.base/checkpoint.exp: verify i 1 one
  FAIL: gdb.base/checkpoint.exp: step in 1 one
  FAIL: gdb.base/checkpoint.exp: verify lines 1 one
  FAIL: gdb.base/checkpoint.exp: restart 2 one
  FAIL: gdb.base/checkpoint.exp: step in 2 one
  FAIL: gdb.base/checkpoint.exp: verify i 2 one
  FAIL: gdb.base/checkpoint.exp: verify lines 2 one
  FAIL: gdb.base/checkpoint.exp: restart 3 one
  FAIL: gdb.base/checkpoint.exp: step in 3 one
  FAIL: gdb.base/checkpoint.exp: verify i 3 one
  FAIL: gdb.base/checkpoint.exp: verify lines 3 one
  FAIL: gdb.base/checkpoint.exp: restart 4 one
  FAIL: gdb.base/checkpoint.exp: step in 4 one
  FAIL: gdb.base/checkpoint.exp: verify i 4 one
  FAIL: gdb.base/checkpoint.exp: verify lines 4 one
  FAIL: gdb.base/checkpoint.exp: restart 5 one
  FAIL: gdb.base/checkpoint.exp: step in 5 one
  FAIL: gdb.base/checkpoint.exp: verify i 5 one
  FAIL: gdb.base/checkpoint.exp: verify lines 5 one
  FAIL: gdb.base/checkpoint.exp: restart 6 one
  FAIL: gdb.base/checkpoint.exp: step in 6 one
  FAIL: gdb.base/checkpoint.exp: verify i 6 one
  FAIL: gdb.base/checkpoint.exp: verify lines 6 one
  FAIL: gdb.base/checkpoint.exp: restart 7 one
  FAIL: gdb.base/checkpoint.exp: step in 7 one
  FAIL: gdb.base/checkpoint.exp: verify i 7 one
  FAIL: gdb.base/checkpoint.exp: verify lines 7 one
  FAIL: gdb.base/checkpoint.exp: restart 8 one
  FAIL: gdb.base/checkpoint.exp: step in 8 one
  FAIL: gdb.base/checkpoint.exp: verify i 8 one
  FAIL: gdb.base/checkpoint.exp: verify lines 8 one
  FAIL: gdb.base/checkpoint.exp: restart 9 one
  FAIL: gdb.base/checkpoint.exp: step in 9 one
  FAIL: gdb.base/checkpoint.exp: verify i 9 one
  FAIL: gdb.base/checkpoint.exp: verify lines 9 one
  FAIL: gdb.base/checkpoint.exp: restart 10 one
  FAIL: gdb.base/checkpoint.exp: step in 10 one
  FAIL: gdb.base/checkpoint.exp: verify i 10 one
  FAIL: gdb.base/checkpoint.exp: verify lines 10 one
  FAIL: gdb.base/checkpoint.exp: restart 0 one
  FAIL: gdb.base/checkpoint.exp: break3 one (GDB internal error)
  FAIL: gdb.base/checkpoint.exp: Diff input and output one
  FAIL: gdb.base/checkpoint.exp: restart 1 two
  FAIL: gdb.base/checkpoint.exp: breakpoint 1 1 one
  FAIL: gdb.base/checkpoint.exp: step in 1 two
  FAIL: gdb.base/checkpoint.exp: verify lines 1 two
  FAIL: gdb.base/checkpoint.exp: restart 2 two
  FAIL: gdb.base/checkpoint.exp: breakpoint 1 2 one
  FAIL: gdb.base/checkpoint.exp: step in 2 two
  FAIL: gdb.base/checkpoint.exp: verify lines 2 two
  FAIL: gdb.base/checkpoint.exp: restart 3 two
  FAIL: gdb.base/checkpoint.exp: breakpoint 1 3 one
  FAIL: gdb.base/checkpoint.exp: step in 3 two
  FAIL: gdb.base/checkpoint.exp: verify lines 3 two
  FAIL: gdb.base/checkpoint.exp: restart 4 two
  FAIL: gdb.base/checkpoint.exp: breakpoint 1 4 one
  FAIL: gdb.base/checkpoint.exp: step in 4 two
  FAIL: gdb.base/checkpoint.exp: verify lines 4 two
  FAIL: gdb.base/checkpoint.exp: restart 5 two
  FAIL: gdb.base/checkpoint.exp: breakpoint 1 5 one
  FAIL: gdb.base/checkpoint.exp: step in 5 two
  FAIL: gdb.base/checkpoint.exp: verify lines 5 two
  FAIL: gdb.base/checkpoint.exp: restart 6 two
  FAIL: gdb.base/checkpoint.exp: breakpoint 1 6 one
  FAIL: gdb.base/checkpoint.exp: step in 6 two
  FAIL: gdb.base/checkpoint.exp: verify lines 5 two
  FAIL: gdb.base/checkpoint.exp: restart 7 two
  FAIL: gdb.base/checkpoint.exp: breakpoint 1 7 one
  FAIL: gdb.base/checkpoint.exp: step in 7 two
  FAIL: gdb.base/checkpoint.exp: verify lines 7 two
  FAIL: gdb.base/checkpoint.exp: Diff input and output two
  FAIL: gdb.base/checkpoint.exp: restart 0 one
  FAIL: gdb.base/checkpoint.exp: break4 one
  FAIL: gdb.base/checkpoint.exp: delete copy1
  FAIL: gdb.base/checkpoint.exp: restart 1 three
  FAIL: gdb.base/checkpoint.exp: break2 1 one
  FAIL: gdb.base/checkpoint.exp: outfile still open 1
  FAIL: gdb.base/checkpoint.exp: restart 2 three
  FAIL: gdb.base/checkpoint.exp: break2 2 one
  FAIL: gdb.base/checkpoint.exp: outfile still open 2
  FAIL: gdb.base/checkpoint.exp: restart 3 three
  FAIL: gdb.base/checkpoint.exp: break2 3 one
  FAIL: gdb.base/checkpoint.exp: outfile still open 3
  FAIL: gdb.base/checkpoint.exp: restart 4 three
  FAIL: gdb.base/checkpoint.exp: break2 4 one
  FAIL: gdb.base/checkpoint.exp: outfile still open 4
  FAIL: gdb.base/checkpoint.exp: restart 5 three
  FAIL: gdb.base/checkpoint.exp: break2 5 one
  FAIL: gdb.base/checkpoint.exp: outfile still open 5
  FAIL: gdb.base/checkpoint.exp: restart 6 three
  FAIL: gdb.base/checkpoint.exp: break2 6 one
  FAIL: gdb.base/checkpoint.exp: outfile still open 6
  FAIL: gdb.base/checkpoint.exp: restart 7 three
  FAIL: gdb.base/checkpoint.exp: break2 7 one
  FAIL: gdb.base/checkpoint.exp: outfile still open 7
  FAIL: gdb.base/checkpoint.exp: restart 8 three
  FAIL: gdb.base/checkpoint.exp: break2 8 one
  FAIL: gdb.base/checkpoint.exp: outfile still open 8
  FAIL: gdb.base/checkpoint.exp: restart 9 three
  FAIL: gdb.base/checkpoint.exp: break2 9 one
  FAIL: gdb.base/checkpoint.exp: outfile still open 9
  FAIL: gdb.base/checkpoint.exp: restart 10 three
  FAIL: gdb.base/checkpoint.exp: break2 10 one
  FAIL: gdb.base/checkpoint.exp: outfile still open 10
  FAIL: gdb.base/checkpoint.exp: Exit, dropped into next fork one
  FAIL: gdb.base/checkpoint.exp: Exit, dropped into next fork two
  FAIL: gdb.base/checkpoint.exp: Exit, dropped into next fork three
  FAIL: gdb.base/checkpoint.exp: Exit, dropped into next fork four
  FAIL: gdb.base/checkpoint.exp: Exit, dropped into next fork five
  FAIL: gdb.base/checkpoint.exp: info checkpoints two

git bisect tells me the commit causing the regression is:

  2ccd146855365598ad2644ef8139f2f2a6747b90 is the first bad commit
  commit 2ccd146855365598ad2644ef8139f2f2a6747b90
  Author: Ulrich Weigand <uweigand@de.ibm.com>
  Date:   Fri Sep 13 14:11:15 2013 +0000

Cheers,

> 2013-06-07  Andreas Arnez  <arnez@linux.vnet.ibm.com>
>
> 	* s390-tdep.h (S390_IS_GREGSET_REGNUM): New macro.
> 	(S390_IS_FPREGSET_REGNUM): New macro.
>
> 	* s390-tdep.c (s390_dwarf_regmap): Make const.
> 	(regnum_is_gpr_full): New function for replacing repeated code.
> 	(s390_pseudo_register_name): Use it.
> 	(s390_pseudo_register_type): Likewise.
> 	(s390_pseudo_register_read): Likewise.
> 	(s390_pseudo_register_write): Likewise.
> 	(s390_unwind_pseudo_register): Likewise.
> 	(s390_regmap_gregset): New format for regmap.
> 	(s390x_regmap_gregset): Likewise.
> 	(s390_regmap_fpregset): Likewise.
> 	(s390_regmap_upper): Likewise.
> 	(s390_regmap_last_break): Likewise.
> 	(s390_regmap_system_call): Likewise.
> 	(s390_supply_regset): Adjust to new regmap format.
> 	(s390_collect_regset): Likewise.
>
> 	* s390-nat.c (s390_native_supply): Adjust to new regmap format.
> 	(s390_native_collect): Likewise.
> 	(supply_gregset): Likewise.
> 	(fill_gregset): Likewise.
> 	(supply_fpregset): Likewise.
> 	(fill_fpregset): Likewise.
> 	(fetch_regset): Likewise.
> 	(store_regset): Likewise.
> 	(s390_linux_fetch_inferior_registers): Likewise.
> 	(s390_linux_fetch_inferior_registers): Likewise.
>
> Index: gdb/gdb/s390-tdep.h
> ===================================================================
> --- gdb.orig/gdb/s390-tdep.h
> +++ gdb/gdb/s390-tdep.h
> @@ -106,16 +106,24 @@
>  #define S390_RETADDR_REGNUM S390_R14_REGNUM
>  #define S390_FRAME_REGNUM S390_R11_REGNUM
>  
> +#define S390_IS_GREGSET_REGNUM(i)					\
> +  (((i) >= S390_PSWM_REGNUM && (i) <= S390_A15_REGNUM)			\
> +   || ((i) >= S390_R0_UPPER_REGNUM && (i) <= S390_R15_UPPER_REGNUM)	\
> +   || (i) == S390_ORIG_R2_REGNUM)
> +
> +#define S390_IS_FPREGSET_REGNUM(i)			\
> +  ((i) >= S390_FPC_REGNUM && (i) <= S390_F15_REGNUM)
> +
>  /* Core file register sets, defined in s390-tdep.c.  */
>  #define s390_sizeof_gregset 0x90
> -extern int s390_regmap_gregset[S390_NUM_REGS];
> +extern const short s390_regmap_gregset[];
>  #define s390x_sizeof_gregset 0xd8
> -extern int s390x_regmap_gregset[S390_NUM_REGS];
> +extern const short s390x_regmap_gregset[];
>  #define s390_sizeof_fpregset 0x88
> -extern int s390_regmap_fpregset[S390_NUM_REGS];
> -extern int s390_regmap_last_break[S390_NUM_REGS];
> -extern int s390x_regmap_last_break[S390_NUM_REGS];
> -extern int s390_regmap_system_call[S390_NUM_REGS];
> +extern const short s390_regmap_fpregset[];
> +extern const short s390_regmap_last_break[];
> +extern const short s390x_regmap_last_break[];
> +extern const short s390_regmap_system_call[];
>  
>  /* GNU/Linux target descriptions.  */
>  extern struct target_desc *tdesc_s390_linux32;
> Index: gdb/gdb/s390-nat.c
> ===================================================================
> --- gdb.orig/gdb/s390-nat.c
> +++ gdb/gdb/s390-nat.c
> @@ -63,139 +63,129 @@ static int have_regset_system_call = 0;
>  
>  #define regmap_fpregset s390_regmap_fpregset
>  
> -/* 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.  */
> +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 + map[0]);
> +}
>  
>  static void
> -s390_native_supply (struct regcache *regcache, int regno,
> -		    const gdb_byte *regp, int *regmap)
> +s390_native_collect (const struct regcache *regcache, const short *map,
> +		     int regno, gdb_byte *regp)
>  {
> -  int offset = regmap[regno];
> +  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 (offset != -1 && gdbarch_ptr_bit (gdbarch) == 32)
> +  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;
>  
> -      if (regno == S390_PSWM_REGNUM)
> -	{
> -	  ULONGEST pswm;
> -	  gdb_byte buf[4];
> -
> -	  pswm = extract_unsigned_integer (regp + regmap[S390_PSWM_REGNUM],
> -					   8, byte_order);
> -
> -	  store_unsigned_integer (buf, 4, byte_order, (pswm >> 32) | 0x80000);
> -	  regcache_raw_supply (regcache, regno, buf);
> -	  return;
> -	}
> -
> -      if (regno == S390_PSWA_REGNUM)
> +      for (map = regmap_gregset; map[0] >= 0; map += 2)
>  	{
> -	  ULONGEST pswm, pswa;
> -	  gdb_byte buf[4];
> +	  const gdb_byte *p = (const gdb_byte *) regp + map[0];
> +	  int regno = map[1];
>  
> -	  pswa = extract_unsigned_integer (regp + regmap[S390_PSWA_REGNUM],
> -					   8, byte_order);
> -	  pswm = extract_unsigned_integer (regp + regmap[S390_PSWM_REGNUM],
> -					   8, byte_order);
> -
> -	  store_unsigned_integer (buf, 4, byte_order,
> -				  (pswa & 0x7fffffff) | (pswm & 0x80000000));
> -	  regcache_raw_supply (regcache, regno, buf);
> -	  return;
> +	  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);
> +	    }
>  	}
>  
> -      if ((regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM)
> -	  || regno == S390_ORIG_R2_REGNUM)
> -	offset += 4;
> +      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
>  
> -  if (offset != -1)
> -    regcache_raw_supply (regcache, regno, regp + offset);
> +  s390_native_supply (regcache, regmap_gregset, (const gdb_byte *) regp);
>  }
>  
> -static void
> -s390_native_collect (const struct regcache *regcache, int regno,
> -		     gdb_byte *regp, int *regmap)
> +/* 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)
>  {
> -  int offset = regmap[regno];
> -
>  #ifdef __s390x__
>    struct gdbarch *gdbarch = get_regcache_arch (regcache);
> -  if (offset != -1 && gdbarch_ptr_bit (gdbarch) == 32)
> +  if (gdbarch_ptr_bit (gdbarch) == 32)
>      {
> -      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +      gdb_byte *psw_p[2];
> +      const short *map;
>  
> -      if (regno == S390_PSWM_REGNUM)
> +      for (map = regmap_gregset; map[0] >= 0; map += 2)
>  	{
> -	  ULONGEST pswm;
> -	  gdb_byte buf[4];
> +	  gdb_byte *p = (gdb_byte *) regp + map[0];
> +	  int reg = map[1];
>  
> -	  regcache_raw_collect (regcache, regno, buf);
> -	  pswm = extract_unsigned_integer (buf, 4, byte_order);
> +	  if (reg >= S390_PSWM_REGNUM && reg <= S390_PSWA_REGNUM)
> +	    psw_p[reg - S390_PSWM_REGNUM] = p;
>  
> -	  /* We don't know the final addressing mode until the PSW address
> -	     is known, so leave it as-is.  When the PSW address is collected
> -	     (below), the addressing mode will be updated.  */
> -	  store_unsigned_integer (regp + regmap[S390_PSWM_REGNUM],
> -				  4, byte_order, pswm & 0xfff7ffff);
> -	  return;
> +	  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 == S390_PSWA_REGNUM)
> +      if (regno == -1
> +	  || regno == S390_PSWM_REGNUM || regno == S390_PSWA_REGNUM)
>  	{
> -	  ULONGEST pswa;
> +	  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +	  ULONGEST pswa, pswm;
>  	  gdb_byte buf[4];
>  
> -	  regcache_raw_collect (regcache, regno, buf);
> +	  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);
>  
> -	  store_unsigned_integer (regp + regmap[S390_PSWA_REGNUM],
> -				  8, byte_order, pswa & 0x7fffffff);
> -
> -	  /* Update basic addressing mode bit in PSW mask, see above.  */
> -	  store_unsigned_integer (regp + regmap[S390_PSWM_REGNUM] + 4,
> -				  4, byte_order, pswa & 0x80000000);
> -	  return;
> -	}
> -
> -      if ((regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM)
> -	  || regno == S390_ORIG_R2_REGNUM)
> -	{
> -	  memset (regp + offset, 0, 4);
> -	  offset += 4;
> +	  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
>  
> -  if (offset != -1)
> -    regcache_raw_collect (regcache, regno, regp + offset);
> -}
> -
> -/* Fill GDB's register array with the general-purpose register values
> -   in *REGP.  */
> -void
> -supply_gregset (struct regcache *regcache, const gregset_t *regp)
> -{
> -  int i;
> -  for (i = 0; i < S390_NUM_REGS; i++)
> -    s390_native_supply (regcache, i, (const gdb_byte *) regp, regmap_gregset);
> -}
> -
> -/* 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)
> -{
> -  int i;
> -  for (i = 0; i < S390_NUM_REGS; i++)
> -    if (regno == -1 || regno == i)
> -      s390_native_collect (regcache, i, (gdb_byte *) regp, regmap_gregset);
> +  s390_native_collect (regcache, regmap_gregset, regno, (gdb_byte *) regp);
>  }
>  
>  /* Fill GDB's register array with the floating-point register values
> @@ -203,9 +193,7 @@ fill_gregset (const struct regcache *reg
>  void
>  supply_fpregset (struct regcache *regcache, const fpregset_t *regp)
>  {
> -  int i;
> -  for (i = 0; i < S390_NUM_REGS; i++)
> -    s390_native_supply (regcache, i, (const gdb_byte *) regp, regmap_fpregset);
> +  s390_native_supply (regcache, regmap_fpregset, (const gdb_byte *) regp);
>  }
>  
>  /* Fill register REGNO (if it is a general-purpose register) in
> @@ -214,10 +202,7 @@ supply_fpregset (struct regcache *regcac
>  void
>  fill_fpregset (const struct regcache *regcache, fpregset_t *regp, int regno)
>  {
> -  int i;
> -  for (i = 0; i < S390_NUM_REGS; i++)
> -    if (regno == -1 || regno == i)
> -      s390_native_collect (regcache, i, (gdb_byte *) regp, regmap_fpregset);
> +  s390_native_collect (regcache, regmap_fpregset, regno, (gdb_byte *) regp);
>  }
>  
>  /* Find the TID for the current inferior thread to use with ptrace.  */
> @@ -311,12 +296,10 @@ store_fpregs (const struct regcache *reg
>     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)
> +	      int regset, int regsize, const short *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;
> @@ -324,8 +307,7 @@ fetch_regset (struct regcache *regcache,
>    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);
> +  s390_native_supply (regcache, regmap, buf);
>  }
>  
>  /* Store all registers in the kernel's register set whose number is REGSET,
> @@ -333,12 +315,10 @@ fetch_regset (struct regcache *regcache,
>     GDB's register cache back to process/thread TID.  */
>  static void
>  store_regset (struct regcache *regcache, int tid,
> -	      int regset, int regsize, int *regmap)
> +	      int regset, int regsize, const short *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;
> @@ -346,8 +326,7 @@ store_regset (struct regcache *regcache,
>    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);
> +  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"));
> @@ -378,12 +357,10 @@ s390_linux_fetch_inferior_registers (str
>  {
>    int tid = s390_inferior_tid ();
>  
> -  if (regnum == -1 
> -      || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
> +  if (regnum == -1 || S390_IS_GREGSET_REGNUM (regnum))
>      fetch_regs (regcache, tid);
>  
> -  if (regnum == -1 
> -      || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
> +  if (regnum == -1 || S390_IS_FPREGSET_REGNUM (regnum))
>      fetch_fpregs (regcache, tid);
>  
>    if (have_regset_last_break)
> @@ -406,12 +383,10 @@ s390_linux_store_inferior_registers (str
>  {
>    int tid = s390_inferior_tid ();
>  
> -  if (regnum == -1 
> -      || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
> +  if (regnum == -1 || S390_IS_GREGSET_REGNUM (regnum))
>      store_regs (regcache, tid, regnum);
>  
> -  if (regnum == -1 
> -      || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
> +  if (regnum == -1 || S390_IS_FPREGSET_REGNUM (regnum))
>      store_fpregs (regcache, tid, regnum);
>  
>    /* S390_LAST_BREAK_REGNUM is read-only.  */
> Index: gdb/gdb/s390-tdep.c
> ===================================================================
> --- gdb.orig/gdb/s390-tdep.c
> +++ gdb/gdb/s390-tdep.c
> @@ -141,7 +141,7 @@ s390_write_pc (struct regcache *regcache
>  
>  /* DWARF Register Mapping.  */
>  
> -static int s390_dwarf_regmap[] =
> +static const short s390_dwarf_regmap[] =
>  {
>    /* General Purpose Registers.  */
>    S390_R0_REGNUM, S390_R1_REGNUM, S390_R2_REGNUM, S390_R3_REGNUM,
> @@ -212,6 +212,14 @@ s390_adjust_frame_regnum (struct gdbarch
>  
>  /* Pseudo registers.  */
>  
> +static int
> +regnum_is_gpr_full (struct gdbarch_tdep *tdep, int regnum)
> +{
> +  return (tdep->gpr_full_regnum != -1
> +	  && regnum >= tdep->gpr_full_regnum
> +	  && regnum <= tdep->gpr_full_regnum + 15);
> +}
> +
>  static const char *
>  s390_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
>  {
> @@ -223,9 +231,7 @@ s390_pseudo_register_name (struct gdbarc
>    if (regnum == tdep->cc_regnum)
>      return "cc";
>  
> -  if (tdep->gpr_full_regnum != -1
> -      && regnum >= tdep->gpr_full_regnum
> -      && regnum < tdep->gpr_full_regnum + 16)
> +  if (regnum_is_gpr_full (tdep, regnum))
>      {
>        static const char *full_name[] = {
>  	"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
> @@ -248,9 +254,7 @@ s390_pseudo_register_type (struct gdbarc
>    if (regnum == tdep->cc_regnum)
>      return builtin_type (gdbarch)->builtin_int;
>  
> -  if (tdep->gpr_full_regnum != -1
> -      && regnum >= tdep->gpr_full_regnum
> -      && regnum < tdep->gpr_full_regnum + 16)
> +  if (regnum_is_gpr_full (tdep, regnum))
>      return builtin_type (gdbarch)->builtin_uint64;
>  
>    internal_error (__FILE__, __LINE__, _("invalid regnum"));
> @@ -295,9 +299,7 @@ s390_pseudo_register_read (struct gdbarc
>        return status;
>      }
>  
> -  if (tdep->gpr_full_regnum != -1
> -      && regnum >= tdep->gpr_full_regnum
> -      && regnum < tdep->gpr_full_regnum + 16)
> +  if (regnum_is_gpr_full (tdep, regnum))
>      {
>        enum register_status status;
>        ULONGEST val_upper;
> @@ -352,9 +354,7 @@ s390_pseudo_register_write (struct gdbar
>        return;
>      }
>  
> -  if (tdep->gpr_full_regnum != -1
> -      && regnum >= tdep->gpr_full_regnum
> -      && regnum < tdep->gpr_full_regnum + 16)
> +  if (regnum_is_gpr_full (tdep, regnum))
>      {
>        regnum -= tdep->gpr_full_regnum;
>        val = extract_unsigned_integer (buf, regsize, byte_order);
> @@ -409,175 +409,166 @@ s390_pseudo_register_reggroup_p (struct
>  }
>  
>  
> -/* Core file register sets.  */
> +/* Maps for register sets.  */
>  
> -int s390_regmap_gregset[S390_NUM_REGS] =
> -{
> -  /* Program Status Word.  */
> -  0x00, 0x04,
> -  /* General Purpose Registers.  */
> -  0x08, 0x0c, 0x10, 0x14,
> -  0x18, 0x1c, 0x20, 0x24,
> -  0x28, 0x2c, 0x30, 0x34,
> -  0x38, 0x3c, 0x40, 0x44,
> -  /* Access Registers.  */
> -  0x48, 0x4c, 0x50, 0x54,
> -  0x58, 0x5c, 0x60, 0x64,
> -  0x68, 0x6c, 0x70, 0x74,
> -  0x78, 0x7c, 0x80, 0x84,
> -  /* Floating Point Control Word.  */
> -  -1,
> -  /* Floating Point Registers.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* GPR Uppper Halves.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* GNU/Linux-specific optional "registers".  */
> -  0x88, -1, -1,
> -};
> +const short s390_regmap_gregset[] =
> +  {
> +    0x00, S390_PSWM_REGNUM,
> +    0x04, S390_PSWA_REGNUM,
> +    0x08, S390_R0_REGNUM,
> +    0x0c, S390_R1_REGNUM,
> +    0x10, S390_R2_REGNUM,
> +    0x14, S390_R3_REGNUM,
> +    0x18, S390_R4_REGNUM,
> +    0x1c, S390_R5_REGNUM,
> +    0x20, S390_R6_REGNUM,
> +    0x24, S390_R7_REGNUM,
> +    0x28, S390_R8_REGNUM,
> +    0x2c, S390_R9_REGNUM,
> +    0x30, S390_R10_REGNUM,
> +    0x34, S390_R11_REGNUM,
> +    0x38, S390_R12_REGNUM,
> +    0x3c, S390_R13_REGNUM,
> +    0x40, S390_R14_REGNUM,
> +    0x44, S390_R15_REGNUM,
> +    0x48, S390_A0_REGNUM,
> +    0x4c, S390_A1_REGNUM,
> +    0x50, S390_A2_REGNUM,
> +    0x54, S390_A3_REGNUM,
> +    0x58, S390_A4_REGNUM,
> +    0x5c, S390_A5_REGNUM,
> +    0x60, S390_A6_REGNUM,
> +    0x64, S390_A7_REGNUM,
> +    0x68, S390_A8_REGNUM,
> +    0x6c, S390_A9_REGNUM,
> +    0x70, S390_A10_REGNUM,
> +    0x74, S390_A11_REGNUM,
> +    0x78, S390_A12_REGNUM,
> +    0x7c, S390_A13_REGNUM,
> +    0x80, S390_A14_REGNUM,
> +    0x84, S390_A15_REGNUM,
> +    0x88, S390_ORIG_R2_REGNUM,
> +    -1, -1
> +  };
>  
> -int s390x_regmap_gregset[S390_NUM_REGS] =
> -{
> -  /* Program Status Word.  */
> -  0x00, 0x08,
> -  /* General Purpose Registers.  */
> -  0x10, 0x18, 0x20, 0x28,
> -  0x30, 0x38, 0x40, 0x48,
> -  0x50, 0x58, 0x60, 0x68,
> -  0x70, 0x78, 0x80, 0x88,
> -  /* Access Registers.  */
> -  0x90, 0x94, 0x98, 0x9c,
> -  0xa0, 0xa4, 0xa8, 0xac,
> -  0xb0, 0xb4, 0xb8, 0xbc,
> -  0xc0, 0xc4, 0xc8, 0xcc,
> -  /* Floating Point Control Word.  */
> -  -1,
> -  /* Floating Point Registers.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* GPR Uppper Halves.  */
> -  0x10, 0x18, 0x20, 0x28,
> -  0x30, 0x38, 0x40, 0x48,
> -  0x50, 0x58, 0x60, 0x68,
> -  0x70, 0x78, 0x80, 0x88,
> -  /* GNU/Linux-specific optional "registers".  */
> -  0xd0, -1, -1,
> -};
> +const short s390x_regmap_gregset[] =
> +  {
> +    0x00, S390_PSWM_REGNUM,
> +    0x08, S390_PSWA_REGNUM,
> +    0x10, S390_R0_REGNUM,
> +    0x18, S390_R1_REGNUM,
> +    0x20, S390_R2_REGNUM,
> +    0x28, S390_R3_REGNUM,
> +    0x30, S390_R4_REGNUM,
> +    0x38, S390_R5_REGNUM,
> +    0x40, S390_R6_REGNUM,
> +    0x48, S390_R7_REGNUM,
> +    0x50, S390_R8_REGNUM,
> +    0x58, S390_R9_REGNUM,
> +    0x60, S390_R10_REGNUM,
> +    0x68, S390_R11_REGNUM,
> +    0x70, S390_R12_REGNUM,
> +    0x78, S390_R13_REGNUM,
> +    0x80, S390_R14_REGNUM,
> +    0x88, S390_R15_REGNUM,
> +    0x90, S390_A0_REGNUM,
> +    0x94, S390_A1_REGNUM,
> +    0x98, S390_A2_REGNUM,
> +    0x9c, S390_A3_REGNUM,
> +    0xa0, S390_A4_REGNUM,
> +    0xa4, S390_A5_REGNUM,
> +    0xa8, S390_A6_REGNUM,
> +    0xac, S390_A7_REGNUM,
> +    0xb0, S390_A8_REGNUM,
> +    0xb4, S390_A9_REGNUM,
> +    0xb8, S390_A10_REGNUM,
> +    0xbc, S390_A11_REGNUM,
> +    0xc0, S390_A12_REGNUM,
> +    0xc4, S390_A13_REGNUM,
> +    0xc8, S390_A14_REGNUM,
> +    0xcc, S390_A15_REGNUM,
> +    0x10, S390_R0_UPPER_REGNUM,
> +    0x18, S390_R1_UPPER_REGNUM,
> +    0x20, S390_R2_UPPER_REGNUM,
> +    0x28, S390_R3_UPPER_REGNUM,
> +    0x30, S390_R4_UPPER_REGNUM,
> +    0x38, S390_R5_UPPER_REGNUM,
> +    0x40, S390_R6_UPPER_REGNUM,
> +    0x48, S390_R7_UPPER_REGNUM,
> +    0x50, S390_R8_UPPER_REGNUM,
> +    0x58, S390_R9_UPPER_REGNUM,
> +    0x60, S390_R10_UPPER_REGNUM,
> +    0x68, S390_R11_UPPER_REGNUM,
> +    0x70, S390_R12_UPPER_REGNUM,
> +    0x78, S390_R13_UPPER_REGNUM,
> +    0x80, S390_R14_UPPER_REGNUM,
> +    0x88, S390_R15_UPPER_REGNUM,
> +    0xd0, S390_ORIG_R2_REGNUM,
> +    -1, -1
> +  };
>  
> -int s390_regmap_fpregset[S390_NUM_REGS] =
> -{
> -  /* Program Status Word.  */
> -  -1, -1,
> -  /* General Purpose Registers.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* Access Registers.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* Floating Point Control Word.  */
> -  0x00,
> -  /* Floating Point Registers.  */
> -  0x08, 0x10, 0x18, 0x20,
> -  0x28, 0x30, 0x38, 0x40,
> -  0x48, 0x50, 0x58, 0x60,
> -  0x68, 0x70, 0x78, 0x80,
> -  /* GPR Uppper Halves.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* GNU/Linux-specific optional "registers".  */
> -  -1, -1, -1,
> -};
> +const short s390_regmap_fpregset[] =
> +  {
> +    0x00, S390_FPC_REGNUM,
> +    0x08, S390_F0_REGNUM,
> +    0x10, S390_F1_REGNUM,
> +    0x18, S390_F2_REGNUM,
> +    0x20, S390_F3_REGNUM,
> +    0x28, S390_F4_REGNUM,
> +    0x30, S390_F5_REGNUM,
> +    0x38, S390_F6_REGNUM,
> +    0x40, S390_F7_REGNUM,
> +    0x48, S390_F8_REGNUM,
> +    0x50, S390_F9_REGNUM,
> +    0x58, S390_F10_REGNUM,
> +    0x60, S390_F11_REGNUM,
> +    0x68, S390_F12_REGNUM,
> +    0x70, S390_F13_REGNUM,
> +    0x78, S390_F14_REGNUM,
> +    0x80, S390_F15_REGNUM,
> +    -1, -1
> +  };
>  
> -int s390_regmap_upper[S390_NUM_REGS] =
> -{
> -  /* Program Status Word.  */
> -  -1, -1,
> -  /* General Purpose Registers.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* Access Registers.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* Floating Point Control Word.  */
> -  -1,
> -  /* Floating Point Registers.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* GPR Uppper Halves.  */
> -  0x00, 0x04, 0x08, 0x0c,
> -  0x10, 0x14, 0x18, 0x1c,
> -  0x20, 0x24, 0x28, 0x2c,
> -  0x30, 0x34, 0x38, 0x3c,
> -  /* GNU/Linux-specific optional "registers".  */
> -  -1, -1, -1,
> -};
> +const short s390_regmap_upper[] =
> +  {
> +    0x00, S390_R0_UPPER_REGNUM,
> +    0x04, S390_R1_UPPER_REGNUM,
> +    0x08, S390_R2_UPPER_REGNUM,
> +    0x0c, S390_R3_UPPER_REGNUM,
> +    0x10, S390_R4_UPPER_REGNUM,
> +    0x14, S390_R5_UPPER_REGNUM,
> +    0x18, S390_R6_UPPER_REGNUM,
> +    0x1c, S390_R7_UPPER_REGNUM,
> +    0x20, S390_R8_UPPER_REGNUM,
> +    0x24, S390_R9_UPPER_REGNUM,
> +    0x28, S390_R10_UPPER_REGNUM,
> +    0x2c, S390_R11_UPPER_REGNUM,
> +    0x30, S390_R12_UPPER_REGNUM,
> +    0x34, S390_R13_UPPER_REGNUM,
> +    0x38, S390_R14_UPPER_REGNUM,
> +    0x3c, S390_R15_UPPER_REGNUM,
> +    -1, -1
> +  };
>  
> -int s390_regmap_last_break[S390_NUM_REGS] =
> -{
> -  /* Program Status Word.  */
> -  -1, -1,
> -  /* General Purpose Registers.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* Access Registers.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* Floating Point Control Word.  */
> -  -1,
> -  /* Floating Point Registers.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* GPR Uppper Halves.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* GNU/Linux-specific optional "registers".  */
> -  -1, 4, -1,
> -};
> +const short s390_regmap_last_break[] =
> +  {
> +    0x04, S390_LAST_BREAK_REGNUM,
> +    -1, -1
> +  };
> +
> +const short s390x_regmap_last_break[] =
> +  {
> +    0x00, S390_LAST_BREAK_REGNUM,
> +    -1, -1
> +  };
> +
> +const short s390_regmap_system_call[] =
> +  {
> +    0x00, S390_SYSTEM_CALL_REGNUM,
> +    -1, -1
> +  };
>  
> -int s390x_regmap_last_break[S390_NUM_REGS] =
> -{
> -  /* Program Status Word.  */
> -  -1, -1,
> -  /* General Purpose Registers.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* Access Registers.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* Floating Point Control Word.  */
> -  -1,
> -  /* Floating Point Registers.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* GPR Uppper Halves.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* GNU/Linux-specific optional "registers".  */
> -  -1, 0, -1,
> -};
>  
> -int s390_regmap_system_call[S390_NUM_REGS] =
> -{
> -  /* Program Status Word.  */
> -  -1, -1,
> -  /* General Purpose Registers.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* Access Registers.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* Floating Point Control Word.  */
> -  -1,
> -  /* Floating Point Registers.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* GPR Uppper Halves.  */
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  -1, -1, -1, -1, -1, -1, -1, -1,
> -  /* GNU/Linux-specific optional "registers".  */
> -  -1, -1, 0,
> -};
>  
>  /* Supply register REGNUM from the register set REGSET to register cache 
>     REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
> @@ -585,14 +576,10 @@ static void
>  s390_supply_regset (const struct regset *regset, struct regcache *regcache,
>  		    int regnum, const void *regs, size_t len)
>  {
> -  const int *offset = regset->descr;
> -  int i;
> -
> -  for (i = 0; i < S390_NUM_REGS; i++)
> -    {
> -      if ((regnum == i || regnum == -1) && offset[i] != -1)
> -	regcache_raw_supply (regcache, i, (const char *)regs + offset[i]);
> -    }
> +  const short *map;
> +  for (map = regset->descr; map[0] >= 0; map += 2)
> +    if (regnum == -1 || regnum == map[1])
> +      regcache_raw_supply (regcache, map[1], (const char *)regs + map[0]);
>  }
>  
>  /* Collect register REGNUM from the register cache REGCACHE and store
> @@ -604,14 +591,10 @@ s390_collect_regset (const struct regset
>  		     const struct regcache *regcache,
>  		     int regnum, void *regs, size_t len)
>  {
> -  const int *offset = regset->descr;
> -  int i;
> -
> -  for (i = 0; i < S390_NUM_REGS; i++)
> -    {
> -      if ((regnum == i || regnum == -1) && offset[i] != -1)
> -	regcache_raw_collect (regcache, i, (char *)regs + offset[i]);
> -    }
> +  const short *map;
> +  for (map = regset->descr; map[0] >= 0; map += 2)
> +    if (regnum == -1 || regnum == map[1])
> +      regcache_raw_collect (regcache, map[1], (char *)regs + map[0]);
>  }
>  
>  static const struct regset s390_gregset = {
> @@ -1718,9 +1701,7 @@ s390_unwind_pseudo_register (struct fram
>  
>    /* Unwind full GPRs to show at least the lower halves (as the
>       upper halves are undefined).  */
> -  if (tdep->gpr_full_regnum != -1
> -      && regnum >= tdep->gpr_full_regnum
> -      && regnum < tdep->gpr_full_regnum + 16)
> +  if (regnum_is_gpr_full (tdep, regnum))
>      {
>        int reg = regnum - tdep->gpr_full_regnum;
>        struct value *val;

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Regression on gdb.base/checkpoint.exp on S/390
  2015-05-05 19:17   ` Regression on gdb.base/checkpoint.exp on S/390 (was: Re: [PATCH 1/3] S/390 regmap rework) Sergio Durigan Junior
@ 2015-05-06 18:16     ` Andreas Arnez
  0 siblings, 0 replies; 15+ messages in thread
From: Andreas Arnez @ 2015-05-06 18:16 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches, Ulrich Weigand

On Tue, May 05 2015, Sergio Durigan Junior wrote:

> On Friday, June 07 2013, Andreas Arnez wrote:
>
>> S/390 regmap rework: Represent register maps in a less redundant and
>> more readable way.  Also remove some code repetition.
>
> Hey Andreas,
>
> As we discussed on private, this commit has caused the following
> regression on S/390 (31-bit):
>
>   $ make check RUNTESTFLAGS='--target_board=unix/-m31 gdb.base/checkpoint.exp'
>   Running ../../../gdb/gdb/testsuite/gdb.base/checkpoint.exp ...
>   FAIL: gdb.base/checkpoint.exp: restart 1 one
>   FAIL: gdb.base/checkpoint.exp: verify i 1 one
> [...]

Right.  This is caused by a misunderstanding on my side when I wrote
that patch.  In fill_gregset, I was under the assumption that the
"gregset" part of the REGCACHE is fully populated, since that's what
supply_gregset would do.  However, fill_gregset is also used within
s390_linux_store_inferior_registers, for merging the inferior's
registers with one (or all) of a regcache's registers.  And that is
invoked via regcache_raw_write in a loop for each register when doing
regcache_cpy.  Until the loop has finished, the destination regcache is
partially filled, and my assumption is broken.

I've tried a fix that avoids this assumption, and it works.  (I'll post
it soon.)

But I also wonder whether it's intended that each regcache_raw_write
results in two ptrace calls?  This seems quite inefficient, considering
that all inferior's registers could be modified at once.

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2015-05-06 18:16 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-07 13:44 [RFA/RFT PATCH 0/3] Add TDB regset support Andreas Arnez
2013-06-07 13:50 ` [PATCH 1/3] S/390 regmap rework Andreas Arnez
2015-05-05 19:17   ` Regression on gdb.base/checkpoint.exp on S/390 (was: Re: [PATCH 1/3] S/390 regmap rework) Sergio Durigan Junior
2015-05-06 18:16     ` Regression on gdb.base/checkpoint.exp on S/390 Andreas Arnez
2013-06-07 13:51 ` [PATCH 2/3] Add TDB regset Andreas Arnez
2013-06-07 13:53 ` [PATCH 3/3] Dynamic core regset sections support Andreas Arnez
2013-06-07 14:43   ` Luis Machado
2013-06-07 16:40     ` Andreas Arnez
2013-06-07 15:03 ` [RFA/RFT PATCH 0/3] Add TDB regset support Pedro Alves
2013-06-07 15:59   ` Andreas Arnez
2013-06-07 16:44     ` Pedro Alves
2013-06-07 18:16       ` Andreas Arnez
2013-06-07 19:06         ` Pedro Alves
2013-06-10 16:59           ` Andreas Arnez
2013-06-11 10:48             ` Pedro Alves

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).