diff options
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/ChangeLog | 29 | ||||
-rw-r--r-- | gdb/arm-linux-nat.c | 20 | ||||
-rw-r--r-- | gdb/arm-linux-tdep.c | 101 | ||||
-rw-r--r-- | gdb/arm-linux-tdep.h | 9 | ||||
-rw-r--r-- | gdb/arm-tdep.c | 8 | ||||
-rw-r--r-- | gdb/arm-tdep.h | 9 |
6 files changed, 155 insertions, 21 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index b40d0a6..ba1a501 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,32 @@ +2011-06-15 Ulrich Weigand <ulrich.weigand@linaro.org> + + * arm-linux-tdep.c: Include "auxv.h". + (AT_HWCAP): Define. + (ARM_LINUX_SIZEOF_VFP): Define. + (arm_linux_supply_vfp): New function. + (arm_linux_collect_vfp): Likewise. + (arm_linux_regset_from_core_section): Handle .reg-arm-vfp sections. + (arm_linux_fpa_regset_sections): New variable. + (arm_linux_vfp_regset_sections): Likewise. + (arm_linux_core_read_description): New function. + (arm_linux_init_abi): Install arm_linux_core_read_description and + arm_linux_fpa_regset_sections or arm_linux_vfp_regset_sections as + appropriate for the architecture. + * arm-tdep.h (struct gdbarch_tdep): Add member "vfpregset". + (tdesc_arm_with_m): Declare. + (tdesc_arm_with_iwmmxt): Likewise. + (tdesc_arm_with_vfpv2): Likewise. + (tdesc_arm_with_vfpv3): Likewise. + (tdesc_arm_with_neon): Likewise. + * arm-linux-nat.c: Move features/*.c includes ... + * arm-tdep.c: ... here. + * arm-linux-nat.c (arm_linux_read_description): Move initializing + target description data structures ... + * arm-tdep.c (_initialize_arm_tdep): ... here. + * arm-linux-nat.c (HWCAP_VFP, HWCAP_IWMMXT, HWCAP_NEON, HWCAP_VFPv3, + HWCAP_VFPv3D16): Move definitions ... + * arm-linux-tdep.h: ... here. + 2011-06-15 Hui Zhu <teawater@gmail.com> * remote.c (remote_trace_set_readonly_regions): Add a check for diff --git a/gdb/arm-linux-nat.c b/gdb/arm-linux-nat.c index 43f4fde..f64c37c 100644 --- a/gdb/arm-linux-nat.c +++ b/gdb/arm-linux-nat.c @@ -44,11 +44,6 @@ /* Defines ps_err_e, struct ps_prochandle. */ #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 #endif @@ -68,13 +63,6 @@ #define PTRACE_SETHBPREGS 30 #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; @@ -696,8 +684,6 @@ arm_linux_read_description (struct target_ops *ops) 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; } @@ -712,22 +698,16 @@ arm_linux_read_description (struct target_ops *ops) 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; } diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c index b7ff5ec..b5b56de 100644 --- a/gdb/arm-linux-tdep.c +++ b/gdb/arm-linux-tdep.c @@ -33,6 +33,7 @@ #include "trad-frame.h" #include "tramp-frame.h" #include "breakpoint.h" +#include "auxv.h" #include "arm-tdep.h" #include "arm-linux-tdep.h" @@ -45,6 +46,9 @@ #include "gdb_string.h" +/* This is defined in <elf.h> on ARM GNU/Linux systems. */ +#define AT_HWCAP 16 + extern int arm_apcs_32; /* Under ARM GNU/Linux the traditional way of performing a breakpoint @@ -638,6 +642,44 @@ arm_linux_collect_nwfpe (const struct regset *regset, regs + INT_REGISTER_SIZE * ARM_FPS_REGNUM); } +/* Support VFP register format. */ + +#define ARM_LINUX_SIZEOF_VFP (32 * 8 + 4) + +static void +arm_linux_supply_vfp (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *regs_buf, size_t len) +{ + const gdb_byte *regs = regs_buf; + int regno; + + if (regnum == ARM_FPSCR_REGNUM || regnum == -1) + regcache_raw_supply (regcache, ARM_FPSCR_REGNUM, regs + 32 * 8); + + for (regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++) + if (regnum == -1 || regnum == regno) + regcache_raw_supply (regcache, regno, + regs + (regno - ARM_D0_REGNUM) * 8); +} + +static void +arm_linux_collect_vfp (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *regs_buf, size_t len) +{ + gdb_byte *regs = regs_buf; + int regno; + + if (regnum == ARM_FPSCR_REGNUM || regnum == -1) + regcache_raw_collect (regcache, ARM_FPSCR_REGNUM, regs + 32 * 8); + + for (regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++) + if (regnum == -1 || regnum == regno) + regcache_raw_collect (regcache, regno, + regs + (regno - ARM_D0_REGNUM) * 8); +} + /* Return the appropriate register set for the core section identified by SECT_NAME and SECT_SIZE. */ @@ -665,9 +707,62 @@ arm_linux_regset_from_core_section (struct gdbarch *gdbarch, return tdep->fpregset; } + if (strcmp (sect_name, ".reg-arm-vfp") == 0 + && sect_size == ARM_LINUX_SIZEOF_VFP) + { + if (tdep->vfpregset == NULL) + tdep->vfpregset = regset_alloc (gdbarch, arm_linux_supply_vfp, + arm_linux_collect_vfp); + return tdep->vfpregset; + } + + return NULL; +} + +/* Core file register set sections. */ + +static struct core_regset_section arm_linux_fpa_regset_sections[] = +{ + { ".reg", ARM_LINUX_SIZEOF_GREGSET, "general-purpose" }, + { ".reg2", ARM_LINUX_SIZEOF_NWFPE, "FPA floating-point" }, + { NULL, 0} +}; + +static struct core_regset_section arm_linux_vfp_regset_sections[] = +{ + { ".reg", ARM_LINUX_SIZEOF_GREGSET, "general-purpose" }, + { ".reg-arm-vfp", ARM_LINUX_SIZEOF_VFP, "VFP floating-point" }, + { NULL, 0} +}; + +/* Determine target description from core file. */ + +static const struct target_desc * +arm_linux_core_read_description (struct gdbarch *gdbarch, + struct target_ops *target, + bfd *abfd) +{ + CORE_ADDR arm_hwcap = 0; + + if (target_auxv_search (target, AT_HWCAP, &arm_hwcap) != 1) + return NULL; + + if (arm_hwcap & HWCAP_VFP) + { + /* NEON implies VFPv3-D32 or no-VFP unit. Say that we only support + Neon with VFPv3-D32. */ + if (arm_hwcap & HWCAP_NEON) + return tdesc_arm_with_neon; + else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3) + return tdesc_arm_with_vfpv3; + else + return tdesc_arm_with_vfpv2; + } + return NULL; } + /* Copy the value of next pc of sigreturn and rt_sigrturn into PC, return 1. In addition, set IS_THUMB depending on whether we will return to ARM or Thumb code. Return 0 if it is not a @@ -1036,6 +1131,12 @@ arm_linux_init_abi (struct gdbarch_info info, /* Core file support. */ set_gdbarch_regset_from_core_section (gdbarch, arm_linux_regset_from_core_section); + set_gdbarch_core_read_description (gdbarch, arm_linux_core_read_description); + + if (tdep->have_vfp_registers) + set_gdbarch_core_regset_sections (gdbarch, arm_linux_vfp_regset_sections); + else if (tdep->have_fpa_registers) + set_gdbarch_core_regset_sections (gdbarch, arm_linux_fpa_regset_sections); set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type); diff --git a/gdb/arm-linux-tdep.h b/gdb/arm-linux-tdep.h index 248994d..d967e43 100644 --- a/gdb/arm-linux-tdep.h +++ b/gdb/arm-linux-tdep.h @@ -59,3 +59,12 @@ void arm_linux_supply_nwfpe (const struct regset *regset, void arm_linux_collect_nwfpe (const struct regset *regset, const struct regcache *regcache, int regnum, void *regs_buf, size_t len); + +/* ARM GNU/Linux HWCAP values. These are in defined 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 + diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 2dd8c9e..433ce21 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -56,6 +56,10 @@ #include "vec.h" #include "features/arm-with-m.c" +#include "features/arm-with-iwmmxt.c" +#include "features/arm-with-vfpv2.c" +#include "features/arm-with-vfpv3.c" +#include "features/arm-with-neon.c" static int arm_debug; @@ -8800,6 +8804,10 @@ _initialize_arm_tdep (void) /* Initialize the standard target descriptions. */ initialize_tdesc_arm_with_m (); + initialize_tdesc_arm_with_iwmmxt (); + initialize_tdesc_arm_with_vfpv2 (); + initialize_tdesc_arm_with_vfpv3 (); + initialize_tdesc_arm_with_neon (); /* Get the number of possible sets of register names defined in opcodes. */ num_disassembly_options = get_arm_regname_num_options (); diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h index fe27c7f..b6d44a2 100644 --- a/gdb/arm-tdep.h +++ b/gdb/arm-tdep.h @@ -191,7 +191,7 @@ struct gdbarch_tdep enum struct_return struct_return; /* Cached core file helpers. */ - struct regset *gregset, *fpregset; + struct regset *gregset, *fpregset, *vfpregset; /* ISA-specific data types. */ struct type *arm_ext_type; @@ -339,4 +339,11 @@ extern const struct regset * armbsd_regset_from_core_section (struct gdbarch *gdbarch, const char *sect_name, size_t sect_size); +/* Target descriptions. */ +extern struct target_desc *tdesc_arm_with_m; +extern struct target_desc *tdesc_arm_with_iwmmxt; +extern struct target_desc *tdesc_arm_with_vfpv2; +extern struct target_desc *tdesc_arm_with_vfpv3; +extern struct target_desc *tdesc_arm_with_neon; + #endif /* arm-tdep.h */ |