Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PING][PATCH] Add support for accessing VFP registers to ARM  native Linux
@ 2010-03-15 14:49 Matthew Gretton-Dann
  2010-03-19 11:22 ` Richard Earnshaw
  2010-03-19 13:02 ` Daniel Jacobowitz
  0 siblings, 2 replies; 6+ messages in thread
From: Matthew Gretton-Dann @ 2010-03-15 14:49 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1370 bytes --]

All,

The attached patch adds support for VFP registers to GDB running
natively under ARM Linux.  The patch is based in large part on the
equivalent functionality in gdbserver for remote debugging of ARM Linux.

I have tested it with arm-unknown-linux-gnueabi on a target with Neon,
one with VFPv3-D16, one with VFPv2, and a target without VFP.  I have
also tested it on arm-none-linux on a target without VFP.  The patch has
not been tested on an XScale as I do not have access to an appropriate
device.

Can someone please review the patch, comment, and if appropriate commit
it?

Proposed ChangeLog: 

2010-03-01  Matthew Gretton-Dann  <matthew.gretton-dann@arm.com>

	* arm-tdep.h (gdb_regnum): Add ARM_FPSCR_REGNUM
	* arm-linux-nat.c (arm_linux_vfp_register_count): Add new
	variable.
	(fetch_vfp_registers): New function to fetch VFP registers.
	(store_vfp_registers): New function to store VFP registers.
	(arm_linux_fetch_inferior_registers): Add support for VFP
	registers.
	(arm_linux_store_inferior_registers): Likewise.
	(arm_linux_read_description): Likewise.
	(arm_read_auxv, arm_get_hwcap): New function.
	(_initialize_arm_linux_nat): Delay initialising iWMMX tdesc
	until we need it.

Thanks,

Matt

-- 
Matthew Gretton-Dann
Principal Engineer - Tools, PD Software
ARM Limited
-- 
Matthew Gretton-Dann
Principal Engineer - Tools, PD Software
ARM Limited

[-- Attachment #2: 1002-gdb-vfp-native.patch --]
[-- Type: text/x-patch, Size: 8471 bytes --]

Index: gdb/arm-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-linux-nat.c,v
retrieving revision 1.42
diff -u -p -r1.42 arm-linux-nat.c
--- gdb/arm-linux-nat.c	1 Jan 2010 07:31:29 -0000	1.42
+++ gdb/arm-linux-nat.c	1 Mar 2010 11:33:32 -0000
@@ -29,6 +29,7 @@
 #include "arm-tdep.h"
 #include "arm-linux-tdep.h"
 
+#include <elf/common.h>
 #include <sys/user.h>
 #include <sys/ptrace.h>
 #include <sys/utsname.h>
@@ -41,6 +42,9 @@
 #include "gdb_proc_service.h"
 
 #include "features/arm-with-iwmmxt.c"
+#include "features/arm-with-vfpv2.c"
+#include "features/arm-with-vfpv3.c"
+#include "features/arm-with-neon.c"
 
 #ifndef PTRACE_GET_THREAD_AREA
 #define PTRACE_GET_THREAD_AREA 22
@@ -51,9 +55,25 @@
 #define PTRACE_SETWMMXREGS 19
 #endif
 
+#ifndef PTRACE_GETVFPREGS
+#define PTRACE_GETVFPREGS 27
+#define PTRACE_SETVFPREGS 28
+#endif
+
+/* These are in <asm/elf.h> in current kernels.  */
+#define HWCAP_VFP       64
+#define HWCAP_IWMMXT    512
+#define HWCAP_NEON      4096
+#define HWCAP_VFPv3     8192
+#define HWCAP_VFPv3D16  16384
+
 /* A flag for whether the WMMX registers are available.  */
 static int arm_linux_has_wmmx_registers;
 
+/* The number of 64-bit VFP registers we have (expect this to be 0, 16, or
+   32). */
+static int arm_linux_vfp_register_count;
+
 extern int arm_apcs_32;
 
 /* The following variables are used to determine the version of the
@@ -447,6 +467,67 @@ store_wmmx_regs (const struct regcache *
     }
 }
 
+/* Fetch and store VFP Registers.  The kernel object has space for 32
+   64-bit registers, and the FPSCR.  This is even when on a VFPv2 or
+   VFPv3D16 target.  */
+#define VFP_REGS_SIZE (32 * 8 + 4)
+
+static void
+fetch_vfp_regs (struct regcache *regcache)
+{
+  char regbuf[VFP_REGS_SIZE];
+  int ret, regno, tid;
+
+  /* Get the thread id for the ptrace call.  */
+  tid = GET_THREAD_ID (inferior_ptid);
+
+  ret = ptrace (PTRACE_GETVFPREGS, tid, 0, regbuf);
+  if (ret < 0)
+    {
+      warning (_("Unable to fetch VFPv3 registers."));
+      return;
+    }
+
+  for (regno = 0; regno < arm_linux_vfp_register_count; regno++)
+    regcache_raw_supply (regcache, regno + ARM_D0_REGNUM,
+			 (char *) regbuf + regno * 8);
+
+  regcache_raw_supply (regcache, ARM_FPSCR_REGNUM,
+		       (char *) regbuf + 32 * 8);
+}
+
+static void
+store_vfp_regs (const struct regcache *regcache)
+{
+  char regbuf[VFP_REGS_SIZE];
+  int ret, regno, tid;
+
+  /* Get the thread id for the ptrace call.  */
+  tid = GET_THREAD_ID (inferior_ptid);
+
+  ret = ptrace (PTRACE_GETVFPREGS, tid, 0, regbuf);
+  if (ret < 0)
+    {
+      warning (_("Unable to fetch VFPv3 registers."));
+      return;
+    }
+
+  for (regno = 0; regno < arm_linux_vfp_register_count; regno++)
+    regcache_raw_collect (regcache, regno + ARM_D0_REGNUM,
+			  (char *) regbuf + regno * 8);
+
+  regcache_raw_collect (regcache, ARM_FPSCR_REGNUM,
+			(char *) regbuf + 32 * 8);
+
+  ret = ptrace (PTRACE_SETVFPREGS, tid, 0, regbuf);
+
+  if (ret < 0)
+    {
+      warning (_("Unable to store VFPv3 registers."));
+      return;
+    }
+}
+
 /* Fetch registers from the child process.  Fetch all registers if
    regno == -1, otherwise fetch all general registers or all floating
    point registers depending upon the value of regno.  */
@@ -461,6 +542,8 @@ arm_linux_fetch_inferior_registers (stru
       fetch_fpregs (regcache);
       if (arm_linux_has_wmmx_registers)
 	fetch_wmmx_regs (regcache);
+      if (arm_linux_vfp_register_count > 0)
+	fetch_vfp_regs (regcache);
     }
   else 
     {
@@ -471,6 +554,10 @@ arm_linux_fetch_inferior_registers (stru
       else if (arm_linux_has_wmmx_registers
 	       && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
 	fetch_wmmx_regs (regcache);
+      else if (arm_linux_vfp_register_count > 0
+	       && regno >= ARM_D0_REGNUM
+	       && regno <= ARM_D0_REGNUM + arm_linux_vfp_register_count)
+	fetch_vfp_regs (regcache);
     }
 }
 
@@ -488,6 +575,8 @@ arm_linux_store_inferior_registers (stru
       store_fpregs (regcache);
       if (arm_linux_has_wmmx_registers)
 	store_wmmx_regs (regcache);
+      if (arm_linux_vfp_register_count > 0)
+	store_vfp_regs (regcache);
     }
   else
     {
@@ -498,6 +587,10 @@ arm_linux_store_inferior_registers (stru
       else if (arm_linux_has_wmmx_registers
 	       && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
 	store_wmmx_regs (regcache);
+      else if (arm_linux_vfp_register_count > 0
+	       && regno >= ARM_D0_REGNUM
+	       && regno <= ARM_D0_REGNUM + arm_linux_vfp_register_count)
+	store_vfp_regs (regcache);
     }
 }
 
@@ -575,23 +668,118 @@ get_linux_version (unsigned int *vmajor,
   return ((*vmajor << 16) | (*vminor << 8) | *vrelease);
 }
 
+/* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET
+   to debugger memory starting at MYADDR.  */
+
+static int
+arm_read_auxv(int offset, unsigned char *myaddr, unsigned int len)
+{
+  char filename[PATH_MAX];
+  int fd, n;
+  int pid = GET_LWP (inferior_ptid);
+
+  snprintf (filename, sizeof filename, "/proc/%d/auxv", pid);
+
+  fd = open (filename, O_RDONLY);
+  if (fd < 0)
+    return -1;
+
+  if (offset != (CORE_ADDR) 0
+      && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
+    n = -1;
+  else
+    n = read (fd, myaddr, len);
+
+  close (fd);
+
+  return n;
+}
+
+static int
+arm_get_hwcap (unsigned long *valp)
+{
+  unsigned char *data = alloca (8);
+  int offset = 0;
+
+  while (arm_read_auxv (offset, data, 8) == 8)
+    {
+      unsigned int *data_p = (unsigned int *)data;
+      if (data_p[0] == AT_HWCAP)
+	{
+	  *valp = data_p[1];
+	  return 1;
+	}
+
+      offset += 8;
+    }
+
+  *valp = 0;
+  return 0;
+}
+
 static const struct target_desc *
 arm_linux_read_description (struct target_ops *ops)
 {
-  int ret;
-  char regbuf[IWMMXT_REGS_SIZE];
+  unsigned long arm_hwcap = 0;
+  arm_linux_has_wmmx_registers = 0;
+  arm_linux_vfp_register_count = 0;
+
+  if (arm_get_hwcap (&arm_hwcap) == 0)
+    {
+      return NULL;
+    }
+
+  if (arm_hwcap & HWCAP_IWMMXT)
+    {
+      arm_linux_has_wmmx_registers = 1;
+      if (tdesc_arm_with_iwmmxt == NULL)
+	initialize_tdesc_arm_with_iwmmxt ();
+      return tdesc_arm_with_iwmmxt;
+    }
+
+  if (arm_hwcap & HWCAP_VFP)
+    {
+      int pid;
+      char *buf;
+      const struct target_desc * result = NULL;
+
+      /* NEON implies VFPv3-D32 or no-VFP unit.  Say that we only support
+	 Neon with VFPv3-D32.  */
+      if (arm_hwcap & HWCAP_NEON)
+	{
+	  arm_linux_vfp_register_count = 32;
+	  if (tdesc_arm_with_neon == NULL)
+	    initialize_tdesc_arm_with_neon ();
+	  result = tdesc_arm_with_neon;
+	}
+      else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
+	{
+	  arm_linux_vfp_register_count = 32;
+	  if (tdesc_arm_with_vfpv3 == NULL)
+	    initialize_tdesc_arm_with_vfpv3 ();
+	  result = tdesc_arm_with_vfpv3;
+	}
+      else
+	{
+	  arm_linux_vfp_register_count = 16;
+	  if (tdesc_arm_with_vfpv2 == NULL)
+	    initialize_tdesc_arm_with_vfpv2 ();
+	  result = tdesc_arm_with_vfpv2;
+	}
+
+      /* Now make sure that the kernel supports reading these
+	 registers.  Support was added in 2.6.30.  */
+      pid = GET_LWP (inferior_ptid);
+      errno = 0;
+      buf = alloca (VFP_REGS_SIZE);
+      if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0
+	  && errno == EIO)
+	result = NULL;
 
-  ret = ptrace (PTRACE_GETWMMXREGS, GET_THREAD_ID (inferior_ptid),
-		0, regbuf);
-  if (ret < 0)
-    arm_linux_has_wmmx_registers = 0;
-  else
-    arm_linux_has_wmmx_registers = 1;
+      return result;
+    }
 
-  if (arm_linux_has_wmmx_registers)
-    return tdesc_arm_with_iwmmxt;
-  else
-    return NULL;
+  return NULL;
 }
 
 void _initialize_arm_linux_nat (void);
@@ -614,7 +802,4 @@ _initialize_arm_linux_nat (void)
 
   /* Register the target.  */
   linux_nat_add_target (t);
-
-  /* Initialize the standard target descriptions.  */
-  initialize_tdesc_arm_with_iwmmxt ();
 }
Index: gdb/arm-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.h,v
retrieving revision 1.39
diff -u -p -r1.39 arm-tdep.h
--- gdb/arm-tdep.h	1 Feb 2010 16:13:15 -0000	1.39
+++ gdb/arm-tdep.h	1 Mar 2010 11:33:32 -0000
@@ -50,6 +50,7 @@ enum gdb_regnum {
   ARM_WCGR7_REGNUM = ARM_WCGR0_REGNUM + 7,
   ARM_D0_REGNUM,		/* VFP double-precision registers.  */
   ARM_D31_REGNUM = ARM_D0_REGNUM + 31,
+  ARM_FPSCR_REGNUM,
 
   ARM_NUM_REGS,
 

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

* Re: [PING][PATCH] Add support for accessing VFP registers to ARM  native Linux
  2010-03-15 14:49 [PING][PATCH] Add support for accessing VFP registers to ARM native Linux Matthew Gretton-Dann
@ 2010-03-19 11:22 ` Richard Earnshaw
  2010-03-19 13:02 ` Daniel Jacobowitz
  1 sibling, 0 replies; 6+ messages in thread
From: Richard Earnshaw @ 2010-03-19 11:22 UTC (permalink / raw)
  To: Matthew Gretton-Dann; +Cc: gdb-patches


On Mon, 2010-03-15 at 14:48 +0000, Matthew Gretton-Dann wrote:
> All,
> 
> The attached patch adds support for VFP registers to GDB running
> natively under ARM Linux.  The patch is based in large part on the
> equivalent functionality in gdbserver for remote debugging of ARM Linux.
> 
> I have tested it with arm-unknown-linux-gnueabi on a target with Neon,
> one with VFPv3-D16, one with VFPv2, and a target without VFP.  I have
> also tested it on arm-none-linux on a target without VFP.  The patch has
> not been tested on an XScale as I do not have access to an appropriate
> device.
> 
> Can someone please review the patch, comment, and if appropriate commit
> it?
> 
> Proposed ChangeLog: 
> 
> 2010-03-01  Matthew Gretton-Dann  <matthew.gretton-dann@arm.com>
> 
> 	* arm-tdep.h (gdb_regnum): Add ARM_FPSCR_REGNUM
> 	* arm-linux-nat.c (arm_linux_vfp_register_count): Add new
> 	variable.
> 	(fetch_vfp_registers): New function to fetch VFP registers.
> 	(store_vfp_registers): New function to store VFP registers.
> 	(arm_linux_fetch_inferior_registers): Add support for VFP
> 	registers.
> 	(arm_linux_store_inferior_registers): Likewise.
> 	(arm_linux_read_description): Likewise.
> 	(arm_read_auxv, arm_get_hwcap): New function.
> 	(_initialize_arm_linux_nat): Delay initialising iWMMX tdesc
> 	until we need it.
> 
> Thanks,

OK once you've fixed:

+static void
+store_vfp_regs (const struct regcache *regcache)
...
+      warning (_("Unable to fetch VFPv3 registers."));
                             ^^^^^
s/fetch/store/


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

* Re: [PING][PATCH] Add support for accessing VFP registers to ARM   native Linux
  2010-03-15 14:49 [PING][PATCH] Add support for accessing VFP registers to ARM native Linux Matthew Gretton-Dann
  2010-03-19 11:22 ` Richard Earnshaw
@ 2010-03-19 13:02 ` Daniel Jacobowitz
  2010-03-19 15:20   ` Matthew Gretton-Dann
  1 sibling, 1 reply; 6+ messages in thread
From: Daniel Jacobowitz @ 2010-03-19 13:02 UTC (permalink / raw)
  To: Matthew Gretton-Dann; +Cc: gdb-patches

On Mon, Mar 15, 2010 at 02:48:54PM +0000, Matthew Gretton-Dann wrote:
> +/* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET
> +   to debugger memory starting at MYADDR.  */
> +
> +static int
> +arm_read_auxv(int offset, unsigned char *myaddr, unsigned int len)

In GDB you just need:

  target_auxv_search (current_target, AT_HWCAP, &val);

Looks otherwise fine to me too.  Sorry for the delay.

-- 
Daniel Jacobowitz
CodeSourcery


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

* Re: [PING][PATCH] Add support for accessing VFP registers to ARM  native Linux
  2010-03-19 13:02 ` Daniel Jacobowitz
@ 2010-03-19 15:20   ` Matthew Gretton-Dann
  2010-03-19 15:25     ` Matthew Gretton-Dann
  0 siblings, 1 reply; 6+ messages in thread
From: Matthew Gretton-Dann @ 2010-03-19 15:20 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: gdb-patches, Richard Earnshaw

[-- Attachment #1: Type: text/plain, Size: 1489 bytes --]

On Fri, 2010-03-19 at 09:02 -0400, Daniel Jacobowitz wrote:
> On Mon, Mar 15, 2010 at 02:48:54PM +0000, Matthew Gretton-Dann wrote:
> > +/* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET
> > +   to debugger memory starting at MYADDR.  */
> > +
> > +static int
> > +arm_read_auxv(int offset, unsigned char *myaddr, unsigned int len)
> 
> In GDB you just need:
> 
>   target_auxv_search (current_target, AT_HWCAP, &val);
> 
> Looks otherwise fine to me too.  Sorry for the delay.

Please find attached an updated patch which uses arm_read_auxv, and
updates the warning messgaes.  I've tested the change on a Cortex-A9
board.

If this patch is okay can someone please commit it as I do not have
commit rights to the GDB repository.

Proposed ChangeLog:

2010-03-19  Matthew Gretton-Dann  <matthew.gretton-dann@arm.com>

        * arm-tdep.h (gdb_regnum): Add ARM_FPSCR_REGNUM
        * arm-linux-nat.c (arm_linux_vfp_register_count): Add new
        variable.
        (fetch_vfp_registers): New function to fetch VFP registers.
        (store_vfp_registers): New function to store VFP registers.
        (arm_linux_fetch_inferior_registers): Add support for VFP
        registers.
        (arm_linux_store_inferior_registers): Likewise.
        (arm_linux_read_description): Likewise.
        (_initialize_arm_linux_nat): Delay initialising iWMMX tdesc
        until we need it.

Thanks,

Matt

-- 
Matthew Gretton-Dann
Principal Engineer - Tools, PD Software
ARM Limited

[-- Attachment #2: 1003-gdb-vfp-native.patch --]
[-- Type: text/x-patch, Size: 7596 bytes --]

? gdb/.arm-linux-nat.c.swp
Index: gdb/arm-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-linux-nat.c,v
retrieving revision 1.42
diff -u -p -r1.42 arm-linux-nat.c
--- gdb/arm-linux-nat.c	1 Jan 2010 07:31:29 -0000	1.42
+++ gdb/arm-linux-nat.c	19 Mar 2010 14:33:50 -0000
@@ -25,10 +25,12 @@
 #include "target.h"
 #include "linux-nat.h"
 #include "target-descriptions.h"
+#include "auxv.h"
 
 #include "arm-tdep.h"
 #include "arm-linux-tdep.h"
 
+#include <elf/common.h>
 #include <sys/user.h>
 #include <sys/ptrace.h>
 #include <sys/utsname.h>
@@ -41,6 +43,9 @@
 #include "gdb_proc_service.h"
 
 #include "features/arm-with-iwmmxt.c"
+#include "features/arm-with-vfpv2.c"
+#include "features/arm-with-vfpv3.c"
+#include "features/arm-with-neon.c"
 
 #ifndef PTRACE_GET_THREAD_AREA
 #define PTRACE_GET_THREAD_AREA 22
@@ -51,9 +56,25 @@
 #define PTRACE_SETWMMXREGS 19
 #endif
 
+#ifndef PTRACE_GETVFPREGS
+#define PTRACE_GETVFPREGS 27
+#define PTRACE_SETVFPREGS 28
+#endif
+
+/* These are in <asm/elf.h> in current kernels.  */
+#define HWCAP_VFP       64
+#define HWCAP_IWMMXT    512
+#define HWCAP_NEON      4096
+#define HWCAP_VFPv3     8192
+#define HWCAP_VFPv3D16  16384
+
 /* A flag for whether the WMMX registers are available.  */
 static int arm_linux_has_wmmx_registers;
 
+/* The number of 64-bit VFP registers we have (expect this to be 0, 16, or
+   32). */
+static int arm_linux_vfp_register_count;
+
 extern int arm_apcs_32;
 
 /* The following variables are used to determine the version of the
@@ -447,6 +468,67 @@ store_wmmx_regs (const struct regcache *
     }
 }
 
+/* Fetch and store VFP Registers.  The kernel object has space for 32
+   64-bit registers, and the FPSCR.  This is even when on a VFPv2 or
+   VFPv3D16 target.  */
+#define VFP_REGS_SIZE (32 * 8 + 4)
+
+static void
+fetch_vfp_regs (struct regcache *regcache)
+{
+  char regbuf[VFP_REGS_SIZE];
+  int ret, regno, tid;
+
+  /* Get the thread id for the ptrace call.  */
+  tid = GET_THREAD_ID (inferior_ptid);
+
+  ret = ptrace (PTRACE_GETVFPREGS, tid, 0, regbuf);
+  if (ret < 0)
+    {
+      warning (_("Unable to fetch VFP registers."));
+      return;
+    }
+
+  for (regno = 0; regno < arm_linux_vfp_register_count; regno++)
+    regcache_raw_supply (regcache, regno + ARM_D0_REGNUM,
+			 (char *) regbuf + regno * 8);
+
+  regcache_raw_supply (regcache, ARM_FPSCR_REGNUM,
+		       (char *) regbuf + 32 * 8);
+}
+
+static void
+store_vfp_regs (const struct regcache *regcache)
+{
+  char regbuf[VFP_REGS_SIZE];
+  int ret, regno, tid;
+
+  /* Get the thread id for the ptrace call.  */
+  tid = GET_THREAD_ID (inferior_ptid);
+
+  ret = ptrace (PTRACE_GETVFPREGS, tid, 0, regbuf);
+  if (ret < 0)
+    {
+      warning (_("Unable to fetch VFP registers (for update)."));
+      return;
+    }
+
+  for (regno = 0; regno < arm_linux_vfp_register_count; regno++)
+    regcache_raw_collect (regcache, regno + ARM_D0_REGNUM,
+			  (char *) regbuf + regno * 8);
+
+  regcache_raw_collect (regcache, ARM_FPSCR_REGNUM,
+			(char *) regbuf + 32 * 8);
+
+  ret = ptrace (PTRACE_SETVFPREGS, tid, 0, regbuf);
+
+  if (ret < 0)
+    {
+      warning (_("Unable to store VFP registers."));
+      return;
+    }
+}
+
 /* Fetch registers from the child process.  Fetch all registers if
    regno == -1, otherwise fetch all general registers or all floating
    point registers depending upon the value of regno.  */
@@ -461,6 +543,8 @@ arm_linux_fetch_inferior_registers (stru
       fetch_fpregs (regcache);
       if (arm_linux_has_wmmx_registers)
 	fetch_wmmx_regs (regcache);
+      if (arm_linux_vfp_register_count > 0)
+	fetch_vfp_regs (regcache);
     }
   else 
     {
@@ -471,6 +555,10 @@ arm_linux_fetch_inferior_registers (stru
       else if (arm_linux_has_wmmx_registers
 	       && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
 	fetch_wmmx_regs (regcache);
+      else if (arm_linux_vfp_register_count > 0
+	       && regno >= ARM_D0_REGNUM
+	       && regno <= ARM_D0_REGNUM + arm_linux_vfp_register_count)
+	fetch_vfp_regs (regcache);
     }
 }
 
@@ -488,6 +576,8 @@ arm_linux_store_inferior_registers (stru
       store_fpregs (regcache);
       if (arm_linux_has_wmmx_registers)
 	store_wmmx_regs (regcache);
+      if (arm_linux_vfp_register_count > 0)
+	store_vfp_regs (regcache);
     }
   else
     {
@@ -498,6 +588,10 @@ arm_linux_store_inferior_registers (stru
       else if (arm_linux_has_wmmx_registers
 	       && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
 	store_wmmx_regs (regcache);
+      else if (arm_linux_vfp_register_count > 0
+	       && regno >= ARM_D0_REGNUM
+	       && regno <= ARM_D0_REGNUM + arm_linux_vfp_register_count)
+	store_vfp_regs (regcache);
     }
 }
 
@@ -578,20 +672,66 @@ get_linux_version (unsigned int *vmajor,
 static const struct target_desc *
 arm_linux_read_description (struct target_ops *ops)
 {
-  int ret;
-  char regbuf[IWMMXT_REGS_SIZE];
+  CORE_ADDR arm_hwcap = 0;
+  arm_linux_has_wmmx_registers = 0;
+  arm_linux_vfp_register_count = 0;
+
+  if (target_auxv_search (ops, AT_HWCAP, &arm_hwcap) != 1)
+    {
+      return NULL;
+    }
+
+  if (arm_hwcap & HWCAP_IWMMXT)
+    {
+      arm_linux_has_wmmx_registers = 1;
+      if (tdesc_arm_with_iwmmxt == NULL)
+	initialize_tdesc_arm_with_iwmmxt ();
+      return tdesc_arm_with_iwmmxt;
+    }
+
+  if (arm_hwcap & HWCAP_VFP)
+    {
+      int pid;
+      char *buf;
+      const struct target_desc * result = NULL;
+
+      /* NEON implies VFPv3-D32 or no-VFP unit.  Say that we only support
+	 Neon with VFPv3-D32.  */
+      if (arm_hwcap & HWCAP_NEON)
+	{
+	  arm_linux_vfp_register_count = 32;
+	  if (tdesc_arm_with_neon == NULL)
+	    initialize_tdesc_arm_with_neon ();
+	  result = tdesc_arm_with_neon;
+	}
+      else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
+	{
+	  arm_linux_vfp_register_count = 32;
+	  if (tdesc_arm_with_vfpv3 == NULL)
+	    initialize_tdesc_arm_with_vfpv3 ();
+	  result = tdesc_arm_with_vfpv3;
+	}
+      else
+	{
+	  arm_linux_vfp_register_count = 16;
+	  if (tdesc_arm_with_vfpv2 == NULL)
+	    initialize_tdesc_arm_with_vfpv2 ();
+	  result = tdesc_arm_with_vfpv2;
+	}
+
+      /* Now make sure that the kernel supports reading these
+	 registers.  Support was added in 2.6.30.  */
+      pid = GET_LWP (inferior_ptid);
+      errno = 0;
+      buf = alloca (VFP_REGS_SIZE);
+      if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0
+	  && errno == EIO)
+	result = NULL;
 
-  ret = ptrace (PTRACE_GETWMMXREGS, GET_THREAD_ID (inferior_ptid),
-		0, regbuf);
-  if (ret < 0)
-    arm_linux_has_wmmx_registers = 0;
-  else
-    arm_linux_has_wmmx_registers = 1;
+      return result;
+    }
 
-  if (arm_linux_has_wmmx_registers)
-    return tdesc_arm_with_iwmmxt;
-  else
-    return NULL;
+  return NULL;
 }
 
 void _initialize_arm_linux_nat (void);
@@ -614,7 +754,4 @@ _initialize_arm_linux_nat (void)
 
   /* Register the target.  */
   linux_nat_add_target (t);
-
-  /* Initialize the standard target descriptions.  */
-  initialize_tdesc_arm_with_iwmmxt ();
 }
Index: gdb/arm-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.h,v
retrieving revision 1.39
diff -u -p -r1.39 arm-tdep.h
--- gdb/arm-tdep.h	1 Feb 2010 16:13:15 -0000	1.39
+++ gdb/arm-tdep.h	19 Mar 2010 14:33:51 -0000
@@ -50,6 +50,7 @@ enum gdb_regnum {
   ARM_WCGR7_REGNUM = ARM_WCGR0_REGNUM + 7,
   ARM_D0_REGNUM,		/* VFP double-precision registers.  */
   ARM_D31_REGNUM = ARM_D0_REGNUM + 31,
+  ARM_FPSCR_REGNUM,
 
   ARM_NUM_REGS,
 

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

* Re: [PING][PATCH] Add support for accessing VFP registers to ARM  native Linux
  2010-03-19 15:20   ` Matthew Gretton-Dann
@ 2010-03-19 15:25     ` Matthew Gretton-Dann
  0 siblings, 0 replies; 6+ messages in thread
From: Matthew Gretton-Dann @ 2010-03-19 15:25 UTC (permalink / raw)
  To: gdb-patches

On Fri, 2010-03-19 at 15:20 +0000, Matthew Gretton-Dann wrote:
> Please find attached an updated patch which uses arm_read_auxv, and
> updates the warning messgaes.  I've tested the change on a Cortex-A9
> board.

s/arm_read_auxv/target_auxv_search/.

Thanks,

Matt

-- 
Matthew Gretton-Dann
Principal Engineer - Tools, PD Software
ARM Limited


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

* [Ping] [PATCH] Add support for accessing VFP registers to ARM  native Linux
  2010-03-01 11:52 [PATCH] " Matthew Gretton-Dann
@ 2010-03-08  9:54 ` Matthew Gretton-Dann
  0 siblings, 0 replies; 6+ messages in thread
From: Matthew Gretton-Dann @ 2010-03-08  9:54 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1649 bytes --]

Hi,

Has anybody had a chance to look at this patch which I submitted last
week yet?  I am not concerned if it is just taking a while to review - I
just want to make sure it does not get missed by accident.

Thanks,

Matt

On Mon, 2010-03-01 at 11:50 +0000, Matthew Gretton-Dann wrote:
> All,
> 
> The attached patch adds support for VFP registers to GDB running
> natively under ARM Linux.  The patch is based in large part on the
> equivalent functionality in gdbserver for remote debugging of ARM Linux.
> 
> I have tested it with arm-unknown-linux-gnueabi on a target with Neon,
> one with VFPv3-D16, one with VFPv2, and a target without VFP.  I have
> also tested it on arm-none-linux on a target without VFP.  The patch has
> not been tested on an XScale as I do not have access to an appropriate
> device.
> 
> Can someone please review the patch, comment, and if appropriate commit
> it?
> 
> Proposed ChangeLog: 
> 
> 2010-03-01  Matthew Gretton-Dann  <matthew.gretton-dann@arm.com>
> 
> 	* arm-tdep.h (gdb_regnum): Add ARM_FPSCR_REGNUM
> 	* arm-linux-nat.c (arm_linux_vfp_register_count): Add new
> 	variable.
> 	(fetch_vfp_registers): New function to fetch VFP registers.
> 	(store_vfp_registers): New function to store VFP registers.
> 	(arm_linux_fetch_inferior_registers): Add support for VFP
> 	registers.
> 	(arm_linux_store_inferior_registers): Likewise.
> 	(arm_linux_read_description): Likewise.
> 	(arm_read_auxv, arm_get_hwcap): New function.
> 	(_initialize_arm_linux_nat): Delay initialising iWMMX tdesc
> 	until we need it.
> 
> Thanks,
> 
> Matt

-- 
Matthew Gretton-Dann
Principal Engineer - Tools, PD Software
ARM Limited

[-- Attachment #2: 1002-gdb-vfp-native.patch --]
[-- Type: text/x-patch, Size: 8471 bytes --]

Index: gdb/arm-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-linux-nat.c,v
retrieving revision 1.42
diff -u -p -r1.42 arm-linux-nat.c
--- gdb/arm-linux-nat.c	1 Jan 2010 07:31:29 -0000	1.42
+++ gdb/arm-linux-nat.c	1 Mar 2010 11:33:32 -0000
@@ -29,6 +29,7 @@
 #include "arm-tdep.h"
 #include "arm-linux-tdep.h"
 
+#include <elf/common.h>
 #include <sys/user.h>
 #include <sys/ptrace.h>
 #include <sys/utsname.h>
@@ -41,6 +42,9 @@
 #include "gdb_proc_service.h"
 
 #include "features/arm-with-iwmmxt.c"
+#include "features/arm-with-vfpv2.c"
+#include "features/arm-with-vfpv3.c"
+#include "features/arm-with-neon.c"
 
 #ifndef PTRACE_GET_THREAD_AREA
 #define PTRACE_GET_THREAD_AREA 22
@@ -51,9 +55,25 @@
 #define PTRACE_SETWMMXREGS 19
 #endif
 
+#ifndef PTRACE_GETVFPREGS
+#define PTRACE_GETVFPREGS 27
+#define PTRACE_SETVFPREGS 28
+#endif
+
+/* These are in <asm/elf.h> in current kernels.  */
+#define HWCAP_VFP       64
+#define HWCAP_IWMMXT    512
+#define HWCAP_NEON      4096
+#define HWCAP_VFPv3     8192
+#define HWCAP_VFPv3D16  16384
+
 /* A flag for whether the WMMX registers are available.  */
 static int arm_linux_has_wmmx_registers;
 
+/* The number of 64-bit VFP registers we have (expect this to be 0, 16, or
+   32). */
+static int arm_linux_vfp_register_count;
+
 extern int arm_apcs_32;
 
 /* The following variables are used to determine the version of the
@@ -447,6 +467,67 @@ store_wmmx_regs (const struct regcache *
     }
 }
 
+/* Fetch and store VFP Registers.  The kernel object has space for 32
+   64-bit registers, and the FPSCR.  This is even when on a VFPv2 or
+   VFPv3D16 target.  */
+#define VFP_REGS_SIZE (32 * 8 + 4)
+
+static void
+fetch_vfp_regs (struct regcache *regcache)
+{
+  char regbuf[VFP_REGS_SIZE];
+  int ret, regno, tid;
+
+  /* Get the thread id for the ptrace call.  */
+  tid = GET_THREAD_ID (inferior_ptid);
+
+  ret = ptrace (PTRACE_GETVFPREGS, tid, 0, regbuf);
+  if (ret < 0)
+    {
+      warning (_("Unable to fetch VFPv3 registers."));
+      return;
+    }
+
+  for (regno = 0; regno < arm_linux_vfp_register_count; regno++)
+    regcache_raw_supply (regcache, regno + ARM_D0_REGNUM,
+			 (char *) regbuf + regno * 8);
+
+  regcache_raw_supply (regcache, ARM_FPSCR_REGNUM,
+		       (char *) regbuf + 32 * 8);
+}
+
+static void
+store_vfp_regs (const struct regcache *regcache)
+{
+  char regbuf[VFP_REGS_SIZE];
+  int ret, regno, tid;
+
+  /* Get the thread id for the ptrace call.  */
+  tid = GET_THREAD_ID (inferior_ptid);
+
+  ret = ptrace (PTRACE_GETVFPREGS, tid, 0, regbuf);
+  if (ret < 0)
+    {
+      warning (_("Unable to fetch VFPv3 registers."));
+      return;
+    }
+
+  for (regno = 0; regno < arm_linux_vfp_register_count; regno++)
+    regcache_raw_collect (regcache, regno + ARM_D0_REGNUM,
+			  (char *) regbuf + regno * 8);
+
+  regcache_raw_collect (regcache, ARM_FPSCR_REGNUM,
+			(char *) regbuf + 32 * 8);
+
+  ret = ptrace (PTRACE_SETVFPREGS, tid, 0, regbuf);
+
+  if (ret < 0)
+    {
+      warning (_("Unable to store VFPv3 registers."));
+      return;
+    }
+}
+
 /* Fetch registers from the child process.  Fetch all registers if
    regno == -1, otherwise fetch all general registers or all floating
    point registers depending upon the value of regno.  */
@@ -461,6 +542,8 @@ arm_linux_fetch_inferior_registers (stru
       fetch_fpregs (regcache);
       if (arm_linux_has_wmmx_registers)
 	fetch_wmmx_regs (regcache);
+      if (arm_linux_vfp_register_count > 0)
+	fetch_vfp_regs (regcache);
     }
   else 
     {
@@ -471,6 +554,10 @@ arm_linux_fetch_inferior_registers (stru
       else if (arm_linux_has_wmmx_registers
 	       && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
 	fetch_wmmx_regs (regcache);
+      else if (arm_linux_vfp_register_count > 0
+	       && regno >= ARM_D0_REGNUM
+	       && regno <= ARM_D0_REGNUM + arm_linux_vfp_register_count)
+	fetch_vfp_regs (regcache);
     }
 }
 
@@ -488,6 +575,8 @@ arm_linux_store_inferior_registers (stru
       store_fpregs (regcache);
       if (arm_linux_has_wmmx_registers)
 	store_wmmx_regs (regcache);
+      if (arm_linux_vfp_register_count > 0)
+	store_vfp_regs (regcache);
     }
   else
     {
@@ -498,6 +587,10 @@ arm_linux_store_inferior_registers (stru
       else if (arm_linux_has_wmmx_registers
 	       && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
 	store_wmmx_regs (regcache);
+      else if (arm_linux_vfp_register_count > 0
+	       && regno >= ARM_D0_REGNUM
+	       && regno <= ARM_D0_REGNUM + arm_linux_vfp_register_count)
+	store_vfp_regs (regcache);
     }
 }
 
@@ -575,23 +668,118 @@ get_linux_version (unsigned int *vmajor,
   return ((*vmajor << 16) | (*vminor << 8) | *vrelease);
 }
 
+/* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET
+   to debugger memory starting at MYADDR.  */
+
+static int
+arm_read_auxv(int offset, unsigned char *myaddr, unsigned int len)
+{
+  char filename[PATH_MAX];
+  int fd, n;
+  int pid = GET_LWP (inferior_ptid);
+
+  snprintf (filename, sizeof filename, "/proc/%d/auxv", pid);
+
+  fd = open (filename, O_RDONLY);
+  if (fd < 0)
+    return -1;
+
+  if (offset != (CORE_ADDR) 0
+      && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
+    n = -1;
+  else
+    n = read (fd, myaddr, len);
+
+  close (fd);
+
+  return n;
+}
+
+static int
+arm_get_hwcap (unsigned long *valp)
+{
+  unsigned char *data = alloca (8);
+  int offset = 0;
+
+  while (arm_read_auxv (offset, data, 8) == 8)
+    {
+      unsigned int *data_p = (unsigned int *)data;
+      if (data_p[0] == AT_HWCAP)
+	{
+	  *valp = data_p[1];
+	  return 1;
+	}
+
+      offset += 8;
+    }
+
+  *valp = 0;
+  return 0;
+}
+
 static const struct target_desc *
 arm_linux_read_description (struct target_ops *ops)
 {
-  int ret;
-  char regbuf[IWMMXT_REGS_SIZE];
+  unsigned long arm_hwcap = 0;
+  arm_linux_has_wmmx_registers = 0;
+  arm_linux_vfp_register_count = 0;
+
+  if (arm_get_hwcap (&arm_hwcap) == 0)
+    {
+      return NULL;
+    }
+
+  if (arm_hwcap & HWCAP_IWMMXT)
+    {
+      arm_linux_has_wmmx_registers = 1;
+      if (tdesc_arm_with_iwmmxt == NULL)
+	initialize_tdesc_arm_with_iwmmxt ();
+      return tdesc_arm_with_iwmmxt;
+    }
+
+  if (arm_hwcap & HWCAP_VFP)
+    {
+      int pid;
+      char *buf;
+      const struct target_desc * result = NULL;
+
+      /* NEON implies VFPv3-D32 or no-VFP unit.  Say that we only support
+	 Neon with VFPv3-D32.  */
+      if (arm_hwcap & HWCAP_NEON)
+	{
+	  arm_linux_vfp_register_count = 32;
+	  if (tdesc_arm_with_neon == NULL)
+	    initialize_tdesc_arm_with_neon ();
+	  result = tdesc_arm_with_neon;
+	}
+      else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
+	{
+	  arm_linux_vfp_register_count = 32;
+	  if (tdesc_arm_with_vfpv3 == NULL)
+	    initialize_tdesc_arm_with_vfpv3 ();
+	  result = tdesc_arm_with_vfpv3;
+	}
+      else
+	{
+	  arm_linux_vfp_register_count = 16;
+	  if (tdesc_arm_with_vfpv2 == NULL)
+	    initialize_tdesc_arm_with_vfpv2 ();
+	  result = tdesc_arm_with_vfpv2;
+	}
+
+      /* Now make sure that the kernel supports reading these
+	 registers.  Support was added in 2.6.30.  */
+      pid = GET_LWP (inferior_ptid);
+      errno = 0;
+      buf = alloca (VFP_REGS_SIZE);
+      if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0
+	  && errno == EIO)
+	result = NULL;
 
-  ret = ptrace (PTRACE_GETWMMXREGS, GET_THREAD_ID (inferior_ptid),
-		0, regbuf);
-  if (ret < 0)
-    arm_linux_has_wmmx_registers = 0;
-  else
-    arm_linux_has_wmmx_registers = 1;
+      return result;
+    }
 
-  if (arm_linux_has_wmmx_registers)
-    return tdesc_arm_with_iwmmxt;
-  else
-    return NULL;
+  return NULL;
 }
 
 void _initialize_arm_linux_nat (void);
@@ -614,7 +802,4 @@ _initialize_arm_linux_nat (void)
 
   /* Register the target.  */
   linux_nat_add_target (t);
-
-  /* Initialize the standard target descriptions.  */
-  initialize_tdesc_arm_with_iwmmxt ();
 }
Index: gdb/arm-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.h,v
retrieving revision 1.39
diff -u -p -r1.39 arm-tdep.h
--- gdb/arm-tdep.h	1 Feb 2010 16:13:15 -0000	1.39
+++ gdb/arm-tdep.h	1 Mar 2010 11:33:32 -0000
@@ -50,6 +50,7 @@ enum gdb_regnum {
   ARM_WCGR7_REGNUM = ARM_WCGR0_REGNUM + 7,
   ARM_D0_REGNUM,		/* VFP double-precision registers.  */
   ARM_D31_REGNUM = ARM_D0_REGNUM + 31,
+  ARM_FPSCR_REGNUM,
 
   ARM_NUM_REGS,
 

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

end of thread, other threads:[~2010-03-19 15:25 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-03-15 14:49 [PING][PATCH] Add support for accessing VFP registers to ARM native Linux Matthew Gretton-Dann
2010-03-19 11:22 ` Richard Earnshaw
2010-03-19 13:02 ` Daniel Jacobowitz
2010-03-19 15:20   ` Matthew Gretton-Dann
2010-03-19 15:25     ` Matthew Gretton-Dann
  -- strict thread matches above, loose matches on Subject: below --
2010-03-01 11:52 [PATCH] " Matthew Gretton-Dann
2010-03-08  9:54 ` [Ping] " Matthew Gretton-Dann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox