From patchwork Wed Jul 1 13:58:23 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yao Qi X-Patchwork-Id: 7450 Received: (qmail 89551 invoked by alias); 1 Jul 2015 13:58:52 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 89345 invoked by uid 89); 1 Jul 2015 13:58:51 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-pd0-f178.google.com Received: from mail-pd0-f178.google.com (HELO mail-pd0-f178.google.com) (209.85.192.178) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Wed, 01 Jul 2015 13:58:43 +0000 Received: by pdjd13 with SMTP id d13so26441913pdj.0 for ; Wed, 01 Jul 2015 06:58:41 -0700 (PDT) X-Received: by 10.66.147.4 with SMTP id tg4mr7234193pab.69.1435759120928; Wed, 01 Jul 2015 06:58:40 -0700 (PDT) Received: from E107787-LIN.cambridge.arm.com (gcc1-power7.osuosl.org. [140.211.15.137]) by mx.google.com with ESMTPSA id sc7sm2417503pbb.85.2015.07.01.06.58.39 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Jul 2015 06:58:40 -0700 (PDT) From: Yao Qi X-Google-Original-From: Yao Qi To: gdb-patches@sourceware.org Subject: [PATCH 03/11] Native debug arm program by aarch64 GDB Date: Wed, 1 Jul 2015 14:58:23 +0100 Message-Id: <1435759111-22856-4-git-send-email-yao.qi@linaro.org> In-Reply-To: <1435759111-22856-1-git-send-email-yao.qi@linaro.org> References: <1435759111-22856-1-git-send-email-yao.qi@linaro.org> X-IsSubscribed: yes 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-06-24 Yao Qi * 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 --- 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 + 5 files changed, 170 insertions(+), 43 deletions(-) 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 . */ +/* 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 aae4853..9814dce 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 @@ -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 = ®s; - 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 *) ®s[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, ®s[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 = ®s; - 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 *) ®s[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, + ®s[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 = ®s; - 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 *) ®s, 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 *) ®s.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 *) ®s.fpsr); - regcache_raw_supply (regcache, AARCH64_FPCR_REGNUM, (char *) ®s.fpcr); + for (regno = AARCH64_V0_REGNUM; regno <= AARCH64_V31_REGNUM; regno++) + regcache_raw_supply (regcache, regno, + ®s.vregs[regno - AARCH64_V0_REGNUM]); + + regcache_raw_supply (regcache, AARCH64_FPSR_REGNUM, ®s.fpsr); + regcache_raw_supply (regcache, AARCH64_FPCR_REGNUM, ®s.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 = ®s; - 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 *) ®s, 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 *) ®s.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 *) ®s.fpsr); - if (REG_VALID == regcache_register_status (regcache, AARCH64_FPCR_REGNUM)) - regcache_raw_collect (regcache, AARCH64_FPCR_REGNUM, (char *) ®s.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 *) ®s.vregs[regno - AARCH64_V0_REGNUM]); + + if (REG_VALID == regcache_register_status (regcache, AARCH64_FPSR_REGNUM)) + regcache_raw_collect (regcache, AARCH64_FPSR_REGNUM, + (char *) ®s.fpsr); + if (REG_VALID == regcache_register_status (regcache, AARCH64_FPCR_REGNUM)) + regcache_raw_collect (regcache, AARCH64_FPCR_REGNUM, + (char *) ®s.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 . 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