* [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