[v2,6/8,PowerPC] Fix VSX registers in linux core files

Message ID 20180521204458.19070-6-pedromfc@linux.vnet.ibm.com
State New, archived
Headers

Commit Message

pedromfc May 21, 2018, 8:44 p.m. UTC
  The functions used by the VSX regset to collect and supply registers
from core files where incorrect. This patch changes the regset to use
the standard regset collect/supply functions to fix this. The native
target is also changed to use the same regset.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Franco de Carvalho  <pedromfc@linux.vnet.ibm.com>

	* ppc-linux-tdep.c (ppc_linux_vsxregset): New function.
	(ppc32_linux_vsxregmap): New global.
	(ppc32_linux_vsxregset): Initialize with ppc32_linux_vsxregmap,
	regcache_supply_regset, and regcache_collect_regset.
	* ppc-linux-tdep.h (ppc_linux_vsxregset): Declare.
	* ppc-linux-nat.c (supply_vsxregset, fill_vsxregset): Remove.
	(fetch_vsx_register, store_vsx_register): Remove.
	(fetch_vsx_registers): Add regno parameter. Get regset using
	ppc_linux_vsxregset. Use regset to supply registers.
	(store_vsx_registers): Add regno parameter. Get regset using
	ppc_linux_vsxregset. Use regset to collect registers.
	(fetch_register): Call fetch_vsx_registers instead of
	fetch_vsx_register.
	(store_register): Call store_vsx_registers instead of
	store_vsx_register.
	(fetch_ppc_registers): Call fetch_vsx_registers with -1 for the
	new regno parameter.
	(store_ppc_registers): Call store_vsx_registers with -1 for the
	new regno parameter.
	* rs6000-tdep.c (ppc_vsx_support_p, ppc_supply_vsxreget)
	(ppc_collect_vsxregset): Remove.

gdb/testsuite/ChangeLog:
yyyy-mm-dd  Pedro Franco de Carvalho  <pedromfc@linux.vnet.ibm.com>

	* gdb.arch/powerpc-vsx-gcore.exp: New file.
---
 gdb/ppc-linux-nat.c                          | 106 ++++-----------------------
 gdb/ppc-linux-tdep.c                         |  18 ++++-
 gdb/ppc-linux-tdep.h                         |   1 +
 gdb/rs6000-tdep.c                            |  74 -------------------
 gdb/testsuite/gdb.arch/powerpc-vsx-gcore.exp |  90 +++++++++++++++++++++++
 5 files changed, 121 insertions(+), 168 deletions(-)
 create mode 100644 gdb/testsuite/gdb.arch/powerpc-vsx-gcore.exp
  

Patch

diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index e00831a248..0f7dd4c8e2 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -409,13 +409,11 @@  ppc_register_u_addr (struct gdbarch *gdbarch, int regno)
    registers set mechanism, as opposed to the interface for all the
    other registers, that stores/fetches each register individually.  */
 static void
-fetch_vsx_register (struct regcache *regcache, int tid, int regno)
+fetch_vsx_registers (struct regcache *regcache, int tid, int regno)
 {
   int ret;
   gdb_vsxregset_t regs;
-  struct gdbarch *gdbarch = regcache->arch ();
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-  int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
+  const struct regset *vsxregset = ppc_linux_vsxregset ();
 
   ret = ptrace (PTRACE_GETVSXREGS, tid, 0, &regs);
   if (ret < 0)
@@ -425,12 +423,11 @@  fetch_vsx_register (struct regcache *regcache, int tid, int regno)
 	  have_ptrace_getsetvsxregs = 0;
 	  return;
 	}
-      perror_with_name (_("Unable to fetch VSX register"));
+      perror_with_name (_("Unable to fetch VSX registers"));
     }
 
-  regcache_raw_supply (regcache, regno,
-		       regs + (regno - tdep->ppc_vsr0_upper_regnum)
-		       * vsxregsize);
+  vsxregset->supply_regset (vsxregset, regcache, regno, &regs,
+			    PPC_LINUX_SIZEOF_VSXREGSET);
 }
 
 /* The Linux kernel ptrace interface for AltiVec registers uses the
@@ -563,7 +560,7 @@  fetch_register (struct regcache *regcache, int tid, int regno)
     {
       if (have_ptrace_getsetvsxregs)
 	{
-	  fetch_vsx_register (regcache, tid, regno);
+	  fetch_vsx_registers (regcache, tid, regno);
 	  return;
 	}
     }
@@ -624,40 +621,6 @@  fetch_register (struct regcache *regcache, int tid, int regno)
                     gdbarch_byte_order (gdbarch));
 }
 
-static void
-supply_vsxregset (struct regcache *regcache, gdb_vsxregset_t *vsxregsetp)
-{
-  int i;
-  struct gdbarch *gdbarch = regcache->arch ();
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-  int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
-
-  for (i = 0; i < ppc_num_vshrs; i++)
-    {
-	regcache_raw_supply (regcache, tdep->ppc_vsr0_upper_regnum + i,
-			     *vsxregsetp + i * vsxregsize);
-    }
-}
-
-static void
-fetch_vsx_registers (struct regcache *regcache, int tid)
-{
-  int ret;
-  gdb_vsxregset_t regs;
-
-  ret = ptrace (PTRACE_GETVSXREGS, tid, 0, &regs);
-  if (ret < 0)
-    {
-      if (errno == EIO)
-	{
-	  have_ptrace_getsetvsxregs = 0;
-	  return;
-	}
-      perror_with_name (_("Unable to fetch VSX registers"));
-    }
-  supply_vsxregset (regcache, &regs);
-}
-
 /* This function actually issues the request to ptrace, telling
    it to get all general-purpose registers and put them into the
    specified regset.
@@ -799,7 +762,7 @@  fetch_ppc_registers (struct regcache *regcache, int tid)
       fetch_altivec_registers (regcache, tid, -1);
   if (have_ptrace_getsetvsxregs)
     if (tdep->ppc_vsr0_upper_regnum != -1)
-      fetch_vsx_registers (regcache, tid);
+      fetch_vsx_registers (regcache, tid, -1);
   if (tdep->ppc_ev0_upper_regnum >= 0)
     fetch_spe_register (regcache, tid, -1);
 }
@@ -818,15 +781,12 @@  ppc_linux_nat_target::fetch_registers (struct regcache *regcache, int regno)
     fetch_register (regcache, tid, regno);
 }
 
-/* Store one VSX register.  */
 static void
-store_vsx_register (const struct regcache *regcache, int tid, int regno)
+store_vsx_registers (const struct regcache *regcache, int tid, int regno)
 {
   int ret;
   gdb_vsxregset_t regs;
-  struct gdbarch *gdbarch = regcache->arch ();
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-  int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
+  const struct regset *vsxregset = ppc_linux_vsxregset ();
 
   ret = ptrace (PTRACE_GETVSXREGS, tid, 0, &regs);
   if (ret < 0)
@@ -836,15 +796,15 @@  store_vsx_register (const struct regcache *regcache, int tid, int regno)
 	  have_ptrace_getsetvsxregs = 0;
 	  return;
 	}
-      perror_with_name (_("Unable to fetch VSX register"));
+      perror_with_name (_("Unable to fetch VSX registers"));
     }
 
-  regcache_raw_collect (regcache, regno, regs +
-			(regno - tdep->ppc_vsr0_upper_regnum) * vsxregsize);
+  vsxregset->collect_regset (vsxregset, regcache, regno, &regs,
+			     PPC_LINUX_SIZEOF_VSXREGSET);
 
   ret = ptrace (PTRACE_SETVSXREGS, tid, 0, &regs);
   if (ret < 0)
-    perror_with_name (_("Unable to store VSX register"));
+    perror_with_name (_("Unable to store VSX registers"));
 }
 
 static void
@@ -980,7 +940,7 @@  store_register (const struct regcache *regcache, int tid, int regno)
     }
   if (vsx_register_p (gdbarch, regno))
     {
-      store_vsx_register (regcache, tid, regno);
+      store_vsx_registers (regcache, tid, regno);
       return;
     }
   else if (spe_register_p (gdbarch, regno))
@@ -1038,42 +998,6 @@  store_register (const struct regcache *regcache, int tid, int regno)
     }
 }
 
-static void
-fill_vsxregset (const struct regcache *regcache, gdb_vsxregset_t *vsxregsetp)
-{
-  int i;
-  struct gdbarch *gdbarch = regcache->arch ();
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-  int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
-
-  for (i = 0; i < ppc_num_vshrs; i++)
-    regcache_raw_collect (regcache, tdep->ppc_vsr0_upper_regnum + i,
-			  *vsxregsetp + i * vsxregsize);
-}
-
-static void
-store_vsx_registers (const struct regcache *regcache, int tid)
-{
-  int ret;
-  gdb_vsxregset_t regs;
-
-  ret = ptrace (PTRACE_GETVSXREGS, tid, 0, &regs);
-  if (ret < 0)
-    {
-      if (errno == EIO)
-	{
-	  have_ptrace_getsetvsxregs = 0;
-	  return;
-	}
-      perror_with_name (_("Couldn't get VSX registers"));
-    }
-
-  fill_vsxregset (regcache, &regs);
-
-  if (ptrace (PTRACE_SETVSXREGS, tid, 0, &regs) < 0)
-    perror_with_name (_("Couldn't write VSX registers"));
-}
-
 /* This function actually issues the request to ptrace, telling
    it to store all general-purpose registers present in the specified
    regset.
@@ -1235,7 +1159,7 @@  store_ppc_registers (const struct regcache *regcache, int tid)
       store_altivec_registers (regcache, tid, -1);
   if (have_ptrace_getsetvsxregs)
     if (tdep->ppc_vsr0_upper_regnum != -1)
-      store_vsx_registers (regcache, tid);
+      store_vsx_registers (regcache, tid, -1);
   if (tdep->ppc_ev0_upper_regnum >= 0)
     store_spe_register (regcache, tid, -1);
 }
diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
index 7362c4bbe1..293353a878 100644
--- a/gdb/ppc-linux-tdep.c
+++ b/gdb/ppc-linux-tdep.c
@@ -553,10 +553,16 @@  static const struct regset ppc32_be_linux_vrregset = {
   ppc_linux_collect_vrregset
 };
 
+static const struct regcache_map_entry ppc32_linux_vsxregmap[] =
+  {
+      { 32, PPC_VSR0_UPPER_REGNUM, 8 },
+      { 0 }
+  };
+
 static const struct regset ppc32_linux_vsxregset = {
-  &ppc32_linux_reg_offsets,
-  ppc_supply_vsxregset,
-  ppc_collect_vsxregset
+  ppc32_linux_vsxregmap,
+  regcache_supply_regset,
+  regcache_collect_regset
 };
 
 const struct regset *
@@ -580,6 +586,12 @@  ppc_linux_vrregset (struct gdbarch *gdbarch)
     return &ppc32_le_linux_vrregset;
 }
 
+const struct regset *
+ppc_linux_vsxregset (void)
+{
+  return &ppc32_linux_vsxregset;
+}
+
 /* Iterate over supported core file register note sections. */
 
 static void
diff --git a/gdb/ppc-linux-tdep.h b/gdb/ppc-linux-tdep.h
index a8715bd418..51f4b506a1 100644
--- a/gdb/ppc-linux-tdep.h
+++ b/gdb/ppc-linux-tdep.h
@@ -30,6 +30,7 @@  const struct regset *ppc_linux_fpregset (void);
 
 /* Get the vector regset that matches the target byte order.  */
 const struct regset *ppc_linux_vrregset (struct gdbarch *gdbarch);
+const struct regset *ppc_linux_vsxregset (void);
 
 /* Extra register number constants.  The Linux kernel stores a
    "trap" code and the original value of r3 into special "registers";
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index 4ef6f9e980..0a56c7890a 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -224,16 +224,6 @@  ppc_floating_point_unit_p (struct gdbarch *gdbarch)
 }
 
 /* Return non-zero if the architecture described by GDBARCH has
-   VSX registers (vsr0 --- vsr63).  */
-static int
-ppc_vsx_support_p (struct gdbarch *gdbarch)
-{
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-
-  return tdep->ppc_vsr0_regnum >= 0;
-}
-
-/* Return non-zero if the architecture described by GDBARCH has
    Altivec registers (vr0 --- vr31, vrsave and vscr).  */
 int
 ppc_altivec_support_p (struct gdbarch *gdbarch)
@@ -573,37 +563,6 @@  ppc_supply_fpregset (const struct regset *regset, struct regcache *regcache,
 		  regnum == tdep->ppc_fpscr_regnum ? offsets->fpscr_size : 8);
 }
 
-/* Supply register REGNUM in the VSX register set REGSET
-   from the buffer specified by VSXREGS and LEN to register cache
-   REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
-
-void
-ppc_supply_vsxregset (const struct regset *regset, struct regcache *regcache,
-		     int regnum, const void *vsxregs, size_t len)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  struct gdbarch_tdep *tdep;
-
-  if (!ppc_vsx_support_p (gdbarch))
-    return;
-
-  tdep = gdbarch_tdep (gdbarch);
-
-  if (regnum == -1)
-    {
-      int i;
-
-      for (i = tdep->ppc_vsr0_upper_regnum;
-	   i < tdep->ppc_vsr0_upper_regnum + 32;
-	   i++)
-	ppc_supply_reg (regcache, i, (const gdb_byte *) vsxregs, 0, 8);
-
-      return;
-    }
-  else
-    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vsxregs, 0, 8);
-}
-
 /* Collect register REGNUM in the general-purpose register set
    REGSET from register cache REGCACHE into the buffer specified by
    GREGS and LEN.  If REGNUM is -1, do this for all registers in
@@ -695,39 +654,6 @@  ppc_collect_fpregset (const struct regset *regset,
 		   regnum == tdep->ppc_fpscr_regnum ? offsets->fpscr_size : 8);
 }
 
-/* Collect register REGNUM in the VSX register set
-   REGSET from register cache REGCACHE into the buffer specified by
-   VSXREGS and LEN.  If REGNUM is -1, do this for all registers in
-   REGSET.  */
-
-void
-ppc_collect_vsxregset (const struct regset *regset,
-		      const struct regcache *regcache,
-		      int regnum, void *vsxregs, size_t len)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  struct gdbarch_tdep *tdep;
-
-  if (!ppc_vsx_support_p (gdbarch))
-    return;
-
-  tdep = gdbarch_tdep (gdbarch);
-
-  if (regnum == -1)
-    {
-      int i;
-
-      for (i = tdep->ppc_vsr0_upper_regnum;
-	   i < tdep->ppc_vsr0_upper_regnum + 32;
-	   i++)
-	ppc_collect_reg (regcache, i, (gdb_byte *) vsxregs, 0, 8);
-
-      return;
-    }
-  else
-    ppc_collect_reg (regcache, regnum, (gdb_byte *) vsxregs, 0, 8);
-}
-
 static int
 insn_changes_sp_or_jumps (unsigned long insn)
 {
diff --git a/gdb/testsuite/gdb.arch/powerpc-vsx-gcore.exp b/gdb/testsuite/gdb.arch/powerpc-vsx-gcore.exp
new file mode 100644
index 0000000000..e9bdfcdd44
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/powerpc-vsx-gcore.exp
@@ -0,0 +1,90 @@ 
+# Copyright (C) 2018 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/>.
+
+# This file is part of the gdb testsuite.
+
+# This test checks that generating and loading a core file preserves
+# the correct VSX register state.
+
+if {![istarget "powerpc*-*-linux*"] || [skip_vsx_tests]} then {
+    verbose "Skipping PowerPC test for corefiles with VSX registers."
+    return
+}
+
+standard_testfile .c
+
+set gen_src [standard_output_file $srcfile]
+
+gdb_produce_source $gen_src {
+	int main() {
+	    return 0;
+	}
+}
+
+if {[build_executable "compile" $binfile $gen_src] == -1} {
+    return -1
+}
+
+clean_restart $binfile
+
+if ![runto_main] then {
+    fail "could not run to main"
+    return -1
+}
+
+# Check if VSX register access through gdb is supported
+proc check_vsx_access {} {
+    global gdb_prompt
+
+    set test "vsx register access"
+    gdb_test_multiple "info reg vs0" "$test" {
+	-re "Invalid register.*\r\n$gdb_prompt $" {
+	    unsupported "$test"
+	    return 0
+	}
+	-re "\r\nvs0.*\r\n$gdb_prompt $" {
+	    pass "$test"
+	    return 1
+	}
+    }
+    return 0
+}
+
+if { ![check_vsx_access] } {
+    return -1
+}
+
+for {set i 0} {$i < 64} {incr i 1} {
+    gdb_test_no_output "set \$vs$i.uint128 = $i"
+}
+
+set core_filename [standard_output_file "$testfile.core"]
+set core_generated [gdb_gcore_cmd "$core_filename" "generate core file"]
+
+if { !$core_generated } {
+    return -1
+}
+
+clean_restart
+
+set core_loaded [gdb_core_cmd "$core_filename" "load core file"]
+
+if { $core_loaded != 1 } {
+    return -1
+}
+
+for {set i 0} {$i < 64} {incr i 1} {
+    gdb_test "print \$vs$i.uint128" ".* = $i" "print vs$i"
+}