This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[rfc/rfa] VFP/NEON register set support for ARM core files
- From: "Ulrich Weigand" <uweigand at de dot ibm dot com>
- To: gdb-patches at sourceware dot org, binutils at sourceware dot org
- Cc: patches at linaro dot org, dave dot martin at linaro dot org, will dot deacon at arm dot com
- Date: Tue, 5 Apr 2011 20:50:14 +0200 (CEST)
- Subject: [rfc/rfa] VFP/NEON register set support for ARM core files
Hello,
the ARM kernel currently does not save VFP/NEON registers into core files.
However, the patch set available here:
http://lists.infradead.org/pipermail/linux-arm-kernel/2011-April/047222.html
will add support by providing a new NT_ARM_VFP core file note type,
analogously to how vector registers are handled e.g. on ppc or i386.
This patch adds corresponding support to BFD and GDB to read such notes,
and write them as well (for GDB's generate-core-file command).
Tested on armv7l-unknown-linux-gnuabi on a Linux 2.6.38 kernel with the
above patch set applied. Fixes one gcore.exp test case failure.
Are the BFD parts OK?
I'm planning on committing the GDB parts once kernel support has been
accepted and BFD parts are approved.
ChangeLog:
include/elf/
* common.h (NT_ARM_VFP): Define.
bfd/
* elf-bfd.h (elfcore_write_arm_vfp): Add prototype.
* elf.c (elfcore_grok_arm_vfp): New function.
(elfcore_grok_note): Call it to handle NT_ARM_VFP notes.
(elfcore_write_arm_vfp): New function.
(elfcore_write_register_note): Call it to handle .reg-arm-vfp.
gdb/
* 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.
Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.315
diff -u -p -r1.315 elf-bfd.h
--- bfd/elf-bfd.h 14 Mar 2011 15:54:57 -0000 1.315
+++ bfd/elf-bfd.h 1 Apr 2011 19:19:42 -0000
@@ -2210,6 +2210,8 @@ extern char *elfcore_write_s390_ctrs
(bfd *, char *, int *, const void *, int);
extern char *elfcore_write_s390_prefix
(bfd *, char *, int *, const void *, int);
+extern char *elfcore_write_arm_vfp
+ (bfd *, char *, int *, const void *, int);
extern char *elfcore_write_lwpstatus
(bfd *, char *, int *, long, int, const void *);
extern char *elfcore_write_register_note
Index: bfd/elf.c
===================================================================
RCS file: /cvs/src/src/bfd/elf.c,v
retrieving revision 1.530
diff -u -p -r1.530 elf.c
--- bfd/elf.c 14 Mar 2011 15:54:58 -0000 1.530
+++ bfd/elf.c 1 Apr 2011 19:19:43 -0000
@@ -7950,6 +7950,12 @@ elfcore_grok_s390_prefix (bfd *abfd, Elf
return elfcore_make_note_pseudosection (abfd, ".reg-s390-prefix", note);
}
+static bfd_boolean
+elfcore_grok_arm_vfp (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-arm-vfp", note);
+}
+
#if defined (HAVE_PRPSINFO_T)
typedef prpsinfo_t elfcore_psinfo_t;
#if defined (HAVE_PRPSINFO32_T) /* Sparc64 cross Sparc32 */
@@ -8363,6 +8369,13 @@ elfcore_grok_note (bfd *abfd, Elf_Intern
else
return TRUE;
+ case NT_ARM_VFP:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_arm_vfp (abfd, note);
+ else
+ return TRUE;
+
case NT_PRPSINFO:
case NT_PSINFO:
if (bed->elf_backend_grok_psinfo)
@@ -9088,6 +9101,18 @@ elfcore_write_s390_prefix (bfd *abfd,
}
char *
+elfcore_write_arm_vfp (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *arm_vfp,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_ARM_VFP, arm_vfp, size);
+}
+
+char *
elfcore_write_register_note (bfd *abfd,
char *buf,
int *bufsiz,
@@ -9117,6 +9142,8 @@ elfcore_write_register_note (bfd *abfd,
return elfcore_write_s390_ctrs (abfd, buf, bufsiz, data, size);
if (strcmp (section, ".reg-s390-prefix") == 0)
return elfcore_write_s390_prefix (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-arm-vfp") == 0)
+ return elfcore_write_arm_vfp (abfd, buf, bufsiz, data, size);
return NULL;
}
Index: gdb/arm-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-linux-nat.c,v
retrieving revision 1.47
diff -u -p -r1.47 arm-linux-nat.c
--- gdb/arm-linux-nat.c 21 Feb 2011 15:03:37 -0000 1.47
+++ gdb/arm-linux-nat.c 1 Apr 2011 19:19:43 -0000
@@ -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 targe
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 targe
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;
}
Index: gdb/arm-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-linux-tdep.c,v
retrieving revision 1.85
diff -u -p -r1.85 arm-linux-tdep.c
--- gdb/arm-linux-tdep.c 1 Apr 2011 11:57:02 -0000 1.85
+++ gdb/arm-linux-tdep.c 1 Apr 2011 19:19:43 -0000
@@ -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 re
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 (stru
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
@@ -1041,6 +1136,12 @@ arm_linux_init_abi (struct gdbarch_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);
Index: gdb/arm-linux-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/arm-linux-tdep.h,v
retrieving revision 1.9
diff -u -p -r1.9 arm-linux-tdep.h
--- gdb/arm-linux-tdep.h 1 Jan 2011 15:32:57 -0000 1.9
+++ gdb/arm-linux-tdep.h 1 Apr 2011 19:19:43 -0000
@@ -59,3 +59,12 @@ void arm_linux_supply_nwfpe (const struc
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
+
Index: gdb/arm-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.c,v
retrieving revision 1.340
diff -u -p -r1.340 arm-tdep.c
--- gdb/arm-tdep.c 1 Apr 2011 11:57:02 -0000 1.340
+++ gdb/arm-tdep.c 1 Apr 2011 19:19:45 -0000
@@ -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;
@@ -8707,6 +8711,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 ();
Index: gdb/arm-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.h,v
retrieving revision 1.50
diff -u -p -r1.50 arm-tdep.h
--- gdb/arm-tdep.h 1 Apr 2011 11:57:03 -0000 1.50
+++ gdb/arm-tdep.h 1 Apr 2011 19:19:45 -0000
@@ -190,7 +190,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 */
Index: include/elf/common.h
===================================================================
RCS file: /cvs/src/src/include/elf/common.h,v
retrieving revision 1.126
diff -u -p -r1.126 common.h
--- include/elf/common.h 10 Mar 2011 10:23:37 -0000 1.126
+++ include/elf/common.h 1 Apr 2011 19:19:46 -0000
@@ -538,6 +538,8 @@
/* note name must be "LINUX". */
#define NT_S390_PREFIX 0x305 /* S390 prefix register */
/* note name must be "LINUX". */
+#define NT_ARM_VFP 0x400 /* ARM VFP registers */
+ /* note name must be "LINUX". */
/* Note segments for core files on dir-style procfs systems. */
--
Dr. Ulrich Weigand
GNU Toolchain for Linux on System z and Cell BE
Ulrich.Weigand@de.ibm.com