This is the mail archive of the gdb-cvs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb] Native debug arm program by aarch64 GDB


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=607685ecee1015d6c37e0d800d40453dc0aadc8c

commit 607685ecee1015d6c37e0d800d40453dc0aadc8c
Author: Yao Qi <yao.qi@linaro.org>
Date:   Tue Jul 7 16:58:19 2015 +0100

    Native debug arm program by aarch64 GDB
    
    This patch is to let aarch64 GDB debug 32-bit arm program natively.  In
    each function for fetching and storing registers, GDB will check
    gdbarch_bfd_arch_info (gdbarch)->bits_per_word, if it is 32, call
    the corresponding aarch32 functions in aarch32-linux-nat.c, otherwise
    fall back to aarch64 code to fetch and store registers.
    
    aarch64_linux_read_description has to return the right target description,
    but we don't have gdbarch available there, so GDB fetches auxv and gets
    AT_PHENT, in order to determine whether the target is 32-bit or 64-bit.
    I learned this trick from solib-svr4.c.
    
    gdb:
    
    2015-07-07  Yao Qi  <yao.qi@linaro.org>
    
    	* aarch32-linux-nat.h (VFP_REGS_SIZE): New macro, moved from
    	arm-linux-nat.c.
    	* aarch64-linux-nat.c: Include aarch32-linux-nat.h and
    	elf/external.h.
    	(fetch_gregs_from_thread): Call aarch32_gp_regcache_supply
    	if target is 32-bit.
    	(store_gregs_to_thread): Call aarch32_gp_regcache_collect
    	if target is 32-bit.
    	(fetch_fpregs_from_thread): Call aarch32_vfp_regcache_supply
    	if target is 32-bit.
    	(store_fpregs_to_thread): Call aarch32_vfp_regcache_collect
    	if target is 32-bit.
    	(tdesc_arm_with_vfpv3, tdesc_arm_with_neon): Declare.
    	(aarch64_linux_read_description): Return the right target
    	description.
    	* arm-linux-nat.c (VFP_REGS_SIZE): Moved to aarch32-linux-nat.h.
    	* config/aarch64/linux.mh (NATDEPFILES): Add aarch32-linux-nat.o.
    	* configure.tgt (aarch64*-*-linux*): Add arm-tdep.o and
    	arm-linux-tdep.o

Diff:
---
 gdb/ChangeLog               |  22 +++++
 gdb/aarch32-linux-nat.h     |   5 ++
 gdb/aarch64-linux-nat.c     | 200 ++++++++++++++++++++++++++++++++++++--------
 gdb/arm-linux-nat.c         |   5 --
 gdb/config/aarch64/linux.mh |   2 +-
 gdb/configure.tgt           |   1 +
 6 files changed, 192 insertions(+), 43 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 2ac9366..c1f3994 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,27 @@
 2015-07-07  Yao Qi  <yao.qi@linaro.org>
 
+	* aarch32-linux-nat.h (VFP_REGS_SIZE): New macro, moved from
+	arm-linux-nat.c.
+	* aarch64-linux-nat.c: Include aarch32-linux-nat.h and
+	elf/external.h.
+	(fetch_gregs_from_thread): Call aarch32_gp_regcache_supply
+	if target is 32-bit.
+	(store_gregs_to_thread): Call aarch32_gp_regcache_collect
+	if target is 32-bit.
+	(fetch_fpregs_from_thread): Call aarch32_vfp_regcache_supply
+	if target is 32-bit.
+	(store_fpregs_to_thread): Call aarch32_vfp_regcache_collect
+	if target is 32-bit.
+	(tdesc_arm_with_vfpv3, tdesc_arm_with_neon): Declare.
+	(aarch64_linux_read_description): Return the right target
+	description.
+	* arm-linux-nat.c (VFP_REGS_SIZE): Moved to aarch32-linux-nat.h.
+	* config/aarch64/linux.mh (NATDEPFILES): Add aarch32-linux-nat.o.
+	* configure.tgt (aarch64*-*-linux*): Add arm-tdep.o and
+	arm-linux-tdep.o.
+
+2015-07-07  Yao Qi  <yao.qi@linaro.org>
+
 	* aarch32-linux-nat.c: New file.
 	* aarch32-linux-nat.h: New file.
 	* arm-linux-nat.c: Include aarch32-linux-nat.h.
diff --git a/gdb/aarch32-linux-nat.h b/gdb/aarch32-linux-nat.h
index 1b7ff83e..d7b5e16 100644
--- a/gdb/aarch32-linux-nat.h
+++ b/gdb/aarch32-linux-nat.h
@@ -15,6 +15,11 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
+/* 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)
+
 void aarch32_gp_regcache_supply (struct regcache *regcache, uint32_t *regs,
 				 int arm_apcs_32);
 
diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 9959b81..d48624f 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -29,6 +29,9 @@
 #include "gdbcmd.h"
 #include "aarch64-tdep.h"
 #include "aarch64-linux-tdep.h"
+#include "aarch32-linux-nat.h"
+
+#include "elf/external.h"
 #include "elf/common.h"
 
 #include <sys/ptrace.h>
@@ -458,22 +461,36 @@ aarch64_show_debug_reg_state (struct aarch64_debug_reg_state *state,
 static void
 fetch_gregs_from_thread (struct regcache *regcache)
 {
-  int ret, regno, tid;
+  int ret, tid;
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   elf_gregset_t regs;
   struct iovec iovec;
 
+  /* Make sure REGS can hold all registers contents on both aarch64
+     and arm.  */
+  gdb_static_assert (sizeof (regs) >= 18 * 4);
+
   tid = get_thread_id (inferior_ptid);
 
   iovec.iov_base = &regs;
-  iovec.iov_len = sizeof (regs);
+  if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
+    iovec.iov_len = 18 * 4;
+  else
+    iovec.iov_len = sizeof (regs);
 
   ret = ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iovec);
   if (ret < 0)
     perror_with_name (_("Unable to fetch general registers."));
 
-  for (regno = AARCH64_X0_REGNUM; regno <= AARCH64_CPSR_REGNUM; regno++)
-    regcache_raw_supply (regcache, regno,
-			 (char *) &regs[regno - AARCH64_X0_REGNUM]);
+  if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
+    aarch32_gp_regcache_supply (regcache, (uint32_t *) regs, 1);
+  else
+    {
+      int regno;
+
+      for (regno = AARCH64_X0_REGNUM; regno <= AARCH64_CPSR_REGNUM; regno++)
+	regcache_raw_supply (regcache, regno, &regs[regno - AARCH64_X0_REGNUM]);
+    }
 }
 
 /* Store to the current thread the valid general-purpose register
@@ -482,23 +499,37 @@ fetch_gregs_from_thread (struct regcache *regcache)
 static void
 store_gregs_to_thread (const struct regcache *regcache)
 {
-  int ret, regno, tid;
+  int ret, tid;
   elf_gregset_t regs;
   struct iovec iovec;
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
 
+  /* Make sure REGS can hold all registers contents on both aarch64
+     and arm.  */
+  gdb_static_assert (sizeof (regs) >= 18 * 4);
   tid = get_thread_id (inferior_ptid);
 
   iovec.iov_base = &regs;
-  iovec.iov_len = sizeof (regs);
+  if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
+    iovec.iov_len = 18 * 4;
+  else
+    iovec.iov_len = sizeof (regs);
 
   ret = ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iovec);
   if (ret < 0)
     perror_with_name (_("Unable to fetch general registers."));
 
-  for (regno = AARCH64_X0_REGNUM; regno <= AARCH64_CPSR_REGNUM; regno++)
-    if (REG_VALID == regcache_register_status (regcache, regno))
-      regcache_raw_collect (regcache, regno,
-			    (char *) &regs[regno - AARCH64_X0_REGNUM]);
+  if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
+    aarch32_gp_regcache_collect (regcache, (uint32_t *) regs, 1);
+  else
+    {
+      int regno;
+
+      for (regno = AARCH64_X0_REGNUM; regno <= AARCH64_CPSR_REGNUM; regno++)
+	if (REG_VALID == regcache_register_status (regcache, regno))
+	  regcache_raw_collect (regcache, regno,
+				&regs[regno - AARCH64_X0_REGNUM]);
+    }
 
   ret = ptrace (PTRACE_SETREGSET, tid, NT_PRSTATUS, &iovec);
   if (ret < 0)
@@ -511,25 +542,46 @@ store_gregs_to_thread (const struct regcache *regcache)
 static void
 fetch_fpregs_from_thread (struct regcache *regcache)
 {
-  int ret, regno, tid;
+  int ret, tid;
   elf_fpregset_t regs;
   struct iovec iovec;
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+
+  /* Make sure REGS can hold all VFP registers contents on both aarch64
+     and arm.  */
+  gdb_static_assert (sizeof regs >= VFP_REGS_SIZE);
 
   tid = get_thread_id (inferior_ptid);
 
   iovec.iov_base = &regs;
-  iovec.iov_len = sizeof (regs);
 
-  ret = ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec);
-  if (ret < 0)
-    perror_with_name (_("Unable to fetch FP/SIMD registers."));
+  if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
+    {
+      iovec.iov_len = VFP_REGS_SIZE;
+
+      ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_VFP, &iovec);
+      if (ret < 0)
+	perror_with_name (_("Unable to fetch VFP registers."));
+
+      aarch32_vfp_regcache_supply (regcache, (gdb_byte *) &regs, 32);
+    }
+  else
+    {
+      int regno;
+
+      iovec.iov_len = sizeof (regs);
 
-  for (regno = AARCH64_V0_REGNUM; regno <= AARCH64_V31_REGNUM; regno++)
-    regcache_raw_supply (regcache, regno,
-			 (char *) &regs.vregs[regno - AARCH64_V0_REGNUM]);
+      ret = ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec);
+      if (ret < 0)
+	perror_with_name (_("Unable to fetch vFP/SIMD registers."));
 
-  regcache_raw_supply (regcache, AARCH64_FPSR_REGNUM, (char *) &regs.fpsr);
-  regcache_raw_supply (regcache, AARCH64_FPCR_REGNUM, (char *) &regs.fpcr);
+      for (regno = AARCH64_V0_REGNUM; regno <= AARCH64_V31_REGNUM; regno++)
+	regcache_raw_supply (regcache, regno,
+			     &regs.vregs[regno - AARCH64_V0_REGNUM]);
+
+      regcache_raw_supply (regcache, AARCH64_FPSR_REGNUM, &regs.fpsr);
+      regcache_raw_supply (regcache, AARCH64_FPCR_REGNUM, &regs.fpcr);
+    }
 }
 
 /* Store to the current thread the valid fp/simd register
@@ -538,32 +590,63 @@ fetch_fpregs_from_thread (struct regcache *regcache)
 static void
 store_fpregs_to_thread (const struct regcache *regcache)
 {
-  int ret, regno, tid;
+  int ret, tid;
   elf_fpregset_t regs;
   struct iovec iovec;
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
 
+  /* Make sure REGS can hold all VFP registers contents on both aarch64
+     and arm.  */
+  gdb_static_assert (sizeof regs >= VFP_REGS_SIZE);
   tid = get_thread_id (inferior_ptid);
 
   iovec.iov_base = &regs;
-  iovec.iov_len = sizeof (regs);
 
-  ret = ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec);
-  if (ret < 0)
-    perror_with_name (_("Unable to fetch FP/SIMD registers."));
+  if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
+    {
+      iovec.iov_len = VFP_REGS_SIZE;
+
+      ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_VFP, &iovec);
+      if (ret < 0)
+	perror_with_name (_("Unable to fetch VFP registers."));
+
+      aarch32_vfp_regcache_collect (regcache, (gdb_byte *) &regs, 32);
+    }
+  else
+    {
+      int regno;
 
-  for (regno = AARCH64_V0_REGNUM; regno <= AARCH64_V31_REGNUM; regno++)
-    if (REG_VALID == regcache_register_status (regcache, regno))
-      regcache_raw_collect (regcache, regno,
-			    (char *) &regs.vregs[regno - AARCH64_V0_REGNUM]);
+      iovec.iov_len = sizeof (regs);
 
-  if (REG_VALID == regcache_register_status (regcache, AARCH64_FPSR_REGNUM))
-    regcache_raw_collect (regcache, AARCH64_FPSR_REGNUM, (char *) &regs.fpsr);
-  if (REG_VALID == regcache_register_status (regcache, AARCH64_FPCR_REGNUM))
-    regcache_raw_collect (regcache, AARCH64_FPCR_REGNUM, (char *) &regs.fpcr);
+      ret = ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec);
+      if (ret < 0)
+	perror_with_name (_("Unable to fetch FP/SIMD registers."));
 
-  ret = ptrace (PTRACE_SETREGSET, tid, NT_FPREGSET, &iovec);
-  if (ret < 0)
-    perror_with_name (_("Unable to store FP/SIMD registers."));
+      for (regno = AARCH64_V0_REGNUM; regno <= AARCH64_V31_REGNUM; regno++)
+	if (REG_VALID == regcache_register_status (regcache, regno))
+	  regcache_raw_collect (regcache, regno,
+				(char *) &regs.vregs[regno - AARCH64_V0_REGNUM]);
+
+      if (REG_VALID == regcache_register_status (regcache, AARCH64_FPSR_REGNUM))
+	regcache_raw_collect (regcache, AARCH64_FPSR_REGNUM,
+			      (char *) &regs.fpsr);
+      if (REG_VALID == regcache_register_status (regcache, AARCH64_FPCR_REGNUM))
+	regcache_raw_collect (regcache, AARCH64_FPCR_REGNUM,
+			      (char *) &regs.fpcr);
+    }
+
+  if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
+    {
+      ret = ptrace (PTRACE_SETREGSET, tid, NT_ARM_VFP, &iovec);
+      if (ret < 0)
+	perror_with_name (_("Unable to store VFP registers."));
+    }
+  else
+    {
+      ret = ptrace (PTRACE_SETREGSET, tid, NT_FPREGSET, &iovec);
+      if (ret < 0)
+	perror_with_name (_("Unable to store FP/SIMD registers."));
+    }
 }
 
 /* Implement the "to_fetch_register" target_ops method.  */
@@ -823,11 +906,54 @@ aarch64_linux_child_post_startup_inferior (struct target_ops *self,
   super_post_startup_inferior (self, ptid);
 }
 
+extern struct target_desc *tdesc_arm_with_vfpv3;
+extern struct target_desc *tdesc_arm_with_neon;
+
 /* Implement the "to_read_description" target_ops method.  */
 
 static const struct target_desc *
 aarch64_linux_read_description (struct target_ops *ops)
 {
+  CORE_ADDR at_phent;
+
+  if (target_auxv_search (ops, AT_PHENT, &at_phent) == 1)
+    {
+      if (at_phent == sizeof (Elf64_External_Phdr))
+	return tdesc_aarch64;
+      else
+	{
+	  CORE_ADDR arm_hwcap = 0;
+
+	  if (target_auxv_search (ops, AT_HWCAP, &arm_hwcap) != 1)
+	    return ops->beneath->to_read_description (ops->beneath);
+
+#ifndef COMPAT_HWCAP_VFP
+#define COMPAT_HWCAP_VFP        (1 << 6)
+#endif
+#ifndef COMPAT_HWCAP_NEON
+#define COMPAT_HWCAP_NEON       (1 << 12)
+#endif
+#ifndef COMPAT_HWCAP_VFPv3
+#define COMPAT_HWCAP_VFPv3      (1 << 13)
+#endif
+
+	  if (arm_hwcap & COMPAT_HWCAP_VFP)
+	    {
+	      char *buf;
+	      const struct target_desc *result = NULL;
+
+	      if (arm_hwcap & COMPAT_HWCAP_NEON)
+		result = tdesc_arm_with_neon;
+	      else if (arm_hwcap & COMPAT_HWCAP_VFPv3)
+		result = tdesc_arm_with_vfpv3;
+
+	      return result;
+	    }
+
+	  return NULL;
+	}
+    }
+
   return tdesc_aarch64;
 }
 
diff --git a/gdb/arm-linux-nat.c b/gdb/arm-linux-nat.c
index aca0461..f0ab98c 100644
--- a/gdb/arm-linux-nat.c
+++ b/gdb/arm-linux-nat.c
@@ -342,11 +342,6 @@ store_wmmx_regs (const struct regcache *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)
 {
diff --git a/gdb/config/aarch64/linux.mh b/gdb/config/aarch64/linux.mh
index 6a8aa7d..cbe322f 100644
--- a/gdb/config/aarch64/linux.mh
+++ b/gdb/config/aarch64/linux.mh
@@ -19,7 +19,7 @@
 #  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o aarch64-linux-nat.o \
+NATDEPFILES= inf-ptrace.o fork-child.o aarch64-linux-nat.o aarch32-linux-nat.o \
 	proc-service.o linux-thread-db.o linux-nat.o linux-fork.o \
 	linux-procfs.o linux-ptrace.o linux-osdata.o linux-waitpid.o \
 	linux-personality.o linux-namespaces.o
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 4e4d6a9..f2c1a2d 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -44,6 +44,7 @@ aarch64*-*-elf)
 aarch64*-*-linux*)
 	# Target: AArch64 linux
 	gdb_target_obs="aarch64-tdep.o aarch64-linux-tdep.o \
+			arm-tdep.o arm-linux-tdep.o \
 			glibc-tdep.o linux-tdep.o solib-svr4.o \
 			symfile-mem.o linux-record.o"
 	build_gdbserver=yes


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]