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
This commit is contained in:
parent
f1b6788884
commit
607685ecee
|
@ -1,3 +1,25 @@
|
|||
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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 = ®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;
|
||||
|
||||
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_ARM_VFP, &iovec);
|
||||
if (ret < 0)
|
||||
perror_with_name (_("Unable to fetch VFP registers."));
|
||||
|
||||
regcache_raw_supply (regcache, AARCH64_FPSR_REGNUM, (char *) ®s.fpsr);
|
||||
regcache_raw_supply (regcache, AARCH64_FPCR_REGNUM, (char *) ®s.fpcr);
|
||||
aarch32_vfp_regcache_supply (regcache, (gdb_byte *) ®s, 32);
|
||||
}
|
||||
else
|
||||
{
|
||||
int regno;
|
||||
|
||||
iovec.iov_len = sizeof (regs);
|
||||
|
||||
ret = ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec);
|
||||
if (ret < 0)
|
||||
perror_with_name (_("Unable to fetch vFP/SIMD registers."));
|
||||
|
||||
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;
|
||||
|
||||
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]);
|
||||
ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_VFP, &iovec);
|
||||
if (ret < 0)
|
||||
perror_with_name (_("Unable to fetch VFP registers."));
|
||||
|
||||
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);
|
||||
aarch32_vfp_regcache_collect (regcache, (gdb_byte *) ®s, 32);
|
||||
}
|
||||
else
|
||||
{
|
||||
int regno;
|
||||
|
||||
ret = ptrace (PTRACE_SETREGSET, tid, NT_FPREGSET, &iovec);
|
||||
if (ret < 0)
|
||||
perror_with_name (_("Unable to store FP/SIMD registers."));
|
||||
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."));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue