Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Daniel Jacobowitz <drow@false.org>
To: gdb-patches@sourceware.org
Cc: Eli Zaretskii <eliz@gnu.org>,
	Aleksandar Ristovski <aristovski@qnx.com>,
		Matt Fischer <mattfischer84@gmail.com>,
		Peter Nordstrom <pxno_64@yahoo.com>
Subject: [RFA/doc] Add support for ARM VFP and NEON registers
Date: Tue, 28 Jul 2009 18:33:00 -0000	[thread overview]
Message-ID: <20090728180310.GA29633@caradoc.them.org> (raw)

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


             reply	other threads:[~2009-07-28 18:03 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-07-28 18:33 Daniel Jacobowitz [this message]
2009-07-28 19:00 ` Eli Zaretskii
2009-07-28 19:03   ` Daniel Jacobowitz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090728180310.GA29633@caradoc.them.org \
    --to=drow@false.org \
    --cc=aristovski@qnx.com \
    --cc=eliz@gnu.org \
    --cc=gdb-patches@sourceware.org \
    --cc=mattfischer84@gmail.com \
    --cc=pxno_64@yahoo.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox