This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA/doc] Add support for ARM VFP and NEON registers


This patch adds support for the ARM VFP and NEON units.  GDB has long
supported the FPA floating point unit, which hasn't been seen in
hardware in many years; the main place we find it is in software
emulation for pre-EABI GNU/Linux binaries.  VFP is present in a lot
of new parts, including Cortex-A8 and Cortex-A9.

The included support works for ARM GNU/Linux (both native and
gdbserver, 2.6.30 kernel required), and for remote targets.  There's
two new XML features which are documented in gdb.texinfo, and also a
NEWS entry - Eli, are these OK?

Tested on ARM GNU/Linux.  We've also tested this in the past using
the QEMU simulator.

-- 
Daniel Jacobowitz
CodeSourcery

2009-07-28  Daniel Jacobowitz  <dan@codesourcery.com>

	gdb/testsuite/
	* gdb.base/float.exp: Handle VFP registers.

	gdb/
	* NEWS: Mention ARM VFP support.
	* target-descriptions.c (tdesc_register_type): Make public.
	(tdesc_unnumbered_register): New function.
	(tdesc_register_reggroup_p): Allow missing
	pseudo_register_reggroup_p.
	* target-descriptions.h (tdesc_register_type): Declare.
	(tdesc_unnumbered_register): Declare.
	* arm-tdep.c (arm_neon_quad_read, arm_neon_quad_write): New functions.
	(arm_push_dummy_call): Use arm_neon_quad_write.
	(arm_neon_double_type, arm_neon_quad_type): New functions.
	(arm_register_type): Handle VFP and NEON registers.  Override the
	types of double-precision registers for NEON.  Disable FPA registers
	if they are not present.
	(arm_dwarf_reg_to_regnum): Add current VFP and NEON register numbers.
	(arm_return_value): Use arm_neon_quad_write and arm_neon_quad_read.
	(arm_register_name): Handle VFP single and NEON quad registers.
	(arm_pseudo_read, arm_pseudo_write): New functions.
	(arm_gdbarch_init): Check for VFP and NEON in the target description.
	Assign numbers to double-precision registers.  Register VFP and NEON
	pseudo registers.  Remove a shadowed "i" variable.
	* arm-tdep.h (enum gdb_regnum): Add ARM_D0_REGNUM and
	ARM_D31_REGNUM.
	(struct gdbarch_tdep): Add have_neon_pseudos, have_neon,
	have_vfp_registers, have_vfp_pseudos, neon_double_type,
	and neon_quad_type.

	* features/Makefile: Make expedite settings only architecture
	specific.
	(WHICH): Add new ARM descriptions.
	* features/arm-with-neon.xml, features/arm-with-vfpv2.c,
	features/arm-with-vfpv3.c, features/arm-vfpv2.xml,
	features/arm-vfpv3.xml, features/arm-with-vfpv2.xml,
	features/arm-with-vfpv3.xml, features/arm-with-neon.c: New files.
	* regformats/arm-with-neon.dat, regformats/arm-with-vfpv2.dat,
	regformats/arm-with-vfpv3.dat: Generate.

	gdb/doc/
	* gdb.texinfo (ARM Features): Document org.gnu.gdb.arm.vfp and
	org.gnu.gdb.arm.neon.

	gdb/gdbserver/
	* linux-low.c (linux_write_memory): Update debugging output.
	* Makefile.in (clean): Add new descriptions.
	(arm-with-vfpv2.o, arm-with-vfpv2.c, arm-with-vfpv3.o)
	(arm-with-vfpv3.c, arm-with-neon.o, arm-with-neon.c): New rules.
	* configure.srv: Add new files for arm*-*-linux*.
	* linux-arm-low.c: Add new declarations.
	(PTRACE_GETVFPREGS, PTRACE_SETVFPREGS): Define if undefined.
	(arm_hwcap, HWCAP_VFP, HWCAP_IWMMXT, HWCAP_NEON, HWCAP_VFPv3)
	(HWCAP_VFPv3D16): New.
	(arm_fill_wmmxregset, arm_store_wmmxregset): Check HWCAP_IWMMXT
	instead of __IWMMXT__.
	(arm_fill_vfpregset, arm_store_vfpregset, arm_get_hwcap)
	(arm_arch_setup): New.
	(target_regsets): Remove #ifdef.  Add VFP regset.
	(the_low_target): Use arm_arch_setup.

---
 gdb/NEWS                          |    9 
 gdb/arm-tdep.c                    |  446 ++++++++++++++++++++++++++++++++++++--
 gdb/arm-tdep.h                    |   11 
 gdb/doc/gdb.texinfo               |   13 +
 gdb/features/Makefile             |   25 --
 gdb/features/arm-vfpv2.xml        |   28 ++
 gdb/features/arm-vfpv3.xml        |   44 +++
 gdb/features/arm-with-neon.c      |   72 ++++++
 gdb/features/arm-with-neon.xml    |   13 +
 gdb/features/arm-with-vfpv2.c     |   54 ++++
 gdb/features/arm-with-vfpv2.xml   |   12 +
 gdb/features/arm-with-vfpv3.c     |   70 +++++
 gdb/features/arm-with-vfpv3.xml   |   12 +
 gdb/gdbserver/Makefile.in         |   13 +
 gdb/gdbserver/configure.srv       |    8 
 gdb/gdbserver/linux-arm-low.c     |  153 ++++++++++++-
 gdb/gdbserver/linux-low.c         |   11 
 gdb/regformats/arm-with-neon.dat  |   63 +++++
 gdb/regformats/arm-with-vfpv2.dat |   47 ++++
 gdb/regformats/arm-with-vfpv3.dat |   63 +++++
 gdb/target-descriptions.c         |   22 +
 gdb/target-descriptions.h         |   11 
 gdb/testsuite/gdb.base/float.exp  |    5 
 23 files changed, 1150 insertions(+), 55 deletions(-)

Index: gdb-mainline/gdb/arm-tdep.c
===================================================================
--- gdb-mainline.orig/gdb/arm-tdep.c	2009-07-28 08:50:52.000000000 -0700
+++ gdb-mainline/gdb/arm-tdep.c	2009-07-28 08:50:52.000000000 -0700
@@ -208,6 +208,13 @@ static void convert_from_extended (const
 static void convert_to_extended (const struct floatformat *, void *,
 				 const void *, int);
 
+static void arm_neon_quad_read (struct gdbarch *gdbarch,
+				struct regcache *regcache,
+				int regnum, gdb_byte *buf);
+static void arm_neon_quad_write (struct gdbarch *gdbarch,
+				 struct regcache *regcache,
+				 int regnum, const gdb_byte *buf);
+
 struct arm_prologue_cache
 {
   /* The stack pointer at the time this frame was created; i.e. the
@@ -1710,11 +1717,17 @@ arm_push_dummy_call (struct gdbarch *gdb
 		{
 		  char name_buf[4];
 		  int regnum;
-		  sprintf (name_buf, "%c%d", reg_char, reg_scaled + i);
-		  regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
-							strlen (name_buf));
-		  regcache_cooked_write (regcache, regnum,
+		  if (reg_char == 'q')
+		    arm_neon_quad_write (gdbarch, regcache, reg_scaled + i,
 					 val + i * unit_length);
+		  else
+		    {
+		      sprintf (name_buf, "%c%d", reg_char, reg_scaled + i);
+		      regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+							    strlen (name_buf));
+		      regcache_cooked_write (regcache, regnum,
+					     val + i * unit_length);
+		    }
 		}
 	      continue;
 	    }
@@ -1875,14 +1888,115 @@ arm_ext_type (struct gdbarch *gdbarch)
   return tdep->arm_ext_type;
 }
 
+static struct type *
+arm_neon_double_type (struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (tdep->neon_double_type == NULL)
+    {
+      struct type *t, *elem;
+
+      t = arch_composite_type (gdbarch, "__gdb_builtin_type_neon_d",
+			       TYPE_CODE_UNION);
+      elem = builtin_type (gdbarch)->builtin_uint8;
+      append_composite_type_field (t, "u8", init_vector_type (elem, 8));
+      elem = builtin_type (gdbarch)->builtin_uint16;
+      append_composite_type_field (t, "u16", init_vector_type (elem, 4));
+      elem = builtin_type (gdbarch)->builtin_uint32;
+      append_composite_type_field (t, "u32", init_vector_type (elem, 2));
+      elem = builtin_type (gdbarch)->builtin_uint64;
+      append_composite_type_field (t, "u64", elem);
+      elem = builtin_type (gdbarch)->builtin_float;
+      append_composite_type_field (t, "f32", init_vector_type (elem, 2));
+      elem = builtin_type (gdbarch)->builtin_double;
+      append_composite_type_field (t, "f64", elem);
+
+      TYPE_VECTOR (t) = 1;
+      TYPE_NAME (t) = "neon_d";
+      tdep->neon_double_type = t;
+    }
+
+  return tdep->neon_double_type;
+}
+
+/* FIXME: The vector types are not correctly ordered on big-endian
+   targets.  Just as s0 is the low bits of d0, d0[0] is also the low
+   bits of d0 - regardless of what unit size is being held in d0.  So
+   the offset of the first uint8 in d0 is 7, but the offset of the
+   first float is 4.  This code works as-is for little-endian
+   targets.  */
+
+static struct type *
+arm_neon_quad_type (struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (tdep->neon_quad_type == NULL)
+    {
+      struct type *t, *elem;
+
+      t = arch_composite_type (gdbarch, "__gdb_builtin_type_neon_q",
+			       TYPE_CODE_UNION);
+      elem = builtin_type (gdbarch)->builtin_uint8;
+      append_composite_type_field (t, "u8", init_vector_type (elem, 16));
+      elem = builtin_type (gdbarch)->builtin_uint16;
+      append_composite_type_field (t, "u16", init_vector_type (elem, 8));
+      elem = builtin_type (gdbarch)->builtin_uint32;
+      append_composite_type_field (t, "u32", init_vector_type (elem, 4));
+      elem = builtin_type (gdbarch)->builtin_uint64;
+      append_composite_type_field (t, "u64", init_vector_type (elem, 2));
+      elem = builtin_type (gdbarch)->builtin_float;
+      append_composite_type_field (t, "f32", init_vector_type (elem, 4));
+      elem = builtin_type (gdbarch)->builtin_double;
+      append_composite_type_field (t, "f64", init_vector_type (elem, 2));
+
+      TYPE_VECTOR (t) = 1;
+      TYPE_NAME (t) = "neon_q";
+      tdep->neon_quad_type = t;
+    }
+
+  return tdep->neon_quad_type;
+}
+
 /* Return the GDB type object for the "standard" data type of data in
    register N.  */
 
 static struct type *
 arm_register_type (struct gdbarch *gdbarch, int regnum)
 {
+  int num_regs = gdbarch_num_regs (gdbarch);
+
+  if (gdbarch_tdep (gdbarch)->have_vfp_pseudos
+      && regnum >= num_regs && regnum < num_regs + 32)
+    return builtin_type (gdbarch)->builtin_float;
+
+  if (gdbarch_tdep (gdbarch)->have_neon_pseudos
+      && regnum >= num_regs + 32 && regnum < num_regs + 32 + 16)
+    return arm_neon_quad_type (gdbarch);
+
+  /* If the target description has register information, we are only
+     in this function so that we can override the types of
+     double-precision registers for NEON.  */
+  if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+    {
+      struct type *t = tdesc_register_type (gdbarch, regnum);
+
+      if (regnum >= ARM_D0_REGNUM && regnum < ARM_D0_REGNUM + 32
+	  && TYPE_CODE (t) == TYPE_CODE_FLT
+	  && gdbarch_tdep (gdbarch)->have_neon)
+	return arm_neon_double_type (gdbarch);
+      else
+	return t;
+    }
+
   if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS)
-    return arm_ext_type (gdbarch);
+    {
+      if (!gdbarch_tdep (gdbarch)->have_fpa_registers)
+	return builtin_type (gdbarch)->builtin_void;
+
+      return arm_ext_type (gdbarch);
+    }
   else if (regnum == ARM_SP_REGNUM)
     return builtin_type (gdbarch)->builtin_data_ptr;
   else if (regnum == ARM_PC_REGNUM)
@@ -1926,6 +2040,34 @@ arm_dwarf_reg_to_regnum (struct gdbarch 
   if (reg >= 192 && reg <= 199)
     return ARM_WC0_REGNUM + reg - 192;
 
+  /* VFP v2 registers.  A double precision value is actually
+     in d1 rather than s2, but the ABI only defines numbering
+     for the single precision registers.  This will "just work"
+     in GDB for little endian targets (we'll read eight bytes,
+     starting in s0 and then progressing to s1), but will be
+     reversed on big endian targets with VFP.  This won't
+     be a problem for the new Neon quad registers; you're supposed
+     to use DW_OP_piece for those.  */
+  if (reg >= 64 && reg <= 95)
+    {
+      char name_buf[4];
+
+      sprintf (name_buf, "s%d", reg - 64);
+      return user_reg_map_name_to_regnum (gdbarch, name_buf,
+					  strlen (name_buf));
+    }
+
+  /* VFP v3 / Neon registers.  This range is also used for VFP v2
+     registers, except that it now describes d0 instead of s0.  */
+  if (reg >= 256 && reg <= 287)
+    {
+      char name_buf[4];
+
+      sprintf (name_buf, "d%d", reg - 256);
+      return user_reg_map_name_to_regnum (gdbarch, name_buf,
+					  strlen (name_buf));
+    }
+
   return -1;
 }
 
@@ -3070,17 +3212,31 @@ arm_return_value (struct gdbarch *gdbarc
       int i;
       for (i = 0; i < vfp_base_count; i++)
 	{
-	  char name_buf[4];
-	  int regnum;
-	  sprintf (name_buf, "%c%d", reg_char, i);
-	  regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
-						strlen (name_buf));
-	  if (writebuf)
-	    regcache_cooked_write (regcache, regnum,
-				   writebuf + i * unit_length);
-	  if (readbuf)
-	    regcache_cooked_read (regcache, regnum,
-				  readbuf + i * unit_length);
+	  if (reg_char == 'q')
+	    {
+	      if (writebuf)
+		arm_neon_quad_write (gdbarch, regcache, i,
+				     writebuf + i * unit_length);
+
+	      if (readbuf)
+		arm_neon_quad_read (gdbarch, regcache, i,
+				    readbuf + i * unit_length);
+	    }
+	  else
+	    {
+	      char name_buf[4];
+	      int regnum;
+
+	      sprintf (name_buf, "%c%d", reg_char, i);
+	      regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+						    strlen (name_buf));
+	      if (writebuf)
+		regcache_cooked_write (regcache, regnum,
+				       writebuf + i * unit_length);
+	      if (readbuf)
+		regcache_cooked_read (regcache, regnum,
+				      readbuf + i * unit_length);
+	    }
 	}
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
@@ -3337,6 +3493,32 @@ set_disassembly_style_sfunc (char *args,
 static const char *
 arm_register_name (struct gdbarch *gdbarch, int i)
 {
+  const int num_regs = gdbarch_num_regs (gdbarch);
+
+  if (gdbarch_tdep (gdbarch)->have_vfp_pseudos
+      && i >= num_regs && i < num_regs + 32)
+    {
+      static const char *const vfp_pseudo_names[] = {
+	"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+	"s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
+	"s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
+	"s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
+      };
+
+      return vfp_pseudo_names[i - num_regs];
+    }
+
+  if (gdbarch_tdep (gdbarch)->have_neon_pseudos
+      && i >= num_regs + 32 && i < num_regs + 32 + 16)
+    {
+      static const char *const neon_pseudo_names[] = {
+	"q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
+	"q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15",
+      };
+
+      return neon_pseudo_names[i - num_regs - 32];
+    }
+
   if (i >= ARRAY_SIZE (arm_register_names))
     /* These registers are only supported on targets which supply
        an XML description.  */
@@ -3474,6 +3656,140 @@ arm_write_pc (struct regcache *regcache,
     }
 }
 
+/* Read the contents of a NEON quad register, by reading from two
+   double registers.  This is used to implement the quad pseudo
+   registers, and for argument passing in case the quad registers are
+   missing; vectors are passed in quad registers when using the VFP
+   ABI, even if a NEON unit is not present.  REGNUM is the index of
+   the quad register, in [0, 15].  */
+
+static void
+arm_neon_quad_read (struct gdbarch *gdbarch, struct regcache *regcache,
+		    int regnum, gdb_byte *buf)
+{
+  char name_buf[4];
+  gdb_byte reg_buf[8];
+  int offset, double_regnum;
+
+  sprintf (name_buf, "d%d", regnum << 1);
+  double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+					       strlen (name_buf));
+
+  /* d0 is always the least significant half of q0.  */
+  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+    offset = 8;
+  else
+    offset = 0;
+
+  regcache_raw_read (regcache, double_regnum, reg_buf);
+  memcpy (buf + offset, reg_buf, 8);
+
+  offset = 8 - offset;
+  regcache_raw_read (regcache, double_regnum + 1, reg_buf);
+  memcpy (buf + offset, reg_buf, 8);
+}
+
+static void
+arm_pseudo_read (struct gdbarch *gdbarch, struct regcache *regcache,
+		 int regnum, gdb_byte *buf)
+{
+  const int num_regs = gdbarch_num_regs (gdbarch);
+  char name_buf[4];
+  gdb_byte reg_buf[8];
+  int offset, double_regnum;
+
+  gdb_assert (regnum >= num_regs);
+  regnum -= num_regs;
+
+  if (gdbarch_tdep (gdbarch)->have_neon_pseudos && regnum >= 32 && regnum < 48)
+    /* Quad-precision register.  */
+    arm_neon_quad_read (gdbarch, regcache, regnum - 32, buf);
+  else
+    {
+      /* Single-precision register.  */
+      gdb_assert (regnum < 32);
+
+      /* s0 is always the least significant half of d0.  */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	offset = (regnum & 1) ? 0 : 4;
+      else
+	offset = (regnum & 1) ? 4 : 0;
+
+      sprintf (name_buf, "d%d", regnum >> 1);
+      double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+						   strlen (name_buf));
+
+      regcache_raw_read (regcache, double_regnum, reg_buf);
+      memcpy (buf, reg_buf + offset, 4);
+    }
+}
+
+/* Store the contents of BUF to a NEON quad register, by writing to
+   two double registers.  This is used to implement the quad pseudo
+   registers, and for argument passing in case the quad registers are
+   missing; vectors are passed in quad registers when using the VFP
+   ABI, even if a NEON unit is not present.  REGNUM is the index
+   of the quad register, in [0, 15].  */
+
+static void
+arm_neon_quad_write (struct gdbarch *gdbarch, struct regcache *regcache,
+		     int regnum, const gdb_byte *buf)
+{
+  char name_buf[4];
+  gdb_byte reg_buf[8];
+  int offset, double_regnum;
+
+  sprintf (name_buf, "d%d", regnum << 1);
+  double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+					       strlen (name_buf));
+
+  /* d0 is always the least significant half of q0.  */
+  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+    offset = 8;
+  else
+    offset = 0;
+
+  regcache_raw_write (regcache, double_regnum, buf + offset);
+  offset = 8 - offset;
+  regcache_raw_write (regcache, double_regnum + 1, buf + offset);
+}
+
+static void
+arm_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
+		  int regnum, const gdb_byte *buf)
+{
+  const int num_regs = gdbarch_num_regs (gdbarch);
+  char name_buf[4];
+  gdb_byte reg_buf[8];
+  int offset, double_regnum;
+
+  gdb_assert (regnum >= num_regs);
+  regnum -= num_regs;
+
+  if (gdbarch_tdep (gdbarch)->have_neon_pseudos && regnum >= 32 && regnum < 48)
+    /* Quad-precision register.  */
+    arm_neon_quad_write (gdbarch, regcache, regnum - 32, buf);
+  else
+    {
+      /* Single-precision register.  */
+      gdb_assert (regnum < 32);
+
+      /* s0 is always the least significant half of d0.  */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	offset = (regnum & 1) ? 0 : 4;
+      else
+	offset = (regnum & 1) ? 4 : 0;
+
+      sprintf (name_buf, "d%d", regnum >> 1);
+      double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+						   strlen (name_buf));
+
+      regcache_raw_read (regcache, double_regnum, reg_buf);
+      memcpy (reg_buf + offset, buf, 4);
+      regcache_raw_write (regcache, double_regnum, reg_buf);
+    }
+}
+
 static struct value *
 value_of_arm_user_reg (struct frame_info *frame, const void *baton)
 {
@@ -3518,6 +3834,8 @@ arm_gdbarch_init (struct gdbarch_info in
   enum arm_float_model fp_model = arm_fp_model;
   struct tdesc_arch_data *tdesc_data = NULL;
   int i;
+  int have_vfp_registers = 0, have_vfp_pseudos = 0, have_neon_pseudos = 0;
+  int have_neon = 0;
   int have_fpa_registers = 1;
 
   /* Check any target description for validity.  */
@@ -3530,7 +3848,7 @@ arm_gdbarch_init (struct gdbarch_info in
       static const char *const arm_pc_names[] = { "r15", "pc", NULL };
 
       const struct tdesc_feature *feature;
-      int i, valid_p;
+      int valid_p;
 
       feature = tdesc_find_feature (info.target_desc,
 				    "org.gnu.gdb.arm.core");
@@ -3612,6 +3930,67 @@ arm_gdbarch_init (struct gdbarch_info in
 	      return NULL;
 	    }
 	}
+
+      /* If we have a VFP unit, check whether the single precision registers
+	 are present.  If not, then we will synthesize them as pseudo
+	 registers.  */
+      feature = tdesc_find_feature (info.target_desc,
+				    "org.gnu.gdb.arm.vfp");
+      if (feature != NULL)
+	{
+	  static const char *const vfp_double_names[] = {
+	    "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+	    "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
+	    "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
+	    "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
+	  };
+
+	  /* Require the double precision registers.  There must be either
+	     16 or 32.  */
+	  valid_p = 1;
+	  for (i = 0; i < 32; i++)
+	    {
+	      valid_p &= tdesc_numbered_register (feature, tdesc_data,
+						  ARM_D0_REGNUM + i,
+						  vfp_double_names[i]);
+	      if (!valid_p)
+		break;
+	    }
+
+	  if (!valid_p && i != 16)
+	    {
+	      tdesc_data_cleanup (tdesc_data);
+	      return NULL;
+	    }
+
+	  if (tdesc_unnumbered_register (feature, "s0") == 0)
+	    have_vfp_pseudos = 1;
+
+	  have_vfp_registers = 1;
+
+	  /* If we have VFP, also check for NEON.  The architecture allows
+	     NEON without VFP (integer vector operations only), but GDB
+	     does not support that.  */
+	  feature = tdesc_find_feature (info.target_desc,
+					"org.gnu.gdb.arm.neon");
+	  if (feature != NULL)
+	    {
+	      /* NEON requires 32 double-precision registers.  */
+	      if (i != 32)
+		{
+		  tdesc_data_cleanup (tdesc_data);
+		  return NULL;
+		}
+
+	      /* If there are quad registers defined by the stub, use
+		 their type; otherwise (normally) provide them with
+		 the default type.  */
+	      if (tdesc_unnumbered_register (feature, "q0") == 0)
+		have_neon_pseudos = 1;
+
+	      have_neon = 1;
+	    }
+	}
     }
 
   /* If we have an object to base this architecture on, try to determine
@@ -3755,6 +4134,11 @@ arm_gdbarch_init (struct gdbarch_info in
 	  && fp_model != gdbarch_tdep (best_arch->gdbarch)->fp_model)
 	continue;
 
+      /* There are various other properties in tdep that we do not
+	 need to check here: those derived from a target description,
+	 since gdbarches with a different target description are
+	 automatically disqualified.  */
+
       /* Found a match.  */
       break;
     }
@@ -3774,6 +4158,10 @@ arm_gdbarch_init (struct gdbarch_info in
   tdep->arm_abi = arm_abi;
   tdep->fp_model = fp_model;
   tdep->have_fpa_registers = have_fpa_registers;
+  tdep->have_vfp_registers = have_vfp_registers;
+  tdep->have_vfp_pseudos = have_vfp_pseudos;
+  tdep->have_neon_pseudos = have_neon_pseudos;
+  tdep->have_neon = have_neon;
 
   /* Breakpoints.  */
   switch (info.byte_order_for_code)
@@ -3913,8 +4301,30 @@ arm_gdbarch_init (struct gdbarch_info in
       set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
     }
 
+  if (have_vfp_pseudos)
+    {
+      /* NOTE: These are the only pseudo registers used by
+	 the ARM target at the moment.  If more are added, a
+	 little more care in numbering will be needed.  */
+
+      int num_pseudos = 32;
+      if (have_neon_pseudos)
+	num_pseudos += 16;
+      set_gdbarch_num_pseudo_regs (gdbarch, num_pseudos);
+      set_gdbarch_pseudo_register_read (gdbarch, arm_pseudo_read);
+      set_gdbarch_pseudo_register_write (gdbarch, arm_pseudo_write);
+    }
+
   if (tdesc_data)
-    tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
+    {
+      set_tdesc_pseudo_register_name (gdbarch, arm_register_name);
+
+      tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
+
+      /* Override tdesc_register_type to adjust the types of VFP
+	 registers for NEON.  */
+      set_gdbarch_register_type (gdbarch, arm_register_type);
+    }
 
   /* Add standard register aliases.  We add aliases even for those
      nanes which are used by the current architecture - it's simpler,
Index: gdb-mainline/gdb/arm-tdep.h
===================================================================
--- gdb-mainline.orig/gdb/arm-tdep.h	2009-07-28 08:43:02.000000000 -0700
+++ gdb-mainline/gdb/arm-tdep.h	2009-07-28 08:50:52.000000000 -0700
@@ -47,6 +47,8 @@ enum gdb_regnum {
   ARM_WCGR0_REGNUM,		/* WMMX general purpose registers.  */
   ARM_WCGR3_REGNUM = ARM_WCGR0_REGNUM + 3,
   ARM_WCGR7_REGNUM = ARM_WCGR0_REGNUM + 7,
+  ARM_D0_REGNUM,		/* VFP double-precision registers.  */
+  ARM_D31_REGNUM = ARM_D0_REGNUM + 31,
 
   ARM_NUM_REGS,
 
@@ -151,6 +153,13 @@ struct gdbarch_tdep
   enum arm_float_model fp_model; /* Floating point calling conventions.  */
 
   int have_fpa_registers;	/* Does the target report the FPA registers?  */
+  int have_vfp_registers;	/* Does the target report the VFP registers?  */
+  int have_vfp_pseudos;		/* Are we synthesizing the single precision
+				   VFP registers?  */
+  int have_neon_pseudos;	/* Are we synthesizing the quad precision
+				   NEON registers?  Requires
+				   have_vfp_pseudos.  */
+  int have_neon;		/* Do we have a NEON unit?  */
 
   CORE_ADDR lowest_pc;		/* Lowest address at which instructions 
 				   will appear.  */
@@ -173,6 +182,8 @@ struct gdbarch_tdep
 
   /* ISA-specific data types.  */
   struct type *arm_ext_type;
+  struct type *neon_double_type;
+  struct type *neon_quad_type;
 };
 
 
Index: gdb-mainline/gdb/features/Makefile
===================================================================
--- gdb-mainline.orig/gdb/features/Makefile	2009-07-28 08:43:02.000000000 -0700
+++ gdb-mainline/gdb/features/Makefile	2009-07-28 08:50:52.000000000 -0700
@@ -31,28 +31,17 @@
 # in the GDB repository.  To generate C files:
 #   make GDB=/path/to/gdb XMLTOC="xml files" cfiles
 
-WHICH = arm-with-iwmmxt mips-linux mips64-linux \
+WHICH = arm-with-iwmmxt arm-with-vfpv2 arm-with-vfpv3 arm-with-neon \
+	mips-linux mips64-linux \
 	rs6000/powerpc-32l rs6000/powerpc-altivec32l rs6000/powerpc-e500l \
 	rs6000/powerpc-64l rs6000/powerpc-altivec64l rs6000/powerpc-vsx32l \
 	rs6000/powerpc-vsx64l
 
 # Record which registers should be sent to GDB by default after stop.
-arm-with-iwmmxt-expedite = r11,sp,pc
-mips-linux-expedite = r29,pc
-mips64-linux-expedite = r29,pc
-rs6000/powerpc-32l-expedite = r1,pc
-rs6000/powerpc-altivec32l-expedite = r1,pc
-rs6000/powerpc-vsx32l-expedite = r1,pc
-rs6000/powerpc-isa205-32l-expedite = r1,pc
-rs6000/powerpc-isa205-altivec32l-expedite = r1,pc
-rs6000/powerpc-isa205-vsx32l-expedite = r1,pc
-rs6000/powerpc-e500l-expedite = r1,pc
-rs6000/powerpc-64l-expedite = r1,pc
-rs6000/powerpc-altivec64l-expedite = r1,pc
-rs6000/powerpc-vsx64l-expedite = r1,pc
-rs6000/powerpc-isa205-64l-expedite = r1,pc
-rs6000/powerpc-isa205-altivec64l-expedite = r1,pc
-rs6000/powerpc-isa205-vsx64l-expedite = r1,pc
+arm-expedite = r11,sp,pc
+mips-expedite = r29,pc
+mips64-expedite = r29,pc
+powerpc-expedite = r1,pc
 
 
 XSLTPROC = xsltproc
@@ -69,7 +58,7 @@ $(outdir)/%.dat: %.xml number-regs.xsl s
 	echo "# DO NOT EDIT: generated from $<" > $(outdir)/$*.tmp
 	echo "name:`echo $(notdir $*) | sed 's/-/_/g'`" >> $(outdir)/$*.tmp
 	echo "xmltarget:$(<F)" >> $(outdir)/$*.tmp
-	echo "expedite:$($*-expedite)" >> $(outdir)/$*.tmp
+	echo "expedite:$($(firstword $(subst -, ,$(notdir $*)))-expedite)" >> $(outdir)/$*.tmp
 	$(XSLTPROC) --path "$(PWD)" --xinclude number-regs.xsl $< | \
 	  $(XSLTPROC) sort-regs.xsl - | \
 	  $(XSLTPROC) gdbserver-regs.xsl - >> $(outdir)/$*.tmp
Index: gdb-mainline/gdb/features/arm-vfpv2.xml
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gdb-mainline/gdb/features/arm-vfpv2.xml	2009-07-28 08:50:52.000000000 -0700
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2009 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.vfp">
+  <reg name="d0" bitsize="64" type="ieee_double"/>
+  <reg name="d1" bitsize="64" type="ieee_double"/>
+  <reg name="d2" bitsize="64" type="ieee_double"/>
+  <reg name="d3" bitsize="64" type="ieee_double"/>
+  <reg name="d4" bitsize="64" type="ieee_double"/>
+  <reg name="d5" bitsize="64" type="ieee_double"/>
+  <reg name="d6" bitsize="64" type="ieee_double"/>
+  <reg name="d7" bitsize="64" type="ieee_double"/>
+  <reg name="d8" bitsize="64" type="ieee_double"/>
+  <reg name="d9" bitsize="64" type="ieee_double"/>
+  <reg name="d10" bitsize="64" type="ieee_double"/>
+  <reg name="d11" bitsize="64" type="ieee_double"/>
+  <reg name="d12" bitsize="64" type="ieee_double"/>
+  <reg name="d13" bitsize="64" type="ieee_double"/>
+  <reg name="d14" bitsize="64" type="ieee_double"/>
+  <reg name="d15" bitsize="64" type="ieee_double"/>
+
+  <reg name="fpscr" bitsize="32" type="int" group="float"/>
+</feature>
Index: gdb-mainline/gdb/features/arm-vfpv3.xml
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gdb-mainline/gdb/features/arm-vfpv3.xml	2009-07-28 08:50:52.000000000 -0700
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2009 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.vfp">
+  <reg name="d0" bitsize="64" type="ieee_double"/>
+  <reg name="d1" bitsize="64" type="ieee_double"/>
+  <reg name="d2" bitsize="64" type="ieee_double"/>
+  <reg name="d3" bitsize="64" type="ieee_double"/>
+  <reg name="d4" bitsize="64" type="ieee_double"/>
+  <reg name="d5" bitsize="64" type="ieee_double"/>
+  <reg name="d6" bitsize="64" type="ieee_double"/>
+  <reg name="d7" bitsize="64" type="ieee_double"/>
+  <reg name="d8" bitsize="64" type="ieee_double"/>
+  <reg name="d9" bitsize="64" type="ieee_double"/>
+  <reg name="d10" bitsize="64" type="ieee_double"/>
+  <reg name="d11" bitsize="64" type="ieee_double"/>
+  <reg name="d12" bitsize="64" type="ieee_double"/>
+  <reg name="d13" bitsize="64" type="ieee_double"/>
+  <reg name="d14" bitsize="64" type="ieee_double"/>
+  <reg name="d15" bitsize="64" type="ieee_double"/>
+  <reg name="d16" bitsize="64" type="ieee_double"/>
+  <reg name="d17" bitsize="64" type="ieee_double"/>
+  <reg name="d18" bitsize="64" type="ieee_double"/>
+  <reg name="d19" bitsize="64" type="ieee_double"/>
+  <reg name="d20" bitsize="64" type="ieee_double"/>
+  <reg name="d21" bitsize="64" type="ieee_double"/>
+  <reg name="d22" bitsize="64" type="ieee_double"/>
+  <reg name="d23" bitsize="64" type="ieee_double"/>
+  <reg name="d24" bitsize="64" type="ieee_double"/>
+  <reg name="d25" bitsize="64" type="ieee_double"/>
+  <reg name="d26" bitsize="64" type="ieee_double"/>
+  <reg name="d27" bitsize="64" type="ieee_double"/>
+  <reg name="d28" bitsize="64" type="ieee_double"/>
+  <reg name="d29" bitsize="64" type="ieee_double"/>
+  <reg name="d30" bitsize="64" type="ieee_double"/>
+  <reg name="d31" bitsize="64" type="ieee_double"/>
+
+  <reg name="fpscr" bitsize="32" type="int" group="float"/>
+</feature>
Index: gdb-mainline/gdb/features/arm-with-neon.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gdb-mainline/gdb/features/arm-with-neon.c	2009-07-28 08:50:52.000000000 -0700
@@ -0,0 +1,72 @@
+/* THIS FILE IS GENERATED.  Original: arm-with-neon.xml */
+
+#include "defs.h"
+#include "gdbtypes.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_arm_with_neon;
+static void
+initialize_tdesc_arm_with_neon (void)
+{
+  struct target_desc *result = allocate_target_description ();
+  struct tdesc_feature *feature;
+  struct type *field_type, *type;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.arm.core");
+  tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sp", 13, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "lr", 14, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pc", 15, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "cpsr", 25, 1, NULL, 32, "int");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.arm.vfp");
+  tdesc_create_reg (feature, "d0", 26, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d1", 27, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d2", 28, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d3", 29, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d4", 30, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d5", 31, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d6", 32, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d7", 33, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d8", 34, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d9", 35, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d10", 36, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d11", 37, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d12", 38, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d13", 39, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d14", 40, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d15", 41, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d16", 42, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d17", 43, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d18", 44, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d19", 45, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d20", 46, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d21", 47, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d22", 48, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d23", 49, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d24", 50, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d25", 51, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d26", 52, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d27", 53, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d28", 54, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d29", 55, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d30", 56, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d31", 57, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fpscr", 58, 1, "float", 32, "int");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.arm.neon");
+
+  tdesc_arm_with_neon = result;
+}
Index: gdb-mainline/gdb/features/arm-with-neon.xml
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gdb-mainline/gdb/features/arm-with-neon.xml	2009-07-28 08:50:52.000000000 -0700
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2009 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <xi:include href="arm-core.xml"/>
+  <xi:include href="arm-vfpv3.xml"/>
+  <feature name="org.gnu.gdb.arm.neon"/>
+</target>
Index: gdb-mainline/gdb/features/arm-with-vfpv2.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gdb-mainline/gdb/features/arm-with-vfpv2.c	2009-07-28 08:50:52.000000000 -0700
@@ -0,0 +1,54 @@
+/* THIS FILE IS GENERATED.  Original: arm-with-vfpv2.xml */
+
+#include "defs.h"
+#include "gdbtypes.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_arm_with_vfpv2;
+static void
+initialize_tdesc_arm_with_vfpv2 (void)
+{
+  struct target_desc *result = allocate_target_description ();
+  struct tdesc_feature *feature;
+  struct type *field_type, *type;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.arm.core");
+  tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sp", 13, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "lr", 14, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pc", 15, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "cpsr", 25, 1, NULL, 32, "int");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.arm.vfp");
+  tdesc_create_reg (feature, "d0", 26, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d1", 27, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d2", 28, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d3", 29, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d4", 30, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d5", 31, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d6", 32, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d7", 33, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d8", 34, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d9", 35, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d10", 36, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d11", 37, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d12", 38, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d13", 39, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d14", 40, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d15", 41, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fpscr", 42, 1, "float", 32, "int");
+
+  tdesc_arm_with_vfpv2 = result;
+}
Index: gdb-mainline/gdb/features/arm-with-vfpv2.xml
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gdb-mainline/gdb/features/arm-with-vfpv2.xml	2009-07-28 08:50:52.000000000 -0700
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2009 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <xi:include href="arm-core.xml"/>
+  <xi:include href="arm-vfpv2.xml"/>
+</target>
Index: gdb-mainline/gdb/features/arm-with-vfpv3.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gdb-mainline/gdb/features/arm-with-vfpv3.c	2009-07-28 08:50:52.000000000 -0700
@@ -0,0 +1,70 @@
+/* THIS FILE IS GENERATED.  Original: arm-with-vfpv3.xml */
+
+#include "defs.h"
+#include "gdbtypes.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_arm_with_vfpv3;
+static void
+initialize_tdesc_arm_with_vfpv3 (void)
+{
+  struct target_desc *result = allocate_target_description ();
+  struct tdesc_feature *feature;
+  struct type *field_type, *type;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.arm.core");
+  tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sp", 13, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "lr", 14, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pc", 15, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "cpsr", 25, 1, NULL, 32, "int");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.arm.vfp");
+  tdesc_create_reg (feature, "d0", 26, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d1", 27, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d2", 28, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d3", 29, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d4", 30, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d5", 31, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d6", 32, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d7", 33, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d8", 34, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d9", 35, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d10", 36, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d11", 37, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d12", 38, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d13", 39, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d14", 40, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d15", 41, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d16", 42, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d17", 43, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d18", 44, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d19", 45, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d20", 46, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d21", 47, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d22", 48, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d23", 49, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d24", 50, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d25", 51, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d26", 52, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d27", 53, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d28", 54, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d29", 55, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d30", 56, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "d31", 57, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fpscr", 58, 1, "float", 32, "int");
+
+  tdesc_arm_with_vfpv3 = result;
+}
Index: gdb-mainline/gdb/features/arm-with-vfpv3.xml
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gdb-mainline/gdb/features/arm-with-vfpv3.xml	2009-07-28 08:50:52.000000000 -0700
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2009 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <xi:include href="arm-core.xml"/>
+  <xi:include href="arm-vfpv3.xml"/>
+</target>
Index: gdb-mainline/gdb/gdbserver/Makefile.in
===================================================================
--- gdb-mainline.orig/gdb/gdbserver/Makefile.in	2009-07-28 08:43:02.000000000 -0700
+++ gdb-mainline/gdb/gdbserver/Makefile.in	2009-07-28 08:50:52.000000000 -0700
@@ -205,7 +205,9 @@ clean:
 	rm -f reg-arm.c reg-i386.c reg-ia64.c reg-m32r.c reg-m68k.c
 	rm -f reg-sh.c reg-sparc.c reg-spu.c reg-x86-64.c reg-i386-linux.c
 	rm -f reg-cris.c reg-crisv32.c reg-x86-64-linux.c reg-xtensa.c
-	rm -f arm-with-iwmmxt.c mips-linux.c mips64-linux.c
+	rm -f arm-with-iwmmxt.c
+	rm -f arm-with-vfpv2.c arm-with-vfpv3.c arm-with-neon.c
+	rm -f mips-linux.c mips64-linux.c
 	rm -f powerpc-32l.c powerpc-64l.c powerpc-e500l.c
 	rm -f powerpc-altivec32l.c powerpc-vsx32l.c powerpc-altivec64l.c
 	rm -f powerpc-vsx64l.c
@@ -326,6 +328,15 @@ reg-arm.c : $(srcdir)/../regformats/reg-
 arm-with-iwmmxt.o : arm-with-iwmmxt.c $(regdef_h)
 arm-with-iwmmxt.c : $(srcdir)/../regformats/arm-with-iwmmxt.dat $(regdat_sh)
 	$(SHELL) $(regdat_sh) $(srcdir)/../regformats/arm-with-iwmmxt.dat arm-with-iwmmxt.c
+arm-with-vfpv2.o : arm-with-vfpv2.c $(regdef_h)
+arm-with-vfpv2.c : $(srcdir)/../regformats/arm-with-vfpv2.dat $(regdat_sh)
+	$(SHELL) $(regdat_sh) $(srcdir)/../regformats/arm-with-vfpv2.dat arm-with-vfpv2.c
+arm-with-vfpv3.o : arm-with-vfpv3.c $(regdef_h)
+arm-with-vfpv3.c : $(srcdir)/../regformats/arm-with-vfpv3.dat $(regdat_sh)
+	$(SHELL) $(regdat_sh) $(srcdir)/../regformats/arm-with-vfpv3.dat arm-with-vfpv3.c
+arm-with-neon.o : arm-with-neon.c $(regdef_h)
+arm-with-neon.c : $(srcdir)/../regformats/arm-with-neon.dat $(regdat_sh)
+	$(SHELL) $(regdat_sh) $(srcdir)/../regformats/arm-with-neon.dat arm-with-neon.c
 reg-cris.o : reg-cris.c $(regdef_h)
 reg-cris.c : $(srcdir)/../regformats/reg-cris.dat $(regdat_sh)
 	$(SHELL) $(regdat_sh) $(srcdir)/../regformats/reg-cris.dat reg-cris.c
Index: gdb-mainline/gdb/gdbserver/configure.srv
===================================================================
--- gdb-mainline.orig/gdb/gdbserver/configure.srv	2009-07-28 08:43:02.000000000 -0700
+++ gdb-mainline/gdb/gdbserver/configure.srv	2009-07-28 08:50:52.000000000 -0700
@@ -26,10 +26,18 @@ srv_hostio_err_objs="hostio-errno.o"
 
 case "${target}" in
   arm*-*-linux*)	srv_regobj="reg-arm.o arm-with-iwmmxt.o"
+			srv_regobj="${srv_regobj} arm-with-vfpv2.o"
+			srv_regobj="${srv_regobj} arm-with-vfpv3.o"
+			srv_regobj="${srv_regobj} arm-with-neon.o"
 			srv_tgtobj="linux-low.o linux-arm-low.o"
 			srv_xmlfiles="arm-with-iwmmxt.xml"
+			srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv2.xml"
+			srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv3.xml"
+			srv_xmlfiles="${srv_xmlfiles} arm-with-neon.xml"
 			srv_xmlfiles="${srv_xmlfiles} arm-core.xml"
 			srv_xmlfiles="${srv_xmlfiles} xscale-iwmmxt.xml"
+			srv_xmlfiles="${srv_xmlfiles} arm-vfpv2.xml"
+			srv_xmlfiles="${srv_xmlfiles} arm-vfpv3.xml"
 			srv_linux_usrregs=yes
 			srv_linux_regsets=yes
 			srv_linux_thread_db=yes
Index: gdb-mainline/gdb/gdbserver/linux-arm-low.c
===================================================================
--- gdb-mainline.orig/gdb/gdbserver/linux-arm-low.c	2009-07-28 08:43:02.000000000 -0700
+++ gdb-mainline/gdb/gdbserver/linux-arm-low.c	2009-07-28 08:50:52.000000000 -0700
@@ -20,14 +20,17 @@
 #include "server.h"
 #include "linux-low.h"
 
+#include <elf.h>
 #include <sys/ptrace.h>
 
 #include "gdb_proc_service.h"
 
-/* Defined in auto-generated file reg-arm.c.  */
+/* Defined in auto-generated files.  */
 void init_registers_arm (void);
-/* Defined in auto-generated file arm-with-iwmmxt.c.  */
 void init_registers_arm_with_iwmmxt (void);
+void init_registers_arm_with_vfpv2 (void);
+void init_registers_arm_with_vfpv3 (void);
+void init_registers_arm_with_neon (void);
 
 #ifndef PTRACE_GET_THREAD_AREA
 #define PTRACE_GET_THREAD_AREA 22
@@ -38,6 +41,20 @@ void init_registers_arm_with_iwmmxt (voi
 # define PTRACE_SETWMMXREGS 19
 #endif
 
+#ifndef PTRACE_GETVFPREGS
+# define PTRACE_GETVFPREGS 27
+# define PTRACE_SETVFPREGS 28
+#endif
+
+static unsigned long arm_hwcap;
+
+/* 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
+
 #ifdef HAVE_SYS_REG_H
 #include <sys/reg.h>
 #endif
@@ -87,13 +104,14 @@ arm_store_gregset (const void *buf)
       supply_register (i, zerobuf);
 }
 
-#ifdef __IWMMXT__
-
 static void
 arm_fill_wmmxregset (void *buf)
 {
   int i;
 
+  if (!(arm_hwcap & HWCAP_IWMMXT))
+    return;
+
   for (i = 0; i < 16; i++)
     collect_register (arm_num_regs + i, (char *) buf + i * 8);
 
@@ -107,6 +125,9 @@ arm_store_wmmxregset (const void *buf)
 {
   int i;
 
+  if (!(arm_hwcap & HWCAP_IWMMXT))
+    return;
+
   for (i = 0; i < 16; i++)
     supply_register (arm_num_regs + i, (char *) buf + i * 8);
 
@@ -115,7 +136,45 @@ arm_store_wmmxregset (const void *buf)
     supply_register (arm_num_regs + i + 16, (char *) buf + 16 * 8 + i * 4);
 }
 
-#endif /* __IWMMXT__ */
+static void
+arm_fill_vfpregset (void *buf)
+{
+  int i, num, base;
+
+  if (!(arm_hwcap & HWCAP_VFP))
+    return;
+
+  if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
+    num = 32;
+  else
+    num = 16;
+
+  base = find_regno ("d0");
+  for (i = 0; i < num; i++)
+    collect_register (base + i, (char *) buf + i * 8);
+
+  collect_register_by_name ("fpscr", (char *) buf + 32 * 8);
+}
+
+static void
+arm_store_vfpregset (const void *buf)
+{
+  int i, num, base;
+
+  if (!(arm_hwcap & HWCAP_VFP))
+    return;
+
+  if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
+    num = 32;
+  else
+    num = 16;
+
+  base = find_regno ("d0");
+  for (i = 0; i < num; i++)
+    supply_register (base + i, (char *) buf + i * 8);
+
+  supply_register_by_name ("fpscr", (char *) buf + 32 * 8);
+}
 
 extern int debug_threads;
 
@@ -208,24 +267,94 @@ ps_get_thread_area (const struct ps_proc
   return PS_OK;
 }
 
+static int
+arm_get_hwcap (unsigned long *valp)
+{
+  unsigned char *data = alloca (8);
+  int offset = 0;
+
+  while ((*the_target->read_auxv) (offset, data, 8) == 8)
+    {
+      unsigned int *data_p = (unsigned int *)data;
+      if (data_p[0] == AT_HWCAP)
+	{
+	  *valp = data_p[1];
+	  return 1;
+	}
+
+      offset += 8;
+    }
+
+  *valp = 0;
+  return 0;
+}
+
+static void
+arm_arch_setup (void)
+{
+  arm_hwcap = 0;
+  if (arm_get_hwcap (&arm_hwcap) == 0)
+    {
+      init_registers_arm ();
+      return;
+    }
+
+  if (arm_hwcap & HWCAP_IWMMXT)
+    {
+      init_registers_arm_with_iwmmxt ();
+      return;
+    }
+
+  if (arm_hwcap & HWCAP_VFP)
+    {
+      int pid;
+      char *buf;
+
+      /* NEON implies either no VFP, or VFPv3-D32.  We only support
+	 it with VFP.  */
+      if (arm_hwcap & HWCAP_NEON)
+	init_registers_arm_with_neon ();
+      else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
+	init_registers_arm_with_vfpv3 ();
+      else
+	init_registers_arm_with_vfpv2 ();
+
+      /* Now make sure that the kernel supports reading these
+	 registers.  Support was added in 2.6.30.  */
+      pid = lwpid_of (get_thread_lwp (current_inferior));
+      errno = 0;
+      buf = malloc (32 * 8 + 4);
+      if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0
+	  && errno == EIO)
+	{
+	  arm_hwcap = 0;
+	  init_registers_arm ();
+	}
+      free (buf);
+
+      return;
+    }
+
+  /* The default configuration uses legacy FPA registers, probably
+     simulated.  */
+  init_registers_arm ();
+}
+
 struct regset_info target_regsets[] = {
   { PTRACE_GETREGS, PTRACE_SETREGS, 18 * 4,
     GENERAL_REGS,
     arm_fill_gregset, arm_store_gregset },
-#ifdef __IWMMXT__
   { PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS, 16 * 8 + 6 * 4,
     EXTENDED_REGS,
     arm_fill_wmmxregset, arm_store_wmmxregset },
-#endif
+  { PTRACE_GETVFPREGS, PTRACE_SETVFPREGS, 32 * 8 + 4,
+    EXTENDED_REGS,
+    arm_fill_vfpregset, arm_store_vfpregset },
   { 0, 0, -1, -1, NULL, NULL }
 };
 
 struct linux_target_ops the_low_target = {
-#ifdef __IWMMXT__
-  init_registers_arm_with_iwmmxt,
-#else
-  init_registers_arm,
-#endif
+  arm_arch_setup,
   arm_num_regs,
   arm_regmap,
   arm_cannot_fetch_register,
Index: gdb-mainline/gdb/gdbserver/linux-low.c
===================================================================
--- gdb-mainline.orig/gdb/gdbserver/linux-low.c	2009-07-28 08:43:02.000000000 -0700
+++ gdb-mainline/gdb/gdbserver/linux-low.c	2009-07-28 10:49:10.000000000 -0700
@@ -2394,7 +2394,16 @@ linux_write_memory (CORE_ADDR memaddr, c
 
   if (debug_threads)
     {
-      fprintf (stderr, "Writing %02x to %08lx\n", (unsigned)myaddr[0], (long)memaddr);
+      /* Dump up to four bytes.  */
+      unsigned int val = * (unsigned int *) myaddr;
+      if (len == 1)
+	val = val & 0xff;
+      else if (len == 2)
+	val = val & 0xffff;
+      else if (len == 3)
+	val = val & 0xffffff;
+      fprintf (stderr, "Writing %0*x to 0x%08lx\n", 2 * ((len < 4) ? len : 4),
+	       val, (long)memaddr);
     }
 
   /* Fill start and end extra bytes of buffer with existing memory data.  */
Index: gdb-mainline/gdb/regformats/arm-with-neon.dat
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gdb-mainline/gdb/regformats/arm-with-neon.dat	2009-07-28 08:50:52.000000000 -0700
@@ -0,0 +1,63 @@
+# DO NOT EDIT: generated from arm-with-neon.xml
+name:arm_with_neon
+xmltarget:arm-with-neon.xml
+expedite:r11,sp,pc
+32:r0
+32:r1
+32:r2
+32:r3
+32:r4
+32:r5
+32:r6
+32:r7
+32:r8
+32:r9
+32:r10
+32:r11
+32:r12
+32:sp
+32:lr
+32:pc
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+32:cpsr
+64:d0
+64:d1
+64:d2
+64:d3
+64:d4
+64:d5
+64:d6
+64:d7
+64:d8
+64:d9
+64:d10
+64:d11
+64:d12
+64:d13
+64:d14
+64:d15
+64:d16
+64:d17
+64:d18
+64:d19
+64:d20
+64:d21
+64:d22
+64:d23
+64:d24
+64:d25
+64:d26
+64:d27
+64:d28
+64:d29
+64:d30
+64:d31
+32:fpscr
Index: gdb-mainline/gdb/regformats/arm-with-vfpv2.dat
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gdb-mainline/gdb/regformats/arm-with-vfpv2.dat	2009-07-28 08:50:52.000000000 -0700
@@ -0,0 +1,47 @@
+# DO NOT EDIT: generated from arm-with-vfpv2.xml
+name:arm_with_vfpv2
+xmltarget:arm-with-vfpv2.xml
+expedite:r11,sp,pc
+32:r0
+32:r1
+32:r2
+32:r3
+32:r4
+32:r5
+32:r6
+32:r7
+32:r8
+32:r9
+32:r10
+32:r11
+32:r12
+32:sp
+32:lr
+32:pc
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+32:cpsr
+64:d0
+64:d1
+64:d2
+64:d3
+64:d4
+64:d5
+64:d6
+64:d7
+64:d8
+64:d9
+64:d10
+64:d11
+64:d12
+64:d13
+64:d14
+64:d15
+32:fpscr
Index: gdb-mainline/gdb/regformats/arm-with-vfpv3.dat
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gdb-mainline/gdb/regformats/arm-with-vfpv3.dat	2009-07-28 08:50:52.000000000 -0700
@@ -0,0 +1,63 @@
+# DO NOT EDIT: generated from arm-with-vfpv3.xml
+name:arm_with_vfpv3
+xmltarget:arm-with-vfpv3.xml
+expedite:r11,sp,pc
+32:r0
+32:r1
+32:r2
+32:r3
+32:r4
+32:r5
+32:r6
+32:r7
+32:r8
+32:r9
+32:r10
+32:r11
+32:r12
+32:sp
+32:lr
+32:pc
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+32:cpsr
+64:d0
+64:d1
+64:d2
+64:d3
+64:d4
+64:d5
+64:d6
+64:d7
+64:d8
+64:d9
+64:d10
+64:d11
+64:d12
+64:d13
+64:d14
+64:d15
+64:d16
+64:d17
+64:d18
+64:d19
+64:d20
+64:d21
+64:d22
+64:d23
+64:d24
+64:d25
+64:d26
+64:d27
+64:d28
+64:d29
+64:d30
+64:d31
+32:fpscr
Index: gdb-mainline/gdb/target-descriptions.c
===================================================================
--- gdb-mainline.orig/gdb/target-descriptions.c	2009-07-28 08:43:02.000000000 -0700
+++ gdb-mainline/gdb/target-descriptions.c	2009-07-28 08:50:52.000000000 -0700
@@ -619,6 +619,21 @@ tdesc_numbered_register (const struct td
   return 1;
 }
 
+/* Search FEATURE for a register named NAME, but do not assign a fixed
+   register number to it.  */
+
+int
+tdesc_unnumbered_register (const struct tdesc_feature *feature,
+			   const char *name)
+{
+  struct tdesc_reg *reg = tdesc_find_register_early (feature, name);
+
+  if (reg == NULL)
+    return 0;
+
+  return 1;
+}
+
 /* Search FEATURE for a register whose name is in NAMES and assign
    REGNO to it.  */
 
@@ -694,7 +709,7 @@ tdesc_register_name (struct gdbarch *gdb
   return "";
 }
 
-static struct type *
+struct type *
 tdesc_register_type (struct gdbarch *gdbarch, int regno)
 {
   struct tdesc_arch_reg *arch_reg = tdesc_find_arch_register (gdbarch, regno);
@@ -842,8 +857,9 @@ tdesc_register_reggroup_p (struct gdbarc
   if (regno >= num_regs && regno < num_regs + num_pseudo_regs)
     {
       struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data);
-      gdb_assert (data->pseudo_register_reggroup_p != NULL);
-      return data->pseudo_register_reggroup_p (gdbarch, regno, reggroup);
+      if (data->pseudo_register_reggroup_p != NULL)
+	return data->pseudo_register_reggroup_p (gdbarch, regno, reggroup);
+      /* Otherwise fall through to the default reggroup_p.  */
     }
 
   ret = tdesc_register_in_reggroup_p (gdbarch, regno, reggroup);
Index: gdb-mainline/gdb/target-descriptions.h
===================================================================
--- gdb-mainline.orig/gdb/target-descriptions.h	2009-07-28 08:43:02.000000000 -0700
+++ gdb-mainline/gdb/target-descriptions.h	2009-07-28 08:50:52.000000000 -0700
@@ -98,6 +98,12 @@ int tdesc_numbered_register (const struc
 			     struct tdesc_arch_data *data,
 			     int regno, const char *name);
 
+/* Search FEATURE for a register named NAME, but do not assign a fixed
+   register number to it.  */
+
+int tdesc_unnumbered_register (const struct tdesc_feature *feature,
+			       const char *name);
+
 /* Search FEATURE for a register named NAME, and return its size in
    bits.  The register must exist.  */
 
@@ -154,6 +160,11 @@ struct tdesc_type *tdesc_named_type (con
 
 const char *tdesc_register_name (struct gdbarch *gdbarch, int regno);
 
+/* Return the type of register REGNO, from the target description or
+   from an architecture-provided pseudo_register_type method.  */
+
+struct type *tdesc_register_type (struct gdbarch *gdbarch, int regno);
+
 /* Check whether REGNUM is a member of REGGROUP using the target
    description.  Return -1 if the target description does not
    specify a group.  */
Index: gdb-mainline/gdb/testsuite/gdb.base/float.exp
===================================================================
--- gdb-mainline.orig/gdb/testsuite/gdb.base/float.exp	2009-07-28 08:43:02.000000000 -0700
+++ gdb-mainline/gdb/testsuite/gdb.base/float.exp	2009-07-28 08:50:52.000000000 -0700
@@ -51,6 +51,11 @@ if { [istarget "alpha*-*-*"] } then {
 	-re "Software FPU type.*mask:.*flags:.*$gdb_prompt $" {
 	    pass "info float (FPA)"
 	}
+	-re "fpscr.*s0.*s1.*s31.*$gdb_prompt $" {
+	    # Only check for single precision; d0 might be a vector register
+	    # if we have NEON.
+	    pass "info float (VFP)"
+	}
         -re "No floating.point info available for this processor.*" {
             pass "info float (without FPU)"
 	}
Index: gdb-mainline/gdb/NEWS
===================================================================
--- gdb-mainline.orig/gdb/NEWS	2009-07-14 14:40:30.000000000 -0700
+++ gdb-mainline/gdb/NEWS	2009-07-28 10:51:58.000000000 -0700
@@ -64,8 +64,13 @@ operators when expanding macros.  It als
 macros.
 
 * GDB now supports inspecting extra signal information, exported by
-  the new $_siginfo convenience variable.  The feature is currently
-  implemented on linux ARM, i386 and amd64.
+the new $_siginfo convenience variable.  The feature is currently
+implemented on linux ARM, i386 and amd64.
+
+* GDB can now display the VFP floating point registers and NEON vector
+registers on ARM targets.  Both ARM GNU/Linux native GDB and gdbserver
+can provide these registers (requires Linux 2.6.30 or later).  Remote
+and simulator targets may also provide them.
 
 * New remote packets
 
Index: gdb-mainline/gdb/doc/gdb.texinfo
===================================================================
--- gdb-mainline.orig/gdb/doc/gdb.texinfo	2009-07-14 14:40:32.000000000 -0700
+++ gdb-mainline/gdb/doc/gdb.texinfo	2009-07-28 10:57:00.000000000 -0700
@@ -31075,6 +31075,19 @@ it should contain at least registers @sa
 @samp{wCGR0} through @samp{wCGR3}.  The @samp{wCID}, @samp{wCon},
 @samp{wCSSF}, and @samp{wCASF} registers are optional.
 
+The @samp{org.gnu.gdb.arm.vfp} feature is optional.  If present, it
+should contain at least registers @samp{d0} through @samp{d15}.  If
+they are present, @samp{d16} through @samp{d31} should also be included.
+@value{GDBN} will synthesize the single-precision registers from
+halves of the double-precision registers.
+
+The @samp{org.gnu.gdb.arm.neon} feature is optional.  It does not
+need to contain registers; it instructs @value{GDBN} to display the
+VFP double-precision registers as vectors and to synthesize the
+quad-precision registers from pairs of double-precision registers.
+If this feature is present, @samp{org.gnu.gdb.arm.vfp} must also
+be present and include 32 double-precision registers.
+
 @node MIPS Features
 @subsection MIPS Features
 @cindex target descriptions, MIPS features


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]