From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 21417 invoked by alias); 8 Mar 2010 09:54:32 -0000 Received: (qmail 21408 invoked by uid 22791); 8 Mar 2010 09:54:31 -0000 X-SWARE-Spam-Status: No, hits=-1.9 required=5.0 tests=AWL,BAYES_00 X-Spam-Check-By: sourceware.org Received: from cam-admin0.cambridge.arm.com (HELO cam-admin0.cambridge.arm.com) (217.140.96.50) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 08 Mar 2010 09:54:25 +0000 Received: from cam-owa2.Emea.Arm.com (cam-owa2.emea.arm.com [10.1.105.18]) by cam-admin0.cambridge.arm.com (8.12.6/8.12.6) with ESMTP id o289sMeI019168 for ; Mon, 8 Mar 2010 09:54:22 GMT Received: from [10.1.79.63] ([10.1.255.212]) by cam-owa2.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.3959); Mon, 8 Mar 2010 09:54:22 +0000 Subject: [Ping] [PATCH] Add support for accessing VFP registers to ARM native Linux From: Matthew Gretton-Dann To: gdb-patches@sourceware.org In-Reply-To: <1267444251.6165.10.camel@e102111-lin.cambridge.arm.com> References: <1267444251.6165.10.camel@e102111-lin.cambridge.arm.com> Content-Type: multipart/mixed; boundary="=-XyCtb9+0MDqMi+rBXxGo" Date: Mon, 08 Mar 2010 09:54:00 -0000 Message-Id: <1268042061.30678.6.camel@e102111-lin.cambridge.arm.com> Mime-Version: 1.0 X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-03/txt/msg00303.txt.bz2 --=-XyCtb9+0MDqMi+rBXxGo Content-Type: text/plain Content-Transfer-Encoding: 7bit Content-length: 1649 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 > > * 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 --=-XyCtb9+0MDqMi+rBXxGo Content-Disposition: attachment; filename=1002-gdb-vfp-native.patch Content-Type: text/x-patch; name=1002-gdb-vfp-native.patch; charset=us-ascii Content-Transfer-Encoding: 7bit Content-length: 8471 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 #include #include #include @@ -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 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, --=-XyCtb9+0MDqMi+rBXxGo--