[rfc/rft] ppc gdbserver: autodetect AltiVec and SPE

Ulrich Weigand uweigand@de.ibm.com
Thu Feb 28 17:03:00 GMT 2008


Daniel Jacobowitz wrote:
> > Agreed.  I'll see if I can put a patch along those lines together.
> > However, I don't have any non-AltiVec or SPE systems available;
> > would you be able to test on those?
> 
> Yes, definitely.  We've got both.

That would be great, thanks!

What you do think about this patch?  It uses the AT_HWCAP auxv entry
to check for AltiVec and SPE.  One minor annoyance is that you need
to know the target wordsize in order to correctly interpret the auxv
array.  Therefore, we have to do the 64/32 check first, and only then
can we read auxv.

AltiVec and SPE regset access is now enabled uncoditionally, but the
fill/store routines make sure the corresponding HWCAP is set to avoid
accessing registers that are not present in the select register map.

With SPE there were a number of additional issues:
- The ppc_regmap used conditional defines to disable access to 
  floating point registers; I'm now using two different regmaps
  and switch them in the arch_setup routine.
- As the regmap was defined only for 32-bit host machines, I've
  disabled SPE support on 64-bit hosts.  I don't think there are
  any 64-bit machines with SPE anyway, right?
- There was a conditional check for fpscr in ppc_cannot_store_register;
  but as this routine is never called for fpscr in SPE mode, the check
  seems superfluous and I just removed it.

Tested on powerpc-linux and powerpc64-linux (-m64 and -m32) with no
regressions; properly detects AltiVec support.

Bye,
Ulrich


ChangeLog:

	* configure.srv [powerpc64-*-linux*]: Remove powerpc-e500.o from
	srv_regobj.  Remove rs6000/powerpc-e500.xml and rs6000/power-spe.xml	
	from reg_xmlfiles.
	* linux-ppc-low.c: Include <elf.h>.
	(PPC_FEATURE_HAS_ALTIVEC, PPC_FEATURE_HAS_SPE): Define.
	(ppc_hwcap): New global variable.
	(ppc_regmap): Remove __SPE__ #ifdef sections.
	(ppc_regmap_e500): New global variable.
	(ppc_cannot_store_register): Remove __SPE__ special case.
	(ppc_get_hwcap): New function.
	(ppc_arch_setup): Use it to determine whether inferior supports
	AltiVec or SPE registers.  Set the_low_target.regmap if appropriate.
	(ppc_fill_vrregset, ppc_store_vrregset): Define unconditionally.
	Do not access registers if target does not support AltiVec.
	(ppc_fill_evrregset, ppc_store_evrregset): Define unconditionally.
	Do not access registers if target does not support SPE.
	(target_regsets): Unconditionally include AltiVec and SPE regsets.

diff -urNp gdb-orig/gdb/gdbserver/configure.srv gdb-head/gdb/gdbserver/configure.srv
--- gdb-orig/gdb/gdbserver/configure.srv	2008-02-28 06:56:04.000000000 +0100
+++ gdb-head/gdb/gdbserver/configure.srv	2008-02-28 17:17:47.488329501 +0100
@@ -106,15 +106,13 @@ case "${target}" in
 			srv_linux_usrregs=yes
 			srv_linux_thread_db=yes
 			;;
-  powerpc64-*-linux*)	srv_regobj="reg-ppc.o powerpc-32.o powerpc-e500.o"
+  powerpc64-*-linux*)	srv_regobj="reg-ppc.o powerpc-32.o"
 			srv_regobj="${srv_regobj} reg-ppc64.o powerpc-64.o"
 			srv_tgtobj="linux-low.o linux-ppc-low.o"
 			srv_xmlfiles="rs6000/powerpc-32.xml"
 			srv_xmlfiles="${srv_xmlfiles} rs6000/power-altivec.xml"
 			srv_xmlfiles="${srv_xmlfiles} rs6000/power-core.xml"
 			srv_xmlfiles="${srv_xmlfiles} rs6000/power-fpu.xml"
-			srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-e500.xml"
-			srv_xmlfiles="${srv_xmlfiles} rs6000/power-spe.xml"
 			srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-64.xml"
 			srv_xmlfiles="${srv_xmlfiles} rs6000/power64-core.xml"
 			srv_linux_usrregs=yes
diff -urNp gdb-orig/gdb/gdbserver/linux-ppc-low.c gdb-head/gdb/gdbserver/linux-ppc-low.c
--- gdb-orig/gdb/gdbserver/linux-ppc-low.c	2008-02-28 06:56:04.000000000 +0100
+++ gdb-head/gdb/gdbserver/linux-ppc-low.c	2008-02-28 17:18:50.462849876 +0100
@@ -21,8 +21,16 @@
 #include "server.h"
 #include "linux-low.h"
 
+#include <elf.h>
 #include <asm/ptrace.h>
 
+/* These are in <asm/cputable.h> in current kernels.  */
+#define PPC_FEATURE_HAS_ALTIVEC         0x10000000
+#define PPC_FEATURE_HAS_SPE             0x00800000
+
+static unsigned long ppc_hwcap;
+
+
 /* Defined in auto-generated file reg-ppc.c.  */
 void init_registers_ppc (void);
 /* Defined in auto-generated file powerpc-32.c.  */
@@ -69,16 +77,6 @@ static int ppc_regmap[] =
   PT_R20 * 4,    PT_R21 * 4,    PT_R22 * 4,    PT_R23 * 4,
   PT_R24 * 4,    PT_R25 * 4,    PT_R26 * 4,    PT_R27 * 4,
   PT_R28 * 4,    PT_R29 * 4,    PT_R30 * 4,    PT_R31 * 4,
-#ifdef __SPE__
-  -1,            -1,            -1,            -1,
-  -1,            -1,            -1,            -1,
-  -1,            -1,            -1,            -1,
-  -1,            -1,            -1,            -1,
-  -1,            -1,            -1,            -1,
-  -1,            -1,            -1,            -1,
-  -1,            -1,            -1,            -1,
-  -1,            -1,            -1,            -1,
-#else
   PT_FPR0*4,     PT_FPR0*4 + 8, PT_FPR0*4+16,  PT_FPR0*4+24,
   PT_FPR0*4+32,  PT_FPR0*4+40,  PT_FPR0*4+48,  PT_FPR0*4+56,
   PT_FPR0*4+64,  PT_FPR0*4+72,  PT_FPR0*4+80,  PT_FPR0*4+88,
@@ -87,20 +85,36 @@ static int ppc_regmap[] =
   PT_FPR0*4+160,  PT_FPR0*4+168,  PT_FPR0*4+176,  PT_FPR0*4+184,
   PT_FPR0*4+192,  PT_FPR0*4+200,  PT_FPR0*4+208,  PT_FPR0*4+216,
   PT_FPR0*4+224,  PT_FPR0*4+232,  PT_FPR0*4+240,  PT_FPR0*4+248,
-#endif
   PT_NIP * 4,    PT_MSR * 4,    PT_CCR * 4,    PT_LNK * 4,
-#ifdef __SPE__
-  PT_CTR * 4,    PT_XER * 4,    -1
-#else
   PT_CTR * 4,    PT_XER * 4,    PT_FPSCR * 4
-#endif
+ };
+
+static int ppc_regmap_e500[] =
+ {PT_R0 * 4,     PT_R1 * 4,     PT_R2 * 4,     PT_R3 * 4,
+  PT_R4 * 4,     PT_R5 * 4,     PT_R6 * 4,     PT_R7 * 4,
+  PT_R8 * 4,     PT_R9 * 4,     PT_R10 * 4,    PT_R11 * 4,
+  PT_R12 * 4,    PT_R13 * 4,    PT_R14 * 4,    PT_R15 * 4,
+  PT_R16 * 4,    PT_R17 * 4,    PT_R18 * 4,    PT_R19 * 4,
+  PT_R20 * 4,    PT_R21 * 4,    PT_R22 * 4,    PT_R23 * 4,
+  PT_R24 * 4,    PT_R25 * 4,    PT_R26 * 4,    PT_R27 * 4,
+  PT_R28 * 4,    PT_R29 * 4,    PT_R30 * 4,    PT_R31 * 4,
+  -1,            -1,            -1,            -1,
+  -1,            -1,            -1,            -1,
+  -1,            -1,            -1,            -1,
+  -1,            -1,            -1,            -1,
+  -1,            -1,            -1,            -1,
+  -1,            -1,            -1,            -1,
+  -1,            -1,            -1,            -1,
+  -1,            -1,            -1,            -1,
+  PT_NIP * 4,    PT_MSR * 4,    PT_CCR * 4,    PT_LNK * 4,
+  PT_CTR * 4,    PT_XER * 4,    -1
  };
 #endif
 
 static int
 ppc_cannot_store_register (int regno)
 {
-#if !defined (__powerpc64__) && !defined (__SPE__)
+#ifndef __powerpc64__
   /* Some kernels do not allow us to store fpscr.  */
   if (regno == find_regno ("fpscr"))
     return 2;
@@ -167,6 +181,42 @@ ppc_set_pc (CORE_ADDR pc)
     }
 }
 
+
+static int
+ppc_get_hwcap (unsigned long *valp)
+{
+  int wordsize = register_size (0);
+  unsigned char *data = alloca (2 * wordsize);
+  int offset = 0;
+
+  while ((*the_target->read_auxv) (offset, data, 2 * wordsize) == 2 * wordsize)
+    {
+      if (wordsize == 4)
+	{
+	  unsigned int *data_p = (unsigned int *)data;
+	  if (data_p[0] == AT_HWCAP)
+	    {
+	      *valp = data_p[1];
+	      return 1;
+	    }
+	}
+      else
+	{
+	  unsigned long *data_p = (unsigned long *)data;
+	  if (data_p[0] == AT_HWCAP)
+	    {
+	      *valp = data_p[1];
+	      return 1;
+	    }
+	}
+
+      offset += 2 * wordsize;
+    }
+
+  *valp = 0;
+  return 0;
+}
+
 static void
 ppc_arch_setup (void)
 {
@@ -174,28 +224,37 @@ ppc_arch_setup (void)
   long msr;
 
   /* On a 64-bit host, assume 64-bit inferior process.  */
-#ifdef __ALTIVEC__
-  init_registers_powerpc_64 ();
-#else
   init_registers_ppc64 ();
-#endif
 
   /* Only if the high bit of the MSR is set, we actually have
      a 64-bit inferior.  */
   collect_register_by_name ("msr", &msr);
   if (msr < 0)
-    return;
+    {
+      ppc_get_hwcap (&ppc_hwcap);
+      if (ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC)
+	init_registers_powerpc_64 ();
+
+      return;
+    }
 #endif
 
   /* OK, we have a 32-bit inferior.  */
-#ifdef __ALTIVEC__
-  init_registers_powerpc_32 ();
-#else
-#ifdef __SPE__
-  init_registers_powerpc_e500 ();
-#else
   init_registers_ppc ();
-#endif
+
+  ppc_get_hwcap (&ppc_hwcap);
+  if (ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC)
+    init_registers_powerpc_32 ();
+
+  /* On 32-bit machines, check for SPE registers.
+     Set the low target's regmap field as appropriately.  */
+#ifndef __powerpc64__
+  the_low_target.regmap = ppc_regmap;
+  if (ppc_hwcap & PPC_FEATURE_HAS_SPE)
+    {
+      init_registers_powerpc_e500 ();
+      the_low_target.regmap = ppc_regmap_e500;
+   }
 #endif
 }
 
@@ -232,8 +291,6 @@ static void ppc_fill_gregset (void *buf)
     ppc_collect_ptrace_register (i, (char *) buf + ppc_regmap[i]);
 }
 
-#ifdef __ALTIVEC__
-
 #ifndef PTRACE_GETVRREGS
 #define PTRACE_GETVRREGS 18
 #define PTRACE_SETVRREGS 19
@@ -247,6 +304,9 @@ ppc_fill_vrregset (void *buf)
   int i, base;
   char *regset = buf;
 
+  if (!(ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC))
+    return;
+
   base = find_regno ("vr0");
   for (i = 0; i < 32; i++)
     collect_register (base + i, &regset[i * 16]);
@@ -261,6 +321,9 @@ ppc_store_vrregset (const void *buf)
   int i, base;
   const char *regset = buf;
 
+  if (!(ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC))
+    return;
+
   base = find_regno ("vr0");
   for (i = 0; i < 32; i++)
     supply_register (base + i, &regset[i * 16]);
@@ -269,10 +332,6 @@ ppc_store_vrregset (const void *buf)
   supply_register_by_name ("vrsave", &regset[33 * 16]);
 }
 
-#endif /* __ALTIVEC__ */
-
-#ifdef __SPE__
-
 #ifndef PTRACE_GETEVRREGS
 #define PTRACE_GETEVRREGS	20
 #define PTRACE_SETEVRREGS	21
@@ -291,6 +350,9 @@ ppc_fill_evrregset (void *buf)
   int i, ev0;
   struct gdb_evrregset_t *regset = buf;
 
+  if (!(ppc_hwcap & PPC_FEATURE_HAS_SPE))
+    return;
+
   ev0 = find_regno ("ev0h");
   for (i = 0; i < 32; i++)
     collect_register (ev0 + i, &regset->evr[i]);
@@ -305,6 +367,9 @@ ppc_store_evrregset (const void *buf)
   int i, ev0;
   const struct gdb_evrregset_t *regset = buf;
 
+  if (!(ppc_hwcap & PPC_FEATURE_HAS_SPE))
+    return;
+
   ev0 = find_regno ("ev0h");
   for (i = 0; i < 32; i++)
     supply_register (ev0 + i, &regset->evr[i]);
@@ -312,21 +377,16 @@ ppc_store_evrregset (const void *buf)
   supply_register_by_name ("acc", &regset->acc);
   supply_register_by_name ("spefscr", &regset->spefscr);
 }
-#endif /* __SPE__ */
 
 struct regset_info target_regsets[] = {
   /* List the extra register sets before GENERAL_REGS.  That way we will
      fetch them every time, but still fall back to PTRACE_PEEKUSER for the
      general registers.  Some kernels support these, but not the newer
      PPC_PTRACE_GETREGS.  */
-#ifdef __ALTIVEC__
   { PTRACE_GETVRREGS, PTRACE_SETVRREGS, SIZEOF_VRREGS, EXTENDED_REGS,
     ppc_fill_vrregset, ppc_store_vrregset },
-#endif
-#ifdef __SPE__
   { PTRACE_GETEVRREGS, PTRACE_SETEVRREGS, 32 * 4 + 8 + 4, EXTENDED_REGS,
     ppc_fill_evrregset, ppc_store_evrregset },
-#endif
   { 0, 0, 0, GENERAL_REGS, ppc_fill_gregset, NULL },
   { 0, 0, -1, -1, NULL, NULL }
 };

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com



More information about the Gdb-patches mailing list