aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog29
-rw-r--r--gdb/arm-linux-nat.c20
-rw-r--r--gdb/arm-linux-tdep.c101
-rw-r--r--gdb/arm-linux-tdep.h9
-rw-r--r--gdb/arm-tdep.c8
-rw-r--r--gdb/arm-tdep.h9
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 */