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]

[RFC] Target described register suppport (finally)


This is where I've been going for way too long!  This patch adds the
support for constructs like these in XML target descriptions (taken
from the gdb.xml test case):

+<target>
+  <xi:include href="core-regs.xml"/>
+  <feature name="extra">
+    <vector id="v4int8" type="int8" count="4"/>
+    <vector id="v2int16" type="int16" count="2"/>
+    <union id="vecint">
+      <field name="v4" type="v4int8"/>
+      <field name="v2" type="v2int16"/>
+    </union>
+
+    <reg name="extrareg" bitsize="32"/>
+    <reg name="uintreg" bitsize="32" type="uint32"/>
+    <reg name="vecreg" bitsize="32" type="v4int8"/>
+    <reg name="unionreg" bitsize="32" type="vecint"/>
+  </feature>
+</target>

That defines two vector types, a union type made up of two vector
types, and four custom registers.  If you connected to a remote target
with this target description loaded, GDB would try to read the extra
four registers.  I will post a followup patch which does exactly that
for gdbserver, for a particular more useful set of registers (the
XScale iWMMXt coprocessor).  I'm also planning to do Altivec and SPE
(both PowerPC extensions) and ARM VFP using this, also in gdbserver.

A real description for the default ARM register set is included.

The code is a bit complicated, and per-architecture assistance is
necessary to take advantage of this.  So I've added a short chapter to
the internals manual describing what changes are necessary.  This
is the simplest interface I could come up with, and much better than
my last draft.

Jim, Vladimir, you might want to take a brief look at this.  It's not
quite the same as the version we've been using; Jim persuaded me that
I'd overcomplicated it in a couple of places, so I've simplified it
a bit.  <feature-ref> and <feature-set> are gone, for instance.  I'll
probably do a compatibility layer for our internal tree, or else just
update all our descriptions.

Richard, I CC'd you because I added support for described registers to
the ARM target in this patch as a starting point.  I also adjusted
the way register names are handled.  I've made register synonyms work
all the time, regardless of what you set for the disassembly style.
So you can say $ip or $r12, and both will work.  I think that's a
definite improvement.

Tested on arm-none-linux-gnueabi, with and without the iwmmxt patch,
and on x86_64-pc-linux-gnu.  Any thoughts on this patch, or the
included documentation?  Does it look OK?

-- 
Daniel Jacobowitz
CodeSourcery

2007-01-29  Daniel Jacobowitz  <dan@codesourcery.com>

	* Makefile.in (arm-tdep.o, eval.o, target-descriptions.o)
	(xml-tdesc.o): Update.
	* xml-support.c: Add a comment.
	(gdb_xml_enums_boolean): New variable.
	(gdb_xml_parse_attr_enum): Use strcasecmp.
	* xml-support.h (gdb_xml_enums_boolean): Declare.
	* xml-tdesc.c (struct tdesc_parsing_data): Record current_feature,
	next_regnum, and current_union.
	(tdesc_start_feature, tdesc_start_reg, tdesc_start_union)
	(tdesc_end_union, tdesc_start_field, tdesc_start_vector)
	(field_attributes, union_children, reg_attributes, union_attributes)
	(vector_attributes, feature_attributes, feature_children): New.
	(target_children): Make static.  Add <feature>.
	(tdesc_elements): Make static.
	* target-descriptions.c (struct tdesc_reg, tdesc_reg_p, type_p)
	(struct tdesc_feature, tdesc_feature_p): New types.
	(struct target_desc): Add features member.
	(struct tdesc_arch_data, tdesc_data): New.
	(target_find_description): Clarify error message.  Warn about
	ignored register descriptions.
	(tdesc_has_registers, tdesc_find_feature, tdesc_feature_name)
	(tdesc_named_type, tdesc_data_init, tdesc_data_alloc)
	(tdesc_data_cleanup, tdesc_numbered_register)
	(tdesc_numbered_register_choices, tdesc_find_register)
	(tdesc_register_name, tdesc_register_type)
	(tdesc_remote_register_number, tdesc_register_reggroup_p)
	(set_tdesc_pseudo_register_name, set_tdesc_pseudo_register_type)
	(set_tdesc_pseudo_register_reggroup_p, tdesc_use_registers)
	(tdesc_free_reg, tdesc_create_reg, tdesc_free_feature)
	(tdesc_create_feature, tdesc_record_type): New.
	(free_target_description): Free features.
	(_initialize_target_descriptions): Initialize tdesc_data.
	* arch-utils.c (default_remote_register_number): New.
	* arch-utils.h (default_remote_register_number): New prototype.
	* target-descriptions.h (set_tdesc_pseudo_register_name)
	(set_tdesc_pseudo_register_type, set_tdesc_pseudo_register_reggroup_p)
	(tdesc_use_registers, tdesc_data_alloc, tdesc_data_cleanup)
	(tdesc_numbered_register, tdesc_numbered_register_choices)
	(tdesc_has_registers, tdesc_find_feature, tdesc_feature_name)
	(tdesc_named_type, tdesc_create_feature, tdesc_record_type)
	(tdesc_create_reg): Declare.
	* gdbarch.sh (remote_register_number): New entry.
	* gdbarch.c, gdbarch.h: Regenerate.
	* remote.c (init_remote_state): Use gdbarch_remote_register_number.
	* features/gdb-target.dtd: Add feature, reg, vector, union, and field.

	* arm-tdep.c (arm_register_aliases): New.
	(arm_register_name_strings): Rename to...
	(arm_register_names): ...this.  Make const.  Delete the old version.
	(current_option, arm_register_byte): Delete.
	(set_disassembly_style): Simplify.  Do not adjust arm_register_names.
	(value_of_arm_user_reg): New.
	(arm_gdbarch_init): Verify any described registers.  Call
	tdesc_use_registers.  Don't use arm_register_byte.  Create aliases
	for standard register names.
	(_initialize_arm_tdep): Do not adjust arm_register_names.
	* user-regs.c (struct user_reg): Add baton member.
	(append_user_reg, user_reg_add_builtin, user_regs_init)
	(user_reg_add, value_of_user_reg): Use a baton for user
	register functions.
	* std-regs.c: Update.
	* user-regs.h (user_reg_read_ftype, user_reg_add_builtin)
	(user_reg_add): Add baton argument.
	* NEWS: Mention target description register support.
	* features/arm-core.xml, features/arm-fpa.xml: New.
	* eval.c (evaluate_subexp_standard): Allow ptype $register
	when the program is not running.

	* gdb.texinfo (Requirements): Add anchor for Expat.  Update
	description.
	(Target Descriptions): Mention Expat.
	(Target Description Format): Document new elements.
	(Predefined Target Types, Standard Target Features): New sections.
	* doc/gdbint.texinfo (Target Descriptions): New section.

	* gdb.xml/single-reg.xml, gdb.xml/tdesc-regs.exp,
	gdb.xml/core-only.xml, gdb.xml/extra-regs.xml: New files.

---
 gdb/Makefile.in                      |   11 
 gdb/NEWS                             |    4 
 gdb/arch-utils.c                     |    7 
 gdb/arch-utils.h                     |    3 
 gdb/arm-tdep.c                       |  199 +++++++---
 gdb/doc/gdb.texinfo                  |  224 +++++++++++-
 gdb/doc/gdbint.texinfo               |  128 ++++++
 gdb/eval.c                           |    7 
 gdb/features/arm-core.xml            |   31 +
 gdb/features/arm-fpa.xml             |   23 +
 gdb/features/gdb-target.dtd          |   31 +
 gdb/gdbarch.c                        |   24 +
 gdb/gdbarch.h                        |    7 
 gdb/gdbarch.sh                       |    4 
 gdb/remote.c                         |    5 
 gdb/std-regs.c                       |   20 -
 gdb/target-descriptions.c            |  641 ++++++++++++++++++++++++++++++++++-
 gdb/target-descriptions.h            |   93 +++++
 gdb/testsuite/gdb.xml/core-only.xml  |    3 
 gdb/testsuite/gdb.xml/extra-regs.xml |   16 
 gdb/testsuite/gdb.xml/single-reg.xml |    5 
 gdb/testsuite/gdb.xml/tdesc-regs.exp |   95 +++++
 gdb/user-regs.c                      |   20 -
 gdb/user-regs.h                      |    7 
 gdb/xml-support.c                    |   12 
 gdb/xml-support.h                    |    3 
 gdb/xml-tdesc.c                      |  233 ++++++++++++
 27 files changed, 1752 insertions(+), 104 deletions(-)

Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in	2007-01-29 12:39:10.000000000 -0500
+++ src/gdb/Makefile.in	2007-01-29 12:39:17.000000000 -0500
@@ -1823,7 +1823,8 @@ arm-tdep.o: arm-tdep.c $(defs_h) $(frame
 	$(frame_unwind_h) $(frame_base_h) $(trad_frame_h) $(arm_tdep_h) \
 	$(gdb_sim_arm_h) $(elf_bfd_h) $(coff_internal_h) $(elf_arm_h) \
 	$(gdb_assert_h) $(bfd_in2_h) $(libcoff_h) $(objfiles_h) \
-	$(dwarf2_frame_h) $(gdbtypes_h) $(prologue_value_h)
+	$(dwarf2_frame_h) $(gdbtypes_h) $(prologue_value_h) \
+	$(target_descriptions_h) $(user_regs_h)
 auxv.o: auxv.c $(defs_h) $(target_h) $(gdbtypes_h) $(command_h) \
 	$(inferior_h) $(valprint_h) $(gdb_assert_h) $(auxv_h) \
 	$(elf_common_h)
@@ -1986,7 +1987,7 @@ eval.o: eval.c $(defs_h) $(gdb_string_h)
 	$(value_h) $(expression_h) $(target_h) $(frame_h) $(language_h) \
 	$(f_lang_h) $(cp_abi_h) $(infcall_h) $(objc_lang_h) $(block_h) \
 	$(parser_defs_h) $(cp_support_h) $(gdb_assert_h) $(exceptions_h) \
-	$(uiout_h)
+	$(uiout_h) $(regcache_h)
 event-loop.o: event-loop.c $(defs_h) $(event_loop_h) $(event_top_h) \
 	$(gdb_string_h) $(exceptions_h) $(gdb_assert_h) $(gdb_select_h)
 event-top.o: event-top.c $(defs_h) $(top_h) $(inferior_h) $(target_h) \
@@ -2793,7 +2794,8 @@ target.o: target.c $(defs_h) $(gdb_strin
 	$(exceptions_h) $(target_descriptions_h)
 target-descriptions.o: target-descriptions.c $(defs_h) $(arch_utils_h) \
 	$(target_h) $(target_descriptions_h) $(vec_h) $(xml_tdesc_h) \
-	$(gdbcmd_h) $(gdb_assert_h)
+	$(gdbcmd_h) $(gdb_assert_h) $(gdbtypes_h) $(reggroups_h) \
+	$(xml_support_h) $(gdb_obstack_h) $(hashtab_h)
 target-memory.o: target-memory.c $(defs_h) $(vec_h) $(target_h) \
 	$(memory_map_h) $(gdb_assert_h)
 thread.o: thread.c $(defs_h) $(symtab_h) $(frame_h) $(inferior_h) \
@@ -2892,7 +2894,8 @@ xcoffread.o: xcoffread.c $(defs_h) $(bfd
 xcoffsolib.o: xcoffsolib.c $(defs_h) $(bfd_h) $(xcoffsolib_h) $(inferior_h) \
 	$(gdbcmd_h) $(symfile_h) $(frame_h) $(gdb_regex_h)
 xml-tdesc.o: xml-tdesc.c $(defs_h) $(target_h) $(target_descriptions_h) \
-	$(xml_tdesc_h) $(xml_support_h) $(filenames_h) $(gdb_assert_h)
+	$(xml_tdesc_h) $(xml_support_h) $(filenames_h) $(gdb_assert_h) \
+	$(gdbtypes_h)
 xml-support.o: xml-support.c $(defs_h) $(xml_support_h) $(exceptions_h) \
 	$(gdbcmd_h) $(gdb_string_h) $(gdb_expat_h) $(safe_ctype_h)
 xstormy16-tdep.o: xstormy16-tdep.c $(defs_h) $(frame_h) $(frame_base_h) \
Index: src/gdb/xml-support.c
===================================================================
--- src.orig/gdb/xml-support.c	2007-01-29 12:39:10.000000000 -0500
+++ src/gdb/xml-support.c	2007-01-29 12:39:17.000000000 -0500
@@ -40,6 +40,8 @@ static int debug_xml;
    we just want to avoid running out of stack on loops.  */
 #define MAX_XINCLUDE_DEPTH 30
 
+/* Simplified XML parser infrastructure.  */
+
 /* A parsing level -- used to keep track of the current element
    nesting.  */
 struct scope_level
@@ -631,6 +633,14 @@ gdb_xml_parse_attr_ulongest (struct gdb_
   return ret;
 }
 
+/* A handler_data for yes/no boolean values.  */
+
+const struct gdb_xml_enum gdb_xml_enums_boolean[] = {
+  { "yes", 1 },
+  { "no", 0 },
+  { NULL, 0 }
+};
+
 /* Map NAME to VALUE.  A struct gdb_xml_enum * should be saved as the
    value of handler_data when using gdb_xml_parse_attr_enum to parse a
    fixed list of possible strings.  The list is terminated by an entry
@@ -645,7 +655,7 @@ gdb_xml_parse_attr_enum (struct gdb_xml_
   void *ret;
 
   for (enums = attribute->handler_data; enums->name != NULL; enums++)
-    if (strcmp (enums->name, value) == 0)
+    if (strcasecmp (enums->name, value) == 0)
       break;
 
   if (enums->name == NULL)
Index: src/gdb/xml-support.h
===================================================================
--- src.orig/gdb/xml-support.h	2007-01-29 12:39:10.000000000 -0500
+++ src/gdb/xml-support.h	2007-01-29 12:39:17.000000000 -0500
@@ -209,6 +209,9 @@ struct gdb_xml_enum
   ULONGEST value;
 };
 
+/* A handler_data for yes/no boolean values.  */
+extern const struct gdb_xml_enum gdb_xml_enums_boolean[];
+
 extern gdb_xml_attribute_handler gdb_xml_parse_attr_enum;
 
 /* Parse an integer string into a ULONGEST and return it, or call
Index: src/gdb/xml-tdesc.c
===================================================================
--- src.orig/gdb/xml-tdesc.c	2007-01-29 12:39:15.000000000 -0500
+++ src/gdb/xml-tdesc.c	2007-01-29 15:43:31.000000000 -0500
@@ -23,6 +23,7 @@
    Boston, MA 02110-1301, USA.  */
 
 #include "defs.h"
+#include "gdbtypes.h"
 #include "target.h"
 #include "target-descriptions.h"
 #include "xml-support.h"
@@ -79,6 +80,16 @@ struct tdesc_parsing_data
 {
   /* The target description we are building.  */
   struct target_desc *tdesc;
+
+  /* The target feature we are currently parsing, or last parsed.  */
+  struct tdesc_feature *current_feature;
+
+  /* The register number to use for the next register we see, if
+     it does not have its own.  This starts at zero.  */
+  int next_regnum;
+
+  /* The union we are currently parsing, or last parsed.  */
+  struct type *current_union;
 };
 
 /* Handle the end of an <architecture> element and its value.  */
@@ -98,15 +109,233 @@ tdesc_end_arch (struct gdb_xml_parser *p
   set_tdesc_architecture (data->tdesc, arch);
 }
 
+/* Handle the start of a <feature> element.  */
+
+static void
+tdesc_start_feature (struct gdb_xml_parser *parser,
+		     const struct gdb_xml_element *element,
+		     void *user_data, VEC(gdb_xml_value_s) *attributes)
+{
+  struct tdesc_parsing_data *data = user_data;
+  char *name = VEC_index (gdb_xml_value_s, attributes, 0)->value;
+
+  data->current_feature = tdesc_create_feature (data->tdesc, name);
+}
+
+/* Handle the start of a <reg> element.  Fill in the optional
+   attributes and attach it to the containing feature.  */
+
+static void
+tdesc_start_reg (struct gdb_xml_parser *parser,
+		 const struct gdb_xml_element *element,
+		 void *user_data, VEC(gdb_xml_value_s) *attributes)
+{
+  struct tdesc_parsing_data *data = user_data;
+  struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes);
+  int ix = 0, length;
+  char *name, *group, *type;
+  int bitsize, regnum, save_restore;
+
+  length = VEC_length (gdb_xml_value_s, attributes);
+
+  name = attrs[ix++].value;
+  bitsize = * (ULONGEST *) attrs[ix++].value;
+
+  if (ix < length && strcmp (attrs[ix].name, "regnum") == 0)
+    regnum = * (ULONGEST *) attrs[ix++].value;
+  else
+    regnum = data->next_regnum;
+
+  if (ix < length && strcmp (attrs[ix].name, "type") == 0)
+    type = attrs[ix++].value;
+  else
+    type = "int";
+
+  if (ix < length && strcmp (attrs[ix].name, "group") == 0)
+    group = attrs[ix++].value;
+  else
+    group = NULL;
+
+  if (ix < length && strcmp (attrs[ix].name, "save-restore") == 0)
+    save_restore = * (ULONGEST *) attrs[ix++].value;
+  else
+    save_restore = 1;
+
+  if (strcmp (type, "int") != 0
+      && strcmp (type, "float") != 0
+      && tdesc_named_type (data->current_feature, type) == NULL)
+    gdb_xml_error (parser, _("Register \"%s\" has unknown type \"%s\""),
+		   name, type);
+
+  tdesc_create_reg (data->current_feature, name, regnum, save_restore, group,
+		    bitsize, type);
+
+  data->next_regnum = regnum + 1;
+}
+
+/* Handle the start of a <union> element.  Initialize the type and
+   record it with the current feature.  */
+
+static void
+tdesc_start_union (struct gdb_xml_parser *parser,
+		   const struct gdb_xml_element *element,
+		   void *user_data, VEC(gdb_xml_value_s) *attributes)
+{
+  struct tdesc_parsing_data *data = user_data;
+  char *id = VEC_index (gdb_xml_value_s, attributes, 0)->value;
+  struct type *type;
+
+  type = init_composite_type (NULL, TYPE_CODE_UNION);
+  TYPE_NAME (type) = xstrdup (id);
+  tdesc_record_type (data->current_feature, type);
+  data->current_union = type;
+}
+
+/* Handle the end of a <union> element.  */
+
+static void
+tdesc_end_union (struct gdb_xml_parser *parser,
+		 const struct gdb_xml_element *element,
+		 void *user_data, const char *body_text)
+{
+  struct tdesc_parsing_data *data = user_data;
+  int i;
+
+  /* If any of the children of this union are vectors, flag the union
+     as a vector also.  This allows e.g. a union of two vector types
+     to show up automatically in "info vector".  */
+  for (i = 0; i < TYPE_NFIELDS (data->current_union); i++)
+    if (TYPE_VECTOR (TYPE_FIELD_TYPE (data->current_union, i)))
+      {
+        TYPE_FLAGS (data->current_union) |= TYPE_FLAG_VECTOR;
+        break;
+      }
+}
+
+/* Handle the start of a <field> element.  Attach the field to the
+   current union.  */
+
+static void
+tdesc_start_field (struct gdb_xml_parser *parser,
+		   const struct gdb_xml_element *element,
+		   void *user_data, VEC(gdb_xml_value_s) *attributes)
+{
+  struct tdesc_parsing_data *data = user_data;
+  struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes);
+  struct type *type, *field_type;
+  char *field_name, *field_type_id;
+
+  field_name = attrs[0].value;
+  field_type_id = attrs[1].value;
+
+  field_type = tdesc_named_type (data->current_feature, field_type_id);
+  if (field_type == NULL)
+    gdb_xml_error (parser, _("Union field \"%s\" references undefined "
+			     "type \"%s\""),
+		   field_name, field_type_id);
+
+  append_composite_type_field (data->current_union, xstrdup (field_name),
+			       field_type);
+}
+
+/* Handle the start of a <vector> element.  Initialize the type and
+   record it with the current feature.  */
+
+static void
+tdesc_start_vector (struct gdb_xml_parser *parser,
+		    const struct gdb_xml_element *element,
+		    void *user_data, VEC(gdb_xml_value_s) *attributes)
+{
+  struct tdesc_parsing_data *data = user_data;
+  struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes);
+  struct type *type, *field_type, *range_type;
+  char *id, *field_type_id;
+  int count;
+
+  id = attrs[0].value;
+  field_type_id = attrs[1].value;
+  count = * (ULONGEST *) attrs[2].value;
+
+  field_type = tdesc_named_type (data->current_feature, field_type_id);
+  if (field_type == NULL)
+    gdb_xml_error (parser, _("Vector \"%s\" references undefined type \"%s\""),
+		   id, field_type_id);
+
+  /* A vector is just an array plus a special flag.  */
+  range_type = create_range_type (NULL, builtin_type_int, 0, count - 1);
+  type = create_array_type (NULL, field_type, range_type);
+  TYPE_NAME (type) = xstrdup (id);
+
+  TYPE_FLAGS (type) |= TYPE_FLAG_VECTOR;
+
+  tdesc_record_type (data->current_feature, type);
+}
+
 /* The elements and attributes of an XML target description.  */
 
-const struct gdb_xml_element target_children[] = {
+static const struct gdb_xml_attribute field_attributes[] = {
+  { "name", GDB_XML_AF_NONE, NULL, NULL },
+  { "type", GDB_XML_AF_NONE, NULL, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element union_children[] = {
+  { "field", field_attributes, NULL, GDB_XML_EF_REPEATABLE,
+    tdesc_start_field, NULL },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_attribute reg_attributes[] = {
+  { "name", GDB_XML_AF_NONE, NULL, NULL },
+  { "bitsize", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { "regnum", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
+  { "type", GDB_XML_AF_OPTIONAL, NULL, NULL },
+  { "group", GDB_XML_AF_OPTIONAL, NULL, NULL },
+  { "save-restore", GDB_XML_AF_OPTIONAL,
+    gdb_xml_parse_attr_enum, gdb_xml_enums_boolean },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_attribute union_attributes[] = {
+  { "id", GDB_XML_AF_NONE, NULL, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_attribute vector_attributes[] = {
+  { "id", GDB_XML_AF_NONE, NULL, NULL },
+  { "type", GDB_XML_AF_NONE, NULL, NULL },
+  { "count", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_attribute feature_attributes[] = {
+  { "name", GDB_XML_AF_NONE, NULL, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element feature_children[] = {
+  { "reg", reg_attributes, NULL,
+    GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
+    tdesc_start_reg, NULL },
+  { "union", union_attributes, union_children,
+    GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
+    tdesc_start_union, tdesc_end_union },
+  { "vector", vector_attributes, NULL,
+    GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
+    tdesc_start_vector, NULL },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element target_children[] = {
   { "architecture", NULL, NULL, GDB_XML_EF_OPTIONAL,
     NULL, tdesc_end_arch },
+  { "feature", feature_attributes, feature_children,
+    GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
+    tdesc_start_feature, NULL },
   { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
 };
 
-const struct gdb_xml_element tdesc_elements[] = {
+static const struct gdb_xml_element tdesc_elements[] = {
   { "target", NULL, target_children, GDB_XML_EF_NONE,
     NULL, NULL },
   { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
Index: src/gdb/target-descriptions.c
===================================================================
--- src.orig/gdb/target-descriptions.c	2007-01-29 12:37:11.000000000 -0500
+++ src/gdb/target-descriptions.c	2007-01-29 12:39:17.000000000 -0500
@@ -24,12 +24,17 @@
 #include "defs.h"
 #include "arch-utils.h"
 #include "gdbcmd.h"
+#include "gdbtypes.h"
+#include "reggroups.h"
 #include "target.h"
 #include "target-descriptions.h"
 #include "vec.h"
+#include "xml-support.h"
 #include "xml-tdesc.h"
 
 #include "gdb_assert.h"
+#include "gdb_obstack.h"
+#include "hashtab.h"
 
 /* Types.  */
 
@@ -40,6 +45,69 @@ typedef struct property
 } property_s;
 DEF_VEC_O(property_s);
 
+/* An individual register from a target description.  */
+
+typedef struct tdesc_reg
+{
+  /* The name of this register.  In standard features, it may be
+     recognized by the architecture support code, or it may be purely
+     for the user.  */
+  char *name;
+
+  /* The register number used by this target to refer to this
+     register.  This is used for remote p/P packets and to determine
+     the ordering of registers in the remote g/G packets.  */
+  long target_regnum;
+
+  /* If this flag is set, GDB should save and restore this register
+     around calls to an inferior function.  */
+  int save_restore;
+
+  /* The name of the register group containing this register, or NULL
+     if the group should be automatically determined from the
+     register's type.  If this is "general", "float", or "vector", the
+     corresponding "info" command should display this register's
+     value.  It can be an arbitrary string, but should be limited to
+     alphanumeric characters and internal hyphens.  Currently other
+     strings are ignored (treated as NULL).  */
+  char *group;
+
+  /* The size of the register, in bits.  */
+  int bitsize;
+
+  /* The type of the register.  This string corresponds to either
+     a named type from the target description or a predefined
+     type from GDB.  */
+  char *type;
+
+  /* The target-described type corresponding to TYPE, if found.  */
+  struct type *gdb_type;
+} *tdesc_reg_p;
+DEF_VEC_P(tdesc_reg_p);
+
+/* A named type from a target description.  */
+typedef struct type *type_p;
+DEF_VEC_P(type_p);
+
+/* A feature from a target description.  Each feature is a collection
+   of other elements, e.g. registers and types.  */
+
+typedef struct tdesc_feature
+{
+  /* The name of this feature.  It may be recognized by the architecture
+     support code.  */
+  char *name;
+
+  /* The registers associated with this feature.  */
+  VEC(tdesc_reg_p) *registers;
+
+  /* The types associated with this feature.  */
+  VEC(type_p) *types;
+} *tdesc_feature_p;
+DEF_VEC_P(tdesc_feature_p);
+
+/* A target description.  */
+
 struct target_desc
 {
   /* The architecture reported by the target, if any.  */
@@ -47,6 +115,30 @@ struct target_desc
 
   /* Any architecture-specific properties specified by the target.  */
   VEC(property_s) *properties;
+
+  /* The features associated with this target.  */
+  VEC(tdesc_feature_p) *features;
+};
+
+/* Per-architecture data associated with a target description.  The
+   target description may be shared by multiple architectures, but
+   this data is private to one gdbarch.  */
+
+struct tdesc_arch_data
+{
+  /* A list of registers, indexed by GDB's internal register number.
+     During initialization of the gdbarch this list is used to store
+     registers which the architecture assigns a fixed register number.
+     Registers which are NULL in this array, or off the end, are
+     treated as zero-sized and nameless (i.e. placeholders in the
+     numbering).  */
+  VEC(tdesc_reg_p) *registers;
+
+  /* Functions which report the register name, type, and reggroups for
+     pseudo-registers.  */
+  gdbarch_register_name_ftype *pseudo_register_name;
+  gdbarch_register_type_ftype *pseudo_register_type;
+  gdbarch_register_reggroup_p_ftype *pseudo_register_reggroup_p;
 };
 
 /* Global state.  These variables are associated with the current
@@ -72,6 +164,11 @@ static const struct target_desc *current
 
 static char *target_description_filename;
 
+/* A handle for architecture-specific data associated with the
+   target description (see struct tdesc_arch_data).  */
+
+static struct gdbarch_data *tdesc_data;
+
 /* Fetch the current target's description, and switch the current
    architecture to one which incorporates that description.  */
 
@@ -116,7 +213,17 @@ target_find_description (void)
       gdbarch_info_init (&info);
       info.target_desc = current_target_desc;
       if (!gdbarch_update_p (info))
-	warning (_("Could not use target-supplied description"));
+	warning (_("Architecture rejected target-supplied description"));
+      else
+	{
+	  struct tdesc_arch_data *data;
+
+	  data = gdbarch_data (current_gdbarch, tdesc_data);
+	  if (tdesc_has_registers (current_target_desc)
+	      && data->registers == NULL)
+	    warning (_("Target-supplied registers are not supported "
+		       "by the current architecture"));
+	}
     }
 
   /* Now that we know this description is usable, record that we
@@ -158,7 +265,7 @@ target_current_description (void)
 }
 
 
-/* Direct accessors for feature sets.  */
+/* Direct accessors for target descriptions.  */
 
 /* Return the string value of a property named KEY, or NULL if the
    property was not specified.  */
@@ -187,8 +294,529 @@ tdesc_architecture (const struct target_
 }
 
 
+/* Return 1 if this target description includes any registers.  */
+
+int
+tdesc_has_registers (const struct target_desc *target_desc)
+{
+  int ix;
+  struct tdesc_feature *feature;
+
+  if (target_desc == NULL)
+    return 0;
+
+  for (ix = 0;
+       VEC_iterate (tdesc_feature_p, target_desc->features, ix, feature);
+       ix++)
+    if (! VEC_empty (tdesc_reg_p, feature->registers))
+      return 1;
+
+  return 0;
+}
+
+/* Return the feature with the given name, if present, or NULL if
+   the named feature is not found.  */
+
+const struct tdesc_feature *
+tdesc_find_feature (const struct target_desc *target_desc,
+		    const char *name)
+{
+  int ix;
+  struct tdesc_feature *feature;
+
+  for (ix = 0;
+       VEC_iterate (tdesc_feature_p, target_desc->features, ix, feature);
+       ix++)
+    if (strcmp (feature->name, name) == 0)
+      return feature;
+
+  return NULL;
+}
+
+/* Return the name of FEATURE.  */
+
+const char *
+tdesc_feature_name (const struct tdesc_feature *feature)
+{
+  return feature->name;
+}
+
+/* Return the type associated with ID in the context of FEATURE, or
+   NULL if none.  */
+
+struct type *
+tdesc_named_type (const struct tdesc_feature *feature, const char *id)
+{
+  int ix;
+  struct type *gdb_type;
+
+  /* First try target-defined types.  */
+  for (ix = 0; VEC_iterate (type_p, feature->types, ix, gdb_type); ix++)
+    if (strcmp (TYPE_NAME (gdb_type), id) == 0)
+      return gdb_type;
+
+  /* Next try some predefined types.  Note that none of these types
+     depend on the current architecture; some of the builtin_type_foo
+     variables are swapped based on the architecture.  */
+  if (strcmp (id, "int8") == 0)
+    return builtin_type_int8;
+
+  if (strcmp (id, "int16") == 0)
+    return builtin_type_int16;
+
+  if (strcmp (id, "int32") == 0)
+    return builtin_type_int32;
+
+  if (strcmp (id, "int64") == 0)
+    return builtin_type_int64;
+
+  if (strcmp (id, "uint8") == 0)
+    return builtin_type_uint8;
+
+  if (strcmp (id, "uint16") == 0)
+    return builtin_type_uint16;
+
+  if (strcmp (id, "uint32") == 0)
+    return builtin_type_uint32;
+
+  if (strcmp (id, "uint64") == 0)
+    return builtin_type_uint64;
+
+  if (strcmp (id, "code_ptr") == 0)
+    return builtin_type_void_func_ptr;
+
+  if (strcmp (id, "data_ptr") == 0)
+    return builtin_type_void_data_ptr;
+
+  if (strcmp (id, "arm_fpa_ext") == 0)
+    return builtin_type_arm_ext;
+
+  return NULL;
+}
+
+
+/* Support for registers from target descriptions.  */
+
+/* Construct the per-gdbarch data.  */
+
+static void *
+tdesc_data_init (struct obstack *obstack)
+{
+  struct tdesc_arch_data *data;
+
+  data = OBSTACK_ZALLOC (obstack, struct tdesc_arch_data);
+  return data;
+}
+
+/* Similar, but for the temporary copy used during architecture
+   initialization.  */
+
+struct tdesc_arch_data *
+tdesc_data_alloc (void)
+{
+  return XZALLOC (struct tdesc_arch_data);
+}
+
+/* Free something allocated by tdesc_data_alloc, if it is not going
+   to be used (for instance if it was unsuitable for the
+   architecture).  */
+
+void
+tdesc_data_cleanup (void *data_untyped)
+{
+  struct tdesc_arch_data *data = data_untyped;
+
+  VEC_free (tdesc_reg_p, data->registers);
+  xfree (data);
+}
+
+/* Search FEATURE for a register named NAME.  */
+
+int
+tdesc_numbered_register (const struct tdesc_feature *feature,
+			 struct tdesc_arch_data *data,
+			 int regno, const char *name)
+{
+  int ixr;
+  struct tdesc_reg *reg;
+
+  for (ixr = 0;
+       VEC_iterate (tdesc_reg_p, feature->registers, ixr, reg);
+       ixr++)
+    if (strcasecmp (reg->name, name) == 0)
+      {
+	/* Make sure the vector includes a REGNO'th element.  */
+	while (regno >= VEC_length (tdesc_reg_p, data->registers))
+	  VEC_safe_push (tdesc_reg_p, data->registers, NULL);
+	VEC_replace (tdesc_reg_p, data->registers, regno, reg);
+	return 1;
+      }
+
+  return 0;
+}
+
+/* Search FEATURE for a register whose name is in NAMES.  */
+
+int
+tdesc_numbered_register_choices (const struct tdesc_feature *feature,
+				 struct tdesc_arch_data *data,
+				 int regno, const char *const names[])
+{
+  int i;
+
+  for (i = 0; names[i] != NULL; i++)
+    if (tdesc_numbered_register (feature, data, regno, names[i]))
+      return 1;
+
+  return 0;
+}
+
+/* Look up a register by its GDB internal register number.  */
+
+static struct tdesc_reg *
+tdesc_find_register (struct gdbarch *gdbarch, int regno)
+{
+  struct tdesc_reg *reg;
+  struct tdesc_arch_data *data;
+
+  data = gdbarch_data (gdbarch, tdesc_data);
+  if (regno < VEC_length (tdesc_reg_p, data->registers))
+    return VEC_index (tdesc_reg_p, data->registers, regno);
+  else
+    return NULL;
+}
+
+static const char *
+tdesc_register_name (int regno)
+{
+  struct tdesc_reg *reg = tdesc_find_register (current_gdbarch, regno);
+  int num_regs = gdbarch_num_regs (current_gdbarch);
+  int num_pseudo_regs = gdbarch_num_pseudo_regs (current_gdbarch);
+
+  if (reg != NULL)
+    return reg->name;
+
+  if (regno >= num_regs && regno < num_regs + num_pseudo_regs)
+    {
+      struct tdesc_arch_data *data = gdbarch_data (current_gdbarch,
+						   tdesc_data);
+      gdb_assert (data->pseudo_register_name != NULL);
+      return data->pseudo_register_name (regno);
+    }
+
+  return "";
+}
+
+static struct type *
+tdesc_register_type (struct gdbarch *gdbarch, int regno)
+{
+  struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno);
+  int num_regs = gdbarch_num_regs (gdbarch);
+  int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch);
+
+  if (reg == NULL && regno >= num_regs && regno < num_regs + num_pseudo_regs)
+    {
+      struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data);
+      gdb_assert (data->pseudo_register_type != NULL);
+      return data->pseudo_register_type (gdbarch, regno);
+    }
+
+  if (reg == NULL)
+    /* Return "int0_t", since "void" has a misleading size of one.  */
+    return builtin_type_int0;
+
+  /* First check for a predefined or target defined type.  */
+  if (reg->gdb_type)
+    return reg->gdb_type;
+
+  /* Next try size-sensitive type shortcuts.  */
+  if (strcmp (reg->type, "float") == 0)
+    {
+      if (reg->bitsize == gdbarch_float_bit (gdbarch))
+	return builtin_type_float;
+      else if (reg->bitsize == gdbarch_double_bit (gdbarch))
+	return builtin_type_double;
+      else if (reg->bitsize == gdbarch_long_double_bit (gdbarch))
+	return builtin_type_long_double;
+    }
+  else if (strcmp (reg->type, "int") == 0)
+    {
+      if (reg->bitsize == gdbarch_long_bit (gdbarch))
+	return builtin_type_long;
+      else if (reg->bitsize == TARGET_CHAR_BIT)
+	return builtin_type_char;
+      else if (reg->bitsize == gdbarch_short_bit (gdbarch))
+	return builtin_type_short;
+      else if (reg->bitsize == gdbarch_int_bit (gdbarch))
+	return builtin_type_int;
+      else if (reg->bitsize == gdbarch_long_long_bit (gdbarch))
+	return builtin_type_long_long;
+      else if (reg->bitsize == gdbarch_ptr_bit (gdbarch))
+	/* A bit desperate by this point... */
+	return builtin_type_void_data_ptr;
+    }
+  else
+    internal_error (__FILE__, __LINE__,
+		    "Register \"%s\" has an unknown type \"%s\"",
+		    reg->name, reg->type);
+
+  warning (_("Register \"%s\" has an unsupported size (%d bits)"),
+	   reg->name, reg->bitsize);
+  return builtin_type_long;
+}
+
+static int
+tdesc_remote_register_number (struct gdbarch *gdbarch, int regno)
+{
+  struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno);
+
+  if (reg != NULL)
+    return reg->target_regnum;
+  else
+    return -1;
+}
+
+/* Check whether REGNUM is a member of REGGROUP.  Registers from the
+   target description may be classified as general, float, or vector.
+   Registers with no group specified go to the default reggroup
+   function and are handled by type.
+
+   Arbitrary strings (other than "general", "float", and "vector")
+   from the description are not used; they cause the register to be
+   displayed in "info all-registers" but excluded from "info
+   registers" et al.  The names of containing features are also not
+   used.  This might be extended to display registers in some more
+   useful groupings.
+
+   The save-restore flag is also implemented here.  */
+
+static int
+tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regno,
+			   struct reggroup *reggroup)
+{
+  int num_regs = gdbarch_num_regs (gdbarch);
+  int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch);
+  struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno);
+
+  if (reg == NULL && 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 (reg != NULL && reg->group != NULL)
+    {
+      int general_p = 0, float_p = 0, vector_p = 0;
+
+      if (strcmp (reg->group, "general") == 0)
+	general_p = 1;
+      else if (strcmp (reg->group, "float") == 0)
+	float_p = 1;
+      else if (strcmp (reg->group, "vector") == 0)
+	vector_p = 1;
+
+      if (reggroup == float_reggroup)
+	return float_p;
+
+      if (reggroup == vector_reggroup)
+	return vector_p;
+
+      if (reggroup == general_reggroup)
+	return general_p;
+    }
+
+  if (reg != NULL
+      && (reggroup == save_reggroup || reggroup == restore_reggroup))
+    return reg->save_restore;
+
+  return default_register_reggroup_p (gdbarch, regno, reggroup);
+}
+
+/* Record architecture-specific functions to call for pseudo-register
+   support.  */
+
+void
+set_tdesc_pseudo_register_name (struct gdbarch *gdbarch,
+				gdbarch_register_name_ftype *pseudo_name)
+{
+  struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data);
+
+  data->pseudo_register_name = pseudo_name;
+}
+
+void
+set_tdesc_pseudo_register_type (struct gdbarch *gdbarch,
+				gdbarch_register_type_ftype *pseudo_type)
+{
+  struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data);
+
+  data->pseudo_register_type = pseudo_type;
+}
+
+void
+set_tdesc_pseudo_register_reggroup_p
+  (struct gdbarch *gdbarch,
+   gdbarch_register_reggroup_p_ftype *pseudo_reggroup_p)
+{
+  struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data);
+
+  data->pseudo_register_reggroup_p = pseudo_reggroup_p;
+}
+
+/* Update GDBARCH to use the target description for registers.  */
+
+void
+tdesc_use_registers (struct gdbarch *gdbarch,
+		     struct tdesc_arch_data *early_data)
+{
+  int num_regs = gdbarch_num_regs (gdbarch);
+  int i, ixf, ixr;
+  const struct target_desc *target_desc;
+  struct tdesc_feature *feature;
+  struct tdesc_reg *reg;
+  struct tdesc_arch_data *data;
+  htab_t reg_hash;
+
+  target_desc = gdbarch_target_desc (gdbarch);
+
+  /* We can't use the description for registers if it doesn't describe
+     any.  This function should only be called after validating
+     registers, so the caller should know that registers are
+     included.  */
+  gdb_assert (tdesc_has_registers (target_desc));
+
+  data = gdbarch_data (gdbarch, tdesc_data);
+  data->registers = early_data->registers;
+  xfree (early_data);
+
+  /* Build up a set of all registers, so that we can assign register
+     numbers where needed.  The hash table expands as necessary, so
+     the initial size is arbitrary.  */
+  reg_hash = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL);
+  for (ixf = 0;
+       VEC_iterate (tdesc_feature_p, target_desc->features, ixf, feature);
+       ixf++)
+    for (ixr = 0;
+	 VEC_iterate (tdesc_reg_p, feature->registers, ixr, reg);
+	 ixr++)
+      {
+	void **slot = htab_find_slot (reg_hash, reg, INSERT);
+
+	*slot = reg;
+      }
+
+  /* Remove any registers which were assigned numbers by the
+     architecture.  */
+  for (ixr = 0; VEC_iterate (tdesc_reg_p, data->registers, ixr, reg); ixr++)
+    if (reg)
+      htab_remove_elt (reg_hash, reg);
+
+  /* Assign numbers to the remaining registers and add them to the
+     list of registers.  The new numbers are always above NUM_REGS.
+     Iterate over the features, not the hash table, so that the order
+     matches that in the target description.  */
+
+  gdb_assert (VEC_length (tdesc_reg_p, data->registers) <= num_regs);
+  while (VEC_length (tdesc_reg_p, data->registers) < num_regs)
+    VEC_safe_push (tdesc_reg_p, data->registers, NULL);
+  for (ixf = 0;
+       VEC_iterate (tdesc_feature_p, target_desc->features, ixf, feature);
+       ixf++)
+    for (ixr = 0;
+	 VEC_iterate (tdesc_reg_p, feature->registers, ixr, reg);
+	 ixr++)
+      if (htab_find (reg_hash, reg) != NULL)
+	{
+	  VEC_safe_push (tdesc_reg_p, data->registers, reg);
+	  num_regs++;
+	}
+
+  htab_delete (reg_hash);
+
+  /* Update the architecture.  */
+  set_gdbarch_num_regs (gdbarch, num_regs);
+  set_gdbarch_register_name (gdbarch, tdesc_register_name);
+  set_gdbarch_register_type (gdbarch, tdesc_register_type);
+  set_gdbarch_remote_register_number (gdbarch,
+				      tdesc_remote_register_number);
+  set_gdbarch_register_reggroup_p (gdbarch, tdesc_register_reggroup_p);
+}
+
+
 /* Methods for constructing a target description.  */
 
+static void
+tdesc_free_reg (struct tdesc_reg *reg)
+{
+  xfree (reg->name);
+  xfree (reg->type);
+  xfree (reg->group);
+  xfree (reg);
+}
+
+void
+tdesc_create_reg (struct tdesc_feature *feature, const char *name,
+		  int regnum, int save_restore, const char *group,
+		  int bitsize, const char *type)
+{
+  struct tdesc_reg *reg = XZALLOC (struct tdesc_reg);
+
+  reg->name = xstrdup (name);
+  reg->target_regnum = regnum;
+  reg->save_restore = save_restore;
+  reg->group = group ? xstrdup (group) : NULL;
+  reg->bitsize = bitsize;
+  reg->type = type ? xstrdup (type) : NULL;
+
+  /* If the register's type is target-defined, look it up now.  We may not
+     have easy access to the containing feature when we want it later.  */
+  reg->gdb_type = tdesc_named_type (feature, reg->type);
+
+  VEC_safe_push (tdesc_reg_p, feature->registers, reg);
+}
+
+static void
+tdesc_free_feature (struct tdesc_feature *feature)
+{
+  struct tdesc_reg *reg;
+  int ix;
+
+  for (ix = 0; VEC_iterate (tdesc_reg_p, feature->registers, ix, reg); ix++)
+    tdesc_free_reg (reg);
+  VEC_free (tdesc_reg_p, feature->registers);
+
+  /* There is no easy way to free xmalloc-allocated types, nor is
+     there a way to allocate types on an obstack not associated with
+     an objfile.  Therefore we never free types.  Since we only ever
+     parse an identical XML document once, this memory leak is mostly
+     contained.  */
+  VEC_free (type_p, feature->types);
+
+  xfree (feature->name);
+  xfree (feature);
+}
+
+struct tdesc_feature *
+tdesc_create_feature (struct target_desc *tdesc, const char *name)
+{
+  struct tdesc_feature *new_feature = XZALLOC (struct tdesc_feature);
+
+  new_feature->name = xstrdup (name);
+
+  VEC_safe_push (tdesc_feature_p, tdesc->features, new_feature);
+  return new_feature;
+}
+
+void
+tdesc_record_type (struct tdesc_feature *feature, struct type *type)
+{
+  /* The type's ID should be used as its TYPE_NAME.  */
+  gdb_assert (TYPE_NAME (type) != NULL);
+
+  VEC_safe_push (type_p, feature->types, type);
+}
+
 struct target_desc *
 allocate_target_description (void)
 {
@@ -199,10 +827,17 @@ static void
 free_target_description (void *arg)
 {
   struct target_desc *target_desc = arg;
+  struct tdesc_feature *feature;
   struct property *prop;
   int ix;
 
   for (ix = 0;
+       VEC_iterate (tdesc_feature_p, target_desc->features, ix, feature);
+       ix++)
+    tdesc_free_feature (feature);
+  VEC_free (tdesc_feature_p, target_desc->features);
+
+  for (ix = 0;
        VEC_iterate (property_s, target_desc->properties, ix, prop);
        ix++)
     {
@@ -305,6 +940,8 @@ unset_tdesc_filename_cmd (char *args, in
 void
 _initialize_target_descriptions (void)
 {
+  tdesc_data = gdbarch_data_register_pre_init (tdesc_data_init);
+
   add_prefix_cmd ("tdesc", class_maintenance, set_tdesc_cmd, _("\
 Set target description specific variables."),
 		  &tdesc_set_cmdlist, "set tdesc ",
Index: src/gdb/arch-utils.c
===================================================================
--- src.orig/gdb/arch-utils.c	2007-01-29 12:37:44.000000000 -0500
+++ src/gdb/arch-utils.c	2007-01-29 12:39:17.000000000 -0500
@@ -263,6 +263,13 @@ generic_instruction_nullified (struct gd
   return 0;
 }
 
+int
+default_remote_register_number (struct gdbarch *gdbarch,
+				int regno)
+{
+  return regno;
+}
+
 
 /* Functions to manipulate the endianness of the target.  */
 
Index: src/gdb/arch-utils.h
===================================================================
--- src.orig/gdb/arch-utils.h	2007-01-29 12:37:44.000000000 -0500
+++ src/gdb/arch-utils.h	2007-01-29 12:39:17.000000000 -0500
@@ -109,6 +109,9 @@ extern int default_stabs_argument_has_ad
 extern int generic_instruction_nullified (struct gdbarch *gdbarch,
 					  struct regcache *regcache);
 
+int default_remote_register_number (struct gdbarch *gdbarch,
+				    int regno);
+
 /* For compatibility with older architectures, returns
    (LEGACY_SIM_REGNO_IGNORE) when the register doesn't have a valid
    name.  */
Index: src/gdb/target-descriptions.h
===================================================================
--- src.orig/gdb/target-descriptions.h	2007-01-29 12:37:12.000000000 -0500
+++ src/gdb/target-descriptions.h	2007-01-29 12:39:17.000000000 -0500
@@ -24,7 +24,12 @@
 #ifndef TARGET_DESCRIPTIONS_H
 #define TARGET_DESCRIPTIONS_H 1
 
+struct tdesc_feature;
+struct tdesc_arch_data;
+struct tdesc_reg;
 struct target_desc;
+struct target_ops;
+struct type;
 
 /* Fetch the current target's description, and switch the current
    architecture to one which incorporates that description.  */
@@ -42,6 +47,65 @@ void target_clear_description (void);
 
 const struct target_desc *target_current_description (void);
 
+/* Record architecture-specific functions to call for pseudo-register
+   support.  If tdesc_use_registers is called and NUM_PSEUDO_REGS
+   is greater than zero, then these should be called as well.
+   They are equivalent to the gdbarch methods with similar names,
+   except that they will only be called for pseudo registers.  */
+
+void set_tdesc_pseudo_register_name
+  (struct gdbarch *gdbarch, gdbarch_register_name_ftype *pseudo_name);
+
+void set_tdesc_pseudo_register_type
+  (struct gdbarch *gdbarch, gdbarch_register_type_ftype *pseudo_type);
+
+void set_tdesc_pseudo_register_reggroup_p
+  (struct gdbarch *gdbarch,
+   gdbarch_register_reggroup_p_ftype *pseudo_reggroup_p);
+
+/* Update GDBARCH to use the target description for registers.  Fixed
+   register assignments are taken from EARLY_DATA, which is freed.
+   All registers which have not been assigned fixed numbers are given
+   numbers above the current value of NUM_REGS.  NUM_REGS and various
+   register-related predicates are updated to refer to the target
+   description.  This function should only be called from the
+   architecture's gdbarch initialization routine, and only after
+   successfully validating the required registers.  */
+
+void tdesc_use_registers (struct gdbarch *gdbarch,
+			  struct tdesc_arch_data *early_data);
+
+/* Allocate initial data for validation of a target description during
+   gdbarch initialization.  */
+
+struct tdesc_arch_data *tdesc_data_alloc (void);
+
+/* Clean up data allocated by tdesc_data_alloc.  This should only
+   be called to discard the data; tdesc_use_registers takes ownership
+   of its EARLY_DATA argument.  */
+
+void tdesc_data_cleanup (void *data_untyped);
+
+/* Search FEATURE for a register named NAME.  Record REGNO and the
+   register in DATA; when tdesc_use_registers is called, REGNO will be
+   assigned to the register.  1 is returned if the register was found,
+   0 if it was not.  */
+
+int tdesc_numbered_register (const struct tdesc_feature *feature,
+			     struct tdesc_arch_data *data,
+			     int regno, const char *name);
+
+/* Search FEATURE for a register with any of the names from NAMES
+   (NULL-terminated).  Record REGNO and the register in DATA; when
+   tdesc_use_registers is called, REGNO will be assigned to the
+   register.  1 is returned if the register was found, 0 if it was
+   not.  */
+
+int tdesc_numbered_register_choices (const struct tdesc_feature *feature,
+				     struct tdesc_arch_data *data,
+				     int regno, const char *const names[]);
+
+
 /* Accessors for target descriptions.  */
 
 /* Return the BFD architecture associated with this target
@@ -56,14 +120,41 @@ const struct bfd_arch_info *tdesc_archit
 const char *tdesc_property (const struct target_desc *,
 			    const char *key);
 
+/* Return 1 if this target description describes any registers.  */
+
+int tdesc_has_registers (const struct target_desc *);
+
+/* Return the feature with the given name, if present, or NULL if
+   the named feature is not found.  */
+
+const struct tdesc_feature *tdesc_find_feature (const struct target_desc *,
+						const char *name);
+
+/* Return the name of FEATURE.  */
+
+const char *tdesc_feature_name (const struct tdesc_feature *feature);
+
+/* Return the type associated with ID in the context of FEATURE, or
+   NULL if none.  */
+
+struct type *tdesc_named_type (const struct tdesc_feature *feature,
+			       const char *id);
+
 /* Methods for constructing a target description.  */
 
 struct target_desc *allocate_target_description (void);
 struct cleanup *make_cleanup_free_target_description (struct target_desc *);
 void set_tdesc_architecture (struct target_desc *,
 			     const struct bfd_arch_info *);
-
 void set_tdesc_property (struct target_desc *,
 			 const char *key, const char *value);
 
+struct tdesc_feature *tdesc_create_feature (struct target_desc *tdesc,
+					    const char *name);
+void tdesc_record_type (struct tdesc_feature *feature, struct type *type);
+
+void tdesc_create_reg (struct tdesc_feature *feature, const char *name,
+		       int regnum, int save_restore, const char *group,
+		       int bitsize, const char *type);
+
 #endif /* TARGET_DESCRIPTIONS_H */
Index: src/gdb/gdbarch.c
===================================================================
--- src.orig/gdb/gdbarch.c	2007-01-29 12:37:46.000000000 -0500
+++ src/gdb/gdbarch.c	2007-01-29 12:39:17.000000000 -0500
@@ -203,6 +203,7 @@ struct gdbarch
   CORE_ADDR decr_pc_after_break;
   CORE_ADDR deprecated_function_start_offset;
   gdbarch_remote_translate_xfer_address_ftype *remote_translate_xfer_address;
+  gdbarch_remote_register_number_ftype *remote_register_number;
   gdbarch_fetch_tls_load_module_address_ftype *fetch_tls_load_module_address;
   CORE_ADDR frame_args_skip;
   gdbarch_unwind_pc_ftype *unwind_pc;
@@ -330,6 +331,7 @@ struct gdbarch startup_gdbarch =
   0,  /* decr_pc_after_break */
   0,  /* deprecated_function_start_offset */
   generic_remote_translate_xfer_address,  /* remote_translate_xfer_address */
+  default_remote_register_number,  /* remote_register_number */
   0,  /* fetch_tls_load_module_address */
   0,  /* frame_args_skip */
   0,  /* unwind_pc */
@@ -440,6 +442,7 @@ gdbarch_alloc (const struct gdbarch_info
   current_gdbarch->memory_insert_breakpoint = default_memory_insert_breakpoint;
   current_gdbarch->memory_remove_breakpoint = default_memory_remove_breakpoint;
   current_gdbarch->remote_translate_xfer_address = generic_remote_translate_xfer_address;
+  current_gdbarch->remote_register_number = default_remote_register_number;
   current_gdbarch->stabs_argument_has_addr = default_stabs_argument_has_addr;
   current_gdbarch->convert_from_func_ptr_addr = convert_from_func_ptr_addr_identity;
   current_gdbarch->addr_bits_remove = core_addr_identity;
@@ -584,6 +587,7 @@ verify_gdbarch (struct gdbarch *current_
   /* Skip verify of decr_pc_after_break, invalid_p == 0 */
   /* Skip verify of deprecated_function_start_offset, invalid_p == 0 */
   /* Skip verify of remote_translate_xfer_address, invalid_p == 0 */
+  /* Skip verify of remote_register_number, invalid_p == 0 */
   /* Skip verify of fetch_tls_load_module_address, has predicate */
   /* Skip verify of frame_args_skip, invalid_p == 0 */
   /* Skip verify of unwind_pc, has predicate */
@@ -1442,6 +1446,9 @@ gdbarch_dump (struct gdbarch *current_gd
                       "gdbarch_dump: regset_from_core_section = <0x%lx>\n",
                       (long) current_gdbarch->regset_from_core_section);
   fprintf_unfiltered (file,
+                      "gdbarch_dump: remote_register_number = <0x%lx>\n",
+                      (long) current_gdbarch->remote_register_number);
+  fprintf_unfiltered (file,
                       "gdbarch_dump: remote_translate_xfer_address = <0x%lx>\n",
                       (long) current_gdbarch->remote_translate_xfer_address);
   fprintf_unfiltered (file,
@@ -2990,6 +2997,23 @@ set_gdbarch_remote_translate_xfer_addres
 }
 
 int
+gdbarch_remote_register_number (struct gdbarch *gdbarch, int regno)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->remote_register_number != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_remote_register_number called\n");
+  return gdbarch->remote_register_number (gdbarch, regno);
+}
+
+void
+set_gdbarch_remote_register_number (struct gdbarch *gdbarch,
+                                    gdbarch_remote_register_number_ftype remote_register_number)
+{
+  gdbarch->remote_register_number = remote_register_number;
+}
+
+int
 gdbarch_fetch_tls_load_module_address_p (struct gdbarch *gdbarch)
 {
   gdb_assert (gdbarch != NULL);
Index: src/gdb/gdbarch.h
===================================================================
--- src.orig/gdb/gdbarch.h	2007-01-29 12:37:46.000000000 -0500
+++ src/gdb/gdbarch.h	2007-01-29 12:39:17.000000000 -0500
@@ -947,6 +947,13 @@ typedef void (gdbarch_remote_translate_x
 extern void gdbarch_remote_translate_xfer_address (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR gdb_addr, int gdb_len, CORE_ADDR *rem_addr, int *rem_len);
 extern void set_gdbarch_remote_translate_xfer_address (struct gdbarch *gdbarch, gdbarch_remote_translate_xfer_address_ftype *remote_translate_xfer_address);
 
+/* Return the remote protocol register number associated with this
+   register.  Normally the identity mapping. */
+
+typedef int (gdbarch_remote_register_number_ftype) (struct gdbarch *gdbarch, int regno);
+extern int gdbarch_remote_register_number (struct gdbarch *gdbarch, int regno);
+extern void set_gdbarch_remote_register_number (struct gdbarch *gdbarch, gdbarch_remote_register_number_ftype *remote_register_number);
+
 /* Fetch the target specific address used to represent a load module. */
 
 #if defined (FETCH_TLS_LOAD_MODULE_ADDRESS)
Index: src/gdb/gdbarch.sh
===================================================================
--- src.orig/gdb/gdbarch.sh	2007-01-29 12:37:46.000000000 -0500
+++ src/gdb/gdbarch.sh	2007-01-29 12:39:17.000000000 -0500
@@ -574,6 +574,10 @@ v:=:CORE_ADDR:deprecated_function_start_
 
 m::void:remote_translate_xfer_address:struct regcache *regcache, CORE_ADDR gdb_addr, int gdb_len, CORE_ADDR *rem_addr, int *rem_len:regcache, gdb_addr, gdb_len, rem_addr, rem_len::generic_remote_translate_xfer_address::0
 
+# Return the remote protocol register number associated with this
+# register.  Normally the identity mapping.
+m::int:remote_register_number:int regno:regno::default_remote_register_number::0
+
 # Fetch the target specific address used to represent a load module.
 F:=:CORE_ADDR:fetch_tls_load_module_address:struct objfile *objfile:objfile
 #
Index: src/gdb/remote.c
===================================================================
--- src.orig/gdb/remote.c	2007-01-29 12:37:15.000000000 -0500
+++ src/gdb/remote.c	2007-01-29 12:39:17.000000000 -0500
@@ -334,12 +334,13 @@ init_remote_state (struct gdbarch *gdbar
 
   rsa = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct remote_arch_state);
 
-  /* Assume a 1:1 regnum<->pnum table.  */
+  /* Use the architecture to build a regnum<->pnum table, which will be
+     1:1 unless a feature set specifies otherwise.  */
   rsa->regs = GDBARCH_OBSTACK_CALLOC (gdbarch, NUM_REGS, struct packet_reg);
   for (regnum = 0; regnum < NUM_REGS; regnum++)
     {
       struct packet_reg *r = &rsa->regs[regnum];
-      r->pnum = regnum;
+      r->pnum = gdbarch_remote_register_number (gdbarch, regnum);
       r->regnum = regnum;
     }
 
Index: src/gdb/features/gdb-target.dtd
===================================================================
--- src.orig/gdb/features/gdb-target.dtd	2007-01-29 12:39:10.000000000 -0500
+++ src/gdb/features/gdb-target.dtd	2007-01-29 12:39:17.000000000 -0500
@@ -6,9 +6,38 @@
 
 <!-- The root element of a GDB target description is <target>.  -->
 
-<!ELEMENT target	(architecture?)>
+<!ELEMENT target	(architecture?, feature*)>
 
 <!ELEMENT architecture	(#PCDATA)>
 
+<!ELEMENT feature	((vector | union)*, reg*)>
+<!ATTLIST feature
+	name		ID	#REQUIRED>
+
+<!ELEMENT reg		(description*)>
+<!ATTLIST reg
+	name		CDATA	#REQUIRED
+	bitsize		CDATA	#REQUIRED
+	regnum		CDATA	#IMPLIED
+	save-restore	(yes | no) 'yes'
+	type		CDATA	'int'
+	group		CDATA	#IMPLIED
+	>
+
+<!ELEMENT vector	EMPTY>
+<!ATTLIST vector
+	id		CDATA	#REQUIRED
+	type		CDATA	#REQUIRED
+	count		CDATA	#REQUIRED>
+
+<!ELEMENT union		(field+)>
+<!ATTLIST union
+	id		CDATA	#REQUIRED>
+
+<!ELEMENT field		EMPTY>
+<!ATTLIST field
+	name		CDATA	#REQUIRED
+	type		CDATA	#REQUIRED>
+
 <!ENTITY % xinclude SYSTEM "xinclude.dtd">
 %xinclude;
Index: src/gdb/arm-tdep.c
===================================================================
--- src.orig/gdb/arm-tdep.c	2007-01-29 12:37:44.000000000 -0500
+++ src/gdb/arm-tdep.c	2007-01-29 12:39:17.000000000 -0500
@@ -41,6 +41,8 @@
 #include "dwarf2-frame.h"
 #include "gdbtypes.h"
 #include "prologue-value.h"
+#include "target-descriptions.h"
+#include "user-regs.h"
 
 #include "arm-tdep.h"
 #include "gdb/sim-arm.h"
@@ -103,13 +105,58 @@ static const char *arm_abi_string = "aut
 /* Number of different reg name sets (options).  */
 static int num_disassembly_options;
 
-/* We have more registers than the disassembler as gdb can print the value
-   of special registers as well.
-   The general register names are overwritten by whatever is being used by
-   the disassembler at the moment. We also adjust the case of cpsr and fps.  */
+/* The standard register names, and all the valid aliases for them.  */
+static const struct
+{
+  const char *name;
+  int regnum;
+} arm_register_aliases[] = {
+  /* Basic register numbers.  */
+  { "r0", 0 },
+  { "r1", 1 },
+  { "r2", 2 },
+  { "r3", 3 },
+  { "r4", 4 },
+  { "r5", 5 },
+  { "r6", 6 },
+  { "r7", 7 },
+  { "r8", 8 },
+  { "r9", 9 },
+  { "r10", 10 },
+  { "r11", 11 },
+  { "r12", 12 },
+  { "r13", 13 },
+  { "r14", 14 },
+  { "r15", 15 },
+  /* Synonyms (argument and variable registers).  */
+  { "a1", 0 },
+  { "a2", 1 },
+  { "a3", 2 },
+  { "a4", 3 },
+  { "v1", 4 },
+  { "v2", 5 },
+  { "v3", 6 },
+  { "v4", 7 },
+  { "v5", 8 },
+  { "v6", 9 },
+  { "v7", 10 },
+  { "v8", 11 },
+  /* Other platform-specific names for r9.  */
+  { "sb", 9 },
+  { "tr", 9 },
+  /* Special names.  */
+  { "ip", 12 },
+  { "sp", 13 },
+  { "lr", 14 },
+  { "pc", 15 },
+  /* Names used by GCC (not listed in the ARM EABI).  */
+  { "sl", 10 },
+  { "fp", 11 },
+  /* A special name from the older ATPCS.  */
+  { "wr", 7 },
+};
 
-/* Initial value: Register names used in ARM's ISA documentation.  */
-static char * arm_register_name_strings[] =
+static const char *const arm_register_names[] =
 {"r0",  "r1",  "r2",  "r3",	/*  0  1  2  3 */
  "r4",  "r5",  "r6",  "r7",	/*  4  5  6  7 */
  "r8",  "r9",  "r10", "r11",	/*  8  9 10 11 */
@@ -117,15 +164,12 @@ static char * arm_register_name_strings[
  "f0",  "f1",  "f2",  "f3",	/* 16 17 18 19 */
  "f4",  "f5",  "f6",  "f7",	/* 20 21 22 23 */
  "fps", "cpsr" };		/* 24 25       */
-static char **arm_register_names = arm_register_name_strings;
 
 /* Valid register name styles.  */
 static const char **valid_disassembly_styles;
 
 /* Disassembly style to use. Default to "std" register names.  */
 static const char *disassembly_style;
-/* Index to that option in the opcodes table.  */
-static int current_option;
 
 /* This is used to keep the bfd arch_info in sync with the disassembly
    style.  */
@@ -1343,23 +1387,6 @@ arm_register_type (struct gdbarch *gdbar
     return builtin_type_uint32;
 }
 
-/* Index within `registers' of the first byte of the space for
-   register N.  */
-
-static int
-arm_register_byte (int regnum)
-{
-  if (regnum < ARM_F0_REGNUM)
-    return regnum * INT_REGISTER_SIZE;
-  else if (regnum < ARM_PS_REGNUM)
-    return (NUM_GREGS * INT_REGISTER_SIZE
-	    + (regnum - ARM_F0_REGNUM) * FP_REGISTER_SIZE);
-  else
-    return (NUM_GREGS * INT_REGISTER_SIZE
-	    + NUM_FREGS * FP_REGISTER_SIZE
-	    + (regnum - ARM_FPS_REGNUM) * STATUS_REGISTER_SIZE);
-}
-
 /* Map GDB internal REGNUM onto the Arm simulator register numbers.  */
 static int
 arm_register_sim_regno (int regnum)
@@ -2461,32 +2488,13 @@ arm_register_name (int i)
 static void
 set_disassembly_style (void)
 {
-  const char *setname, *setdesc, *const *regnames;
-  int numregs, j;
+  int current;
 
-  /* Find the style that the user wants in the opcodes table.  */
-  int current = 0;
-  numregs = get_arm_regnames (current, &setname, &setdesc, &regnames);
-  while ((disassembly_style != setname)
-	 && (current < num_disassembly_options))
-    get_arm_regnames (++current, &setname, &setdesc, &regnames);
-  current_option = current;
-
-  /* Fill our copy.  */
-  for (j = 0; j < numregs; j++)
-    arm_register_names[j] = (char *) regnames[j];
-
-  /* Adjust case.  */
-  if (isupper (*regnames[ARM_PC_REGNUM]))
-    {
-      arm_register_names[ARM_FPS_REGNUM] = "FPS";
-      arm_register_names[ARM_PS_REGNUM] = "CPSR";
-    }
-  else
-    {
-      arm_register_names[ARM_FPS_REGNUM] = "fps";
-      arm_register_names[ARM_PS_REGNUM] = "cpsr";
-    }
+  /* Find the style that the user wants.  */
+  for (current = 0; current < num_disassembly_options; current++)
+    if (disassembly_style == valid_disassembly_styles[current])
+      break;
+  gdb_assert (current < num_disassembly_options);
 
   /* Synchronize the disassembler.  */
   set_arm_regname_option (current);
@@ -2544,6 +2552,13 @@ arm_write_pc (CORE_ADDR pc, ptid_t ptid)
 	write_register_pid (ARM_PS_REGNUM, val & ~(CORE_ADDR) 0x20, ptid);
     }
 }
+
+static struct value *
+value_of_arm_user_reg (struct frame_info *frame, const void *baton)
+{
+  const int *reg_p = baton;
+  return value_of_register (*reg_p, frame);
+}
 
 static enum gdb_osabi
 arm_elf_osabi_sniffer (bfd *abfd)
@@ -2580,6 +2595,65 @@ arm_gdbarch_init (struct gdbarch_info in
   struct gdbarch_list *best_arch;
   enum arm_abi_kind arm_abi = arm_abi_global;
   enum arm_float_model fp_model = arm_fp_model;
+  struct tdesc_arch_data *tdesc_data = NULL;
+  int i;
+
+  /* Check any target description for validity.  */
+  if (tdesc_has_registers (info.target_desc))
+    {
+      /* For most registers we require GDB's default names; but also allow
+	 the numeric names for sp / lr / pc, as a convenience.  */
+      static const char *const arm_sp_names[] = { "r13", "sp", NULL };
+      static const char *const arm_lr_names[] = { "r14", "lr", NULL };
+      static const char *const arm_pc_names[] = { "r15", "pc", NULL };
+
+      const struct tdesc_feature *feature;
+      int i, valid_p;
+
+      feature = tdesc_find_feature (info.target_desc,
+				    "org.gnu.gdb.arm.core");
+      if (feature == NULL)
+	return NULL;
+
+      tdesc_data = tdesc_data_alloc ();
+
+      valid_p = 1;
+      for (i = 0; i < ARM_SP_REGNUM; i++)
+	valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+					    arm_register_names[i]);
+      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
+						  ARM_SP_REGNUM,
+						  arm_sp_names);
+      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
+						  ARM_LR_REGNUM,
+						  arm_lr_names);
+      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
+						  ARM_PC_REGNUM,
+						  arm_pc_names);
+      valid_p &= tdesc_numbered_register (feature, tdesc_data,
+					  ARM_PS_REGNUM, "cpsr");
+
+      if (!valid_p)
+	{
+	  tdesc_data_cleanup (tdesc_data);
+	  return NULL;
+	}
+
+      feature = tdesc_find_feature (info.target_desc,
+				    "org.gnu.gdb.arm.fpa");
+      if (feature != NULL)
+	{
+	  valid_p = 1;
+	  for (i = ARM_F0_REGNUM; i <= ARM_FPS_REGNUM; i++)
+	    valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+						arm_register_names[i]);
+	  if (!valid_p)
+	    {
+	      tdesc_data_cleanup (tdesc_data);
+	      return NULL;
+	    }
+	}
+    }
 
   /* If we have an object to base this architecture on, try to determine
      its ABI.  */
@@ -2709,7 +2783,11 @@ arm_gdbarch_init (struct gdbarch_info in
     }
 
   if (best_arch != NULL)
-    return best_arch->gdbarch;
+    {
+      if (tdesc_data != NULL)
+	tdesc_data_cleanup (tdesc_data);
+      return best_arch->gdbarch;
+    }
 
   tdep = xcalloc (1, sizeof (struct gdbarch_tdep));
   gdbarch = gdbarch_alloc (&info, tdep);
@@ -2784,7 +2862,6 @@ arm_gdbarch_init (struct gdbarch_info in
   set_gdbarch_deprecated_fp_regnum (gdbarch, ARM_FP_REGNUM);	/* ??? */
   set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM);
   set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM);
-  set_gdbarch_deprecated_register_byte (gdbarch, arm_register_byte);
   set_gdbarch_num_regs (gdbarch, NUM_GREGS + NUM_FREGS + NUM_SREGS);
   set_gdbarch_register_type (gdbarch, arm_register_type);
 
@@ -2842,6 +2919,16 @@ arm_gdbarch_init (struct gdbarch_info in
       set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
     }
 
+  if (tdesc_data)
+    tdesc_use_registers (gdbarch, tdesc_data);
+
+  /* Add standard register aliases.  We add aliases even for those
+     nanes which are used by the current architecture - it's simpler,
+     and does no harm, since nothing ever lists user registers.  */
+  for (i = 0; i < ARRAY_SIZE (arm_register_aliases); i++)
+    user_reg_add (gdbarch, arm_register_aliases[i].name,
+		  value_of_arm_user_reg, &arm_register_aliases[i].regnum);
+
   return gdbarch;
 }
 
@@ -2906,13 +2993,11 @@ _initialize_arm_tdep (void)
       length = snprintf (rdptr, rest, "%s - %s\n", setname, setdesc);
       rdptr += length;
       rest -= length;
-      /* Copy the default names (if found) and synchronize disassembler.  */
+      /* When we find the default names, tell the disassembler to use
+	 them.  */
       if (!strcmp (setname, "std"))
 	{
           disassembly_style = setname;
-          current_option = i;
-	  for (j = 0; j < numregs; j++)
-            arm_register_names[j] = (char *) regnames[j];
           set_arm_regname_option (i);
 	}
     }
Index: src/gdb/std-regs.c
===================================================================
--- src.orig/gdb/std-regs.c	2007-01-29 12:37:12.000000000 -0500
+++ src/gdb/std-regs.c	2007-01-29 12:39:17.000000000 -0500
@@ -53,7 +53,7 @@ build_builtin_type_frame_reg (void)
 }
 
 static struct value *
-value_of_builtin_frame_reg (struct frame_info *frame)
+value_of_builtin_frame_reg (struct frame_info *frame, const void *baton)
 {
   struct value *val;
   gdb_byte *buf;
@@ -72,7 +72,7 @@ value_of_builtin_frame_reg (struct frame
 }
 
 static struct value *
-value_of_builtin_frame_fp_reg (struct frame_info *frame)
+value_of_builtin_frame_fp_reg (struct frame_info *frame, const void *baton)
 {
   if (DEPRECATED_FP_REGNUM >= 0)
     /* NOTE: cagney/2003-04-24: Since the mere presence of "fp" in the
@@ -96,7 +96,7 @@ value_of_builtin_frame_fp_reg (struct fr
 }
 
 static struct value *
-value_of_builtin_frame_pc_reg (struct frame_info *frame)
+value_of_builtin_frame_pc_reg (struct frame_info *frame, const void *baton)
 {
   if (PC_REGNUM >= 0)
     return value_of_register (PC_REGNUM, frame);
@@ -114,7 +114,7 @@ value_of_builtin_frame_pc_reg (struct fr
 }
 
 static struct value *
-value_of_builtin_frame_sp_reg (struct frame_info *frame)
+value_of_builtin_frame_sp_reg (struct frame_info *frame, const void *baton)
 {
 #ifdef SP_REGNUM
   if (SP_REGNUM >= 0)
@@ -124,7 +124,7 @@ value_of_builtin_frame_sp_reg (struct fr
 }
 
 static struct value *
-value_of_builtin_frame_ps_reg (struct frame_info *frame)
+value_of_builtin_frame_ps_reg (struct frame_info *frame, const void *baton)
 {
 #ifdef PS_REGNUM
   if (PS_REGNUM >= 0)
@@ -147,14 +147,14 @@ _initialize_frame_reg (void)
   /* Frame based $fp, $pc, $sp and $ps.  These only come into play
      when the target does not define its own version of these
      registers.  */
-  user_reg_add_builtin ("fp", value_of_builtin_frame_fp_reg);
-  user_reg_add_builtin ("pc", value_of_builtin_frame_pc_reg);
-  user_reg_add_builtin ("sp", value_of_builtin_frame_sp_reg);
-  user_reg_add_builtin ("ps", value_of_builtin_frame_ps_reg);
+  user_reg_add_builtin ("fp", value_of_builtin_frame_fp_reg, NULL);
+  user_reg_add_builtin ("pc", value_of_builtin_frame_pc_reg, NULL);
+  user_reg_add_builtin ("sp", value_of_builtin_frame_sp_reg, NULL);
+  user_reg_add_builtin ("ps", value_of_builtin_frame_ps_reg, NULL);
 
   /* NOTE: cagney/2002-04-05: For moment leave the $frame / $gdbframe
      / $gdb.frame disabled.  It isn't yet clear which of the many
      options is the best.  */
   if (0)
-    user_reg_add_builtin ("frame", value_of_builtin_frame_reg);
+    user_reg_add_builtin ("frame", value_of_builtin_frame_reg, NULL);
 }
Index: src/gdb/user-regs.c
===================================================================
--- src.orig/gdb/user-regs.c	2007-01-29 12:37:12.000000000 -0500
+++ src/gdb/user-regs.c	2007-01-29 12:39:17.000000000 -0500
@@ -41,7 +41,8 @@
 struct user_reg
 {
   const char *name;
-  struct value *(*read) (struct frame_info * frame);
+  struct value *(*read) (struct frame_info * frame, const void *baton);
+  const void *baton;
   struct user_reg *next;
 };
 
@@ -59,7 +60,8 @@ struct gdb_user_regs
 
 static void
 append_user_reg (struct gdb_user_regs *regs, const char *name,
-		 user_reg_read_ftype *read, struct user_reg *reg)
+		 user_reg_read_ftype *read, const void *baton,
+		 struct user_reg *reg)
 {
   /* The caller is responsible for allocating memory needed to store
      the register.  By doing this, the function can operate on a
@@ -67,6 +69,7 @@ append_user_reg (struct gdb_user_regs *r
   gdb_assert (reg != NULL);
   reg->name = name;
   reg->read = read;
+  reg->baton = baton;
   reg->next = NULL;
   (*regs->last) = reg;
   regs->last = &(*regs->last)->next;
@@ -77,9 +80,10 @@ append_user_reg (struct gdb_user_regs *r
 static struct gdb_user_regs builtin_user_regs = { NULL, &builtin_user_regs.first };
 
 void
-user_reg_add_builtin (const char *name, user_reg_read_ftype *read)
+user_reg_add_builtin (const char *name, user_reg_read_ftype *read,
+		      const void *baton)
 {
-  append_user_reg (&builtin_user_regs, name, read,
+  append_user_reg (&builtin_user_regs, name, read, baton,
 		   XMALLOC (struct user_reg));
 }
 
@@ -95,14 +99,14 @@ user_regs_init (struct gdbarch *gdbarch)
   struct gdb_user_regs *regs = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct gdb_user_regs);
   regs->last = &regs->first;
   for (reg = builtin_user_regs.first; reg != NULL; reg = reg->next)
-    append_user_reg (regs, reg->name, reg->read,
+    append_user_reg (regs, reg->name, reg->read, reg->baton,
 		     GDBARCH_OBSTACK_ZALLOC (gdbarch, struct user_reg));
   return regs;
 }
 
 void
 user_reg_add (struct gdbarch *gdbarch, const char *name,
-		 user_reg_read_ftype *read)
+	      user_reg_read_ftype *read, const void *baton)
 {
   struct gdb_user_regs *regs = gdbarch_data (gdbarch, user_regs_data);
   if (regs == NULL)
@@ -112,7 +116,7 @@ user_reg_add (struct gdbarch *gdbarch, c
       regs = user_regs_init (gdbarch);
       deprecated_set_gdbarch_data (gdbarch, user_regs_data, regs);
     }
-  append_user_reg (regs, name, read,
+  append_user_reg (regs, name, read, baton,
 		   GDBARCH_OBSTACK_ZALLOC (gdbarch, struct user_reg));
 }
 
@@ -199,7 +203,7 @@ value_of_user_reg (int regnum, struct fr
 		 + gdbarch_num_pseudo_regs (gdbarch));
   struct user_reg *reg = usernum_to_user_reg (gdbarch, regnum - maxregs);
   gdb_assert (reg != NULL);
-  return reg->read (frame);
+  return reg->read (frame, reg->baton);
 }
 
 extern initialize_file_ftype _initialize_user_regs; /* -Wmissing-prototypes */
Index: src/gdb/user-regs.h
===================================================================
--- src.orig/gdb/user-regs.h	2007-01-29 12:37:12.000000000 -0500
+++ src/gdb/user-regs.h	2007-01-29 12:39:17.000000000 -0500
@@ -57,15 +57,16 @@ extern const char *user_reg_map_regnum_t
    bytes as, at the time the register is being added, the type needed
    to describe the register has not bee initialized.  */
 
-typedef struct value *(user_reg_read_ftype) (struct frame_info *frame);
+typedef struct value *(user_reg_read_ftype) (struct frame_info *frame,
+					     const void *baton);
 extern struct value *value_of_user_reg (int regnum, struct frame_info *frame);
 
 /* Add a builtin register (present in all architectures).  */
 extern void user_reg_add_builtin (const char *name,
-				  user_reg_read_ftype *read);
+				  user_reg_read_ftype *read, const void *baton);
 
 /* Add a per-architecture frame register.  */
 extern void user_reg_add (struct gdbarch *gdbarch, const char *name, 
-			  user_reg_read_ftype *read);
+			  user_reg_read_ftype *read, const void *baton);
 
 #endif
Index: src/gdb/doc/gdb.texinfo
===================================================================
--- src.orig/gdb/doc/gdb.texinfo	2007-01-29 12:39:10.000000000 -0500
+++ src/gdb/doc/gdb.texinfo	2007-01-29 12:39:17.000000000 -0500
@@ -22178,6 +22178,7 @@ working C90 compiler, e.g.@: GCC.
 @heading Tools/packages optional for building @value{GDBN}
 @table @asis
 @item Expat
+@anchor{Expat}
 @value{GDBN} can use the Expat XML parsing library.  This library may be
 included with your operating system distribution; if it is not, you
 can get the latest version from @url{http://expat.sourceforge.net}.
@@ -22185,8 +22186,8 @@ The @code{configure} script will search 
 standard locations; if it is installed in an unusual path, you can
 use the @option{--with-libexpat-prefix} option to specify its location.
 
-Expat is used currently only used to implement some remote-specific
-features.
+Expat is used for remote protocol memory maps (@pxref{Memory map format})
+and for target descriptions (@pxref{Target Descriptions}).
 
 @end table
 
@@ -25694,9 +25695,15 @@ actually describe its own features.  Thi
 processor variants it has never seen before --- to the extent that the
 descriptions are accurate, and that @value{GDBN} understands them.
 
+@value{GDBN} must be compiled with Expat support to support XML target
+descriptions.  @xref{Expat}.
+
 @menu
 * Retrieving Descriptions::         How descriptions are fetched from a target.
 * Target Description Format::       The contents of a target description.
+* Predefined Target Types::         Standard types available for target
+                                    descriptions.
+* Standard Target Features::        Features @value{GDBN} knows about.
 @end menu
 
 @node Retrieving Descriptions
@@ -25743,10 +25750,10 @@ check that your feature descriptions are
 However, to help people unfamiliar with XML write descriptions for
 their targets, we also describe the grammar here.
 
-At the moment, target descriptions can only provide minimal information
-about the architecture of the remote target.  @value{GDBN} can use this
-information to autoconfigure, or to warn you if you connect to an
-unsupported target.
+Target descriptions can identify the architecture of the remote target
+and (for some architectures) provide information about custom register
+sets.  @value{GDBN} can use this information to autoconfigure for your
+target, or to warn you if you connect to an unsupported target.
 
 Here is a simple target description:
 
@@ -25760,13 +25767,16 @@ Here is a simple target description:
 This minimal description only says that the target uses
 the x86-64 architecture.
 
-A target description has the overall form:
+A target description has the following overall form, with [ ] marking
+optional elements and @dots{} marking repeatable elements.  The elements
+are explained further below.
 
 @example
 <?xml version="1.0"?>
 <!DOCTYPE target SYSTEM "gdb-target.dtd">
 <target>
-  <architecture>@var{arch name}</architecture>
+  @r{[}@var{architecture}@r{]}
+  @r{[}@var{feature}@dots{}@r{]}
 </target>
 @end example
 
@@ -25777,10 +25787,6 @@ declaration and document type declaratio
 (@value{GDBN} does not require them), but specifying them may be
 useful for XML validation tools.
 
-The content of the @samp{<architecture>} element is an architecture
-name, from the same selection accepted by @code{set architecture}
-(@pxref{Targets, ,Specifying a Debugging Target}).
-
 @subsection Inclusion
 
 It can sometimes be valuable to split a target description up into
@@ -25802,6 +25808,200 @@ using @samp{qXfer}, then the new documen
 file, @value{GDBN} will look for a file named @var{name} in the same
 directory as the original file.
 
+@subsection Architecture
+
+An @samp{<architecture>} element has this form:
+
+@example
+  <architecture>@var{arch}</architecture>
+@end example
+
+@var{arch} is an architecture name from the same selection
+accepted by @code{set architecture} (@pxref{Targets, ,Specifying a
+Debugging Target}).
+
+@subsection Features
+
+Each @samp{<feature>} describes some logical portion of the target
+system.  Features are currently used to describe available CPU
+registers and the types of their contents.  A @samp{<feature>} element
+has this form:
+
+@example
+<feature name="@var{name}">
+  @r{[}@var{type}@dots{}@r{]}
+  @var{reg}@dots{}
+</feature>
+@end example
+
+@noindent
+Each feature's name should be unique within the description.  The name
+of a feature does not matter unless @value{GDBN} has some special
+knowledge of the contents of that feature; if it does, the feature
+should have its standard name.  @xref{Standard Target Features}.
+
+@subsection Types
+
+Any register's value is a collection of bits which @value{GDBN} must
+interpret.  The default interpretation is a two's complement integer,
+but other types can be requested by name in the register description.
+Some predefined types are provided by @value{GDBN} (@pxref{Predefined
+Target Types}), and the description can define additional composite types.
+
+Each type element must have an @samp{id} attribute, which gives
+a unique (within the containing @samp{<feature>}) name to the type.
+Types must be defined before they are used.
+
+Some targets offer vector registers, which can be treated as arrays
+of scalar elements.  These types are written as @samp{<vector>} elements,
+specifying the array element type, @var{type}, and the number of elements,
+@var{count}:
+
+@example
+<vector id="@var{id}" type="@var{type}" count="@var{count}"/>
+@end example
+
+If a register's value is usefully viewed in multiple ways, define it
+with a union type containing the useful representations.  The
+@samp{<union>} element contains one or more @samp{<field>} elements,
+each of which has a @var{name} and a @var{type}:
+
+@example
+<union id="@var{id}">
+  <field name="@var{name}" type="@var{type}"/>
+  @dots{}
+</union>
+@end example
+
+@subsection Registers
+
+Each register is represented as an element with this form:
+
+@example
+<reg name="@var{name}"
+     bitsize="@var{size}"
+     @r{[}regnum="@var{num}"@r{]}
+     @r{[}save-restore="@var{save-restore}"@r{]}
+     @r{[}type="@var{type}"@r{]}
+     @r{[}group="@var{group}"@r{]}/>
+@end example
+
+@noindent
+The components are as follows:
+
+@table @var
+
+@item name
+The register's name; it must be unique within the target description.
+
+@item bitsize
+The register's size, in bits.
+
+@item regnum
+The register's number.  If omitted, a register's number is one greater
+than that of the previous register (either in the current feature or in
+a preceeding feature); the first register in the target description
+defaults to zero.  This register number is used to read or write
+the register; e.g.@: it is used in the remote @code{p} and @code{P}
+packets, and registers appear in the @code{g} and @code{G} packets
+in order of increasing register number.
+
+@item save-restore
+Whether the register should be preserved across inferior function
+calls; this must be either @code{yes} or @code{no}.  The default is
+@code{yes}, which is appropriate for most registers except for
+some system control registers; this is not related to the target's
+ABI.
+
+@item type
+The type of the register.  @var{type} may be a predefined type, a type
+defined in the current feature, or one of the special types @code{int}
+and @code{float}.  @code{int} is an integer type of the correct size
+for @var{bitsize}, and @code{float} is a floating point type (in the
+architecture's normal floating point format) of the correct size for
+@var{bitsize}.  The default is @code{int}.
+
+@item group
+The register group to which this register belongs.  @var{group} must
+be either @code{general}, @code{float}, or @code{vector}.  If no
+@var{group} is specified, @value{GDBN} will not display the register
+in @code{info registers}.
+
+@end table
+
+@node Predefined Target Types
+@section Predefined Target Types
+
+Type definitions in the self-description can build up composite types
+from basic building blocks, but can not define fundamental types.  Instead,
+standard identifiers are provided by @value{GDBN} for the fundamental
+types.  The currently supported types are:
+
+@table @code
+
+@item int8
+@itemx int16
+@itemx int32
+@itemx int64
+Signed integer types holding the specified number of bits.
+
+@item uint8
+@itemx uint16
+@itemx uint32
+@itemx uint64
+Unsigned integer types holding the specified number of bits.
+
+@item code_ptr
+@itemx data_ptr
+Pointers to unspecified code and data.  The program counter and
+any dedicated return address register may be marked as code
+pointers; printing a code pointer converts it into a symbolic
+address.  The stack pointer and any dedicated address registers
+may be marked as data pointers.
+
+@item arm_fpa_ext
+The 12-byte extended precision format used by ARM FPA registers.
+
+@end table
+
+@node Standard Target Features
+@section Standard Target Features
+
+A target description must contain either no registers or all the
+target's registers.  If the description contains no registers, then
+@value{GDBN} will assume a default register layout, selected based on
+the architecture.  If the description contains any registers, the
+default layout will not be used; the standard registers must be
+described in the target description, in such a way that @value{GDBN}
+can recognize them.
+
+This is accomplished by giving specific names to feature elements
+which contain standard registers.  @value{GDBN} will look for features
+with those names and verify that they contain the expected registers;
+if any known feature is missing required registers, or if any required
+feature is missing, @value{GDBN}, it will reject the target
+description.  You can add additional registers to any of the
+standard features - @value{GDBN} will display them just as if
+they were added to an unrecognized feature.
+
+This section lists the known features and their expected contents.
+Sample XML documents for these features are included in the
+@value{GDBN} source tree, in the directory @file{gdb/features}.
+
+Names recognized by @value{GDBN} should include the name of the
+company or organization which selected the name, and the overall
+architecture to which the feature applies; so e.g.@: the feature
+containing ARM core registers is named @samp{org.gnu.gdb.arm.core}.
+
+@subsection ARM Features
+
+The @samp{org.gnu.gdb.arm.core} feature is required for ARM targets.
+It should contain registers @samp{r0} through @samp{r13}, @samp{sp},
+@samp{lr}, @samp{pc}, and @samp{cpsr}.
+
+The @samp{org.gnu.gdb.arm.fpa} feature is optional.  If present, it
+should contain registers @samp{f0} through @samp{f7} and @samp{fps}.
+
 
 @include gpl.texi
 
Index: src/gdb/NEWS
===================================================================
--- src.orig/gdb/NEWS	2007-01-29 12:37:43.000000000 -0500
+++ src/gdb/NEWS	2007-01-29 12:39:17.000000000 -0500
@@ -18,6 +18,10 @@ a local file or over the remote serial p
 * Arrays of explicitly SIGNED or UNSIGNED CHARs are now printed as arrays
   of numbers.
 
+* Target descriptions can now describe target-specific registers,
+for architectures which have implemented the support (currently
+only ARM).
+
 * New commands
 
 set mem inaccessible-by-default
Index: src/gdb/features/arm-core.xml
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/features/arm-core.xml	2007-01-29 12:39:17.000000000 -0500
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007 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.core">
+  <reg name="r0" bitsize="32"/>
+  <reg name="r1" bitsize="32"/>
+  <reg name="r2" bitsize="32"/>
+  <reg name="r3" bitsize="32"/>
+  <reg name="r4" bitsize="32"/>
+  <reg name="r5" bitsize="32"/>
+  <reg name="r6" bitsize="32"/>
+  <reg name="r7" bitsize="32"/>
+  <reg name="r8" bitsize="32"/>
+  <reg name="r9" bitsize="32"/>
+  <reg name="r10" bitsize="32"/>
+  <reg name="r11" bitsize="32"/>
+  <reg name="r12" bitsize="32"/>
+  <reg name="sp" bitsize="32"/>
+  <reg name="lr" bitsize="32"/>
+  <reg name="pc" bitsize="32"/>
+
+  <!-- The CPSR is register 25, rather than register 16, because
+       the FPA registers historically were placed between the PC
+       and the CPSR in the "g" packet.  -->
+  <reg name="cpsr" bitsize="32" regnum="25"/>
+</feature>
Index: src/gdb/features/arm-fpa.xml
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/features/arm-fpa.xml	2007-01-29 12:39:17.000000000 -0500
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007 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.fpa">
+  <!-- f0's regnum is set explicitly, because the FPA registers
+       historically were placed between the PC and the CPSR in the "g"
+       packet - in the middle of org.gnu.gdb.arm.core.  -->
+  <reg name="f0" bitsize="96" type="arm_fpa_ext" regnum="16"/>
+  <reg name="f1" bitsize="96" type="arm_fpa_ext"/>
+  <reg name="f2" bitsize="96" type="arm_fpa_ext"/>
+  <reg name="f3" bitsize="96" type="arm_fpa_ext"/>
+  <reg name="f4" bitsize="96" type="arm_fpa_ext"/>
+  <reg name="f5" bitsize="96" type="arm_fpa_ext"/>
+  <reg name="f6" bitsize="96" type="arm_fpa_ext"/>
+  <reg name="f7" bitsize="96" type="arm_fpa_ext"/>
+
+  <reg name="fps" bitsize="32"/>
+</feature>
Index: src/gdb/doc/gdbint.texinfo
===================================================================
--- src.orig/gdb/doc/gdbint.texinfo	2007-01-29 12:37:12.000000000 -0500
+++ src/gdb/doc/gdbint.texinfo	2007-01-29 12:39:17.000000000 -0500
@@ -80,6 +80,7 @@ as the mechanisms that adapt @value{GDBN
 * Language Support::
 * Host Definition::
 * Target Architecture Definition::
+* Target Descriptions::
 * Target Vector Definition::
 * Native Debugging::
 * Support Libraries::
@@ -4477,6 +4478,133 @@ The @file{tm-@var{arch}.h} can be delete
 @file{configure.in} updated.
 
 
+@node Target Descriptions
+@chapter Target Descriptions
+@cindex target descriptions
+
+The target architecture definition (@pxref{Target Architecture Definition})
+contains @value{GDBN}'s hard-coded knowledge about an architecture.  For
+some platforms, it is handy to have more flexible knowledge about a specific
+instance of the architecture---for instance, a processor or development board.
+@dfn{Target descriptions} provide a mechanism for the user to tell @value{GDBN}
+more about what their target supports, or for the target to tell @value{GDBN}
+directly.
+
+How to use target descriptions and how to write them are covered in
+the @value{GDBN} user's manual.  This section will cover some related
+topics about the @value{GDBN} internals.
+
+@menu
+* Target Descriptions Implementation::
+* Adding Target Described Register Support::
+@end menu
+
+@node Target Descriptions Implementation
+@section Target Descriptions Implementation
+@cindex target descriptions, implementation
+
+Before @value{GDBN} connects to a new target, or runs a new program on
+an existing target, it discards any existing target description and
+reverts to a default gdbarch.  Then, after connecting, it looks for a
+new target description by calling @code{target_find_description}.
+
+A description may come from a user specified file (XML), the remote
+@samp{qXfer:features:read} packet (also XML), or from any custom
+@code{to_read_description} routine in the target vector.  For instance,
+the remote target supports guessing whether a MIPS target is 32-bit or
+64-bit based on the size of the @samp{g} packet.
+
+If any target description is found, @value{GDBN} creates a new gdbarch
+incorporating the description by calling @code{gdbarch_update_p}.  Any
+@samp{<architecture>} element is handled first, to determine which
+architecture's gdbarch initialization routine is called to create the
+new architecture.  Then the initialization routine is called, and has
+a chance to adjust the constructed architecture based on the contents
+of the target description.  For instance, it can recognize any
+properties set by a @code{to_read_description} routine.  Also
+@xref{Adding Target Described Register Support}.
+
+@node Adding Target Described Register Support
+@section Adding Target Described Register Support
+
+Target descriptions can describe additional registers specific to an
+instance of the target.  But it takes a little work in the architecture
+specific routines to support this.
+
+A target description must either have no registers or a complete
+set---this avoids complexity in trying to merge standard registers
+with the target defined registers.  It is the architecture's
+responsibility to validate that a description with registers has
+everything it needs.  To keep architecture code simple, the same
+mechanism is used to assign fixed internal register numbers to
+standard registers.
+
+If @code{tdesc_has_registers} returns 1, the description contains
+registers.  The architecture's @code{gdbarch_init} routine should:
+
+@itemize @bullet
+
+@item
+Call @code{tdesc_data_alloc} to allocate storage, early, before
+searching for a matching gdbarch or allocating a new one.
+
+@item
+Use @code{tdesc_find_feature} to locate standard features by name.
+
+@item
+Use @code{tdesc_numbered_register} and @code{tdesc_numbered_register_choices}
+to locate the expected registers in the standard features.
+
+@item
+Return @code{NULL} if a required feature is missing, or if any standard
+feature is missing expected registers.  This will produce a warning that
+the description was incomplete.
+
+@item
+Free the allocated data before returning, unless @code{tdesc_use_registers}
+is called.
+
+@item
+Call @code{set_gdbarch_num_regs} as usual, with a number higher than any
+fixed number passed to @code{tdesc_numbered_register}.
+
+@item
+Call @code{tdesc_use_registers} after creating a new gdbarch, before
+returning it.
+
+@end itemize
+
+After @code{tdesc_use_registers} has been called, the architecture's
+@code{register_name}, @code{register_type}, and @code{register_reggroup_p}
+routines will not be called; that information will be taken from
+the target description.  @code{num_regs} may be increased to account
+for any additional registers in the description.
+
+Pseudo-registers require some extra care:
+
+@itemize @bullet
+
+@item
+Using @code{tdesc_numbered_register} allows the architecture to give
+constant register numbers to standard architectural registers, e.g.@:
+as an @code{enum} in @file{@var{arch}-tdep.h}.  But because
+pseudo-registers are always numbered above @code{num_regs},
+which may be increased by the description, constant numbers
+can not be used for pseudos.  They must be numbered relative to
+@code{num_regs} instead.
+
+@item
+The description will not describe pseudo-registers, so the
+architecture must call @code{set_tdesc_pseudo_register_name},
+@code{set_tdesc_pseudo_register_type}, and
+@code{set_tdesc_pseudo_register_reggroup_p} to supply routines
+describing pseudo registers.  These routines will be passed
+internal register numbers, so the same routines used for the
+gdbarch equivalents are usually suitable.
+
+@end itemize
+
+
 @node Target Vector Definition
 
 @chapter Target Vector Definition
Index: src/gdb/eval.c
===================================================================
--- src.orig/gdb/eval.c	2007-01-29 12:37:12.000000000 -0500
+++ src/gdb/eval.c	2007-01-29 12:39:17.000000000 -0500
@@ -39,6 +39,7 @@
 #include "cp-support.h"
 #include "ui-out.h"
 #include "exceptions.h"
+#include "regcache.h"
 
 #include "gdb_assert.h"
 
@@ -500,8 +501,12 @@ evaluate_subexp_standard (struct type *e
     case OP_REGISTER:
       {
 	int regno = longest_to_int (exp->elts[pc + 1].longconst);
-	struct value *val = value_of_register (regno, get_selected_frame (NULL));
+	struct value *val;
 	(*pos) += 2;
+	if (noside == EVAL_AVOID_SIDE_EFFECTS)
+	  val = value_zero (register_type (current_gdbarch, regno), not_lval);
+	else
+	  val = value_of_register (regno, get_selected_frame (NULL));
 	if (val == NULL)
 	  error (_("Value of register %s not available."),
 		 frame_map_regnum_to_name (get_selected_frame (NULL), regno));
Index: src/gdb/testsuite/gdb.xml/single-reg.xml
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/testsuite/gdb.xml/single-reg.xml	2007-01-29 12:39:17.000000000 -0500
@@ -0,0 +1,5 @@
+<target>
+  <feature name="single">
+    <reg name="one" bitsize="32"/>
+  </feature>
+</target>
Index: src/gdb/testsuite/gdb.xml/tdesc-regs.exp
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/testsuite/gdb.xml/tdesc-regs.exp	2007-01-29 12:39:17.000000000 -0500
@@ -0,0 +1,95 @@
+# Copyright 2007 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+if {[gdb_skip_xml_test]} {
+    unsupported "tdesc-regs.exp"
+    return -1
+}
+
+gdb_start
+
+# To test adding registers, we need a core set of registers for this
+# architecture, or the description will be rejected.
+
+set core-regs ""
+switch -glob -- [istarget] {
+    "*arm-*-*" {
+        set core-regs arm-core
+    }
+    "xscale-*-*" {
+        set core-regs arm-core
+    }
+}
+
+# If no core registers were specified, assume this target does not
+# support target-defined registers.  Verify that we get a warning if
+# we try to use them.  This not only tests the warning, but also
+# reminds maintainers to add test support when they add the feature.
+if {[string equal ${core-regs} ""]} {
+    gdb_test "set tdesc file $srcdir/$subdir/single-reg.xml" \
+	"warning: Target-supplied registers are not supported.*" \
+	"set tdesc file single-reg.xml"
+    unsupported "register tests"
+    return 0
+}
+
+# Otherwise, we support both XML and target defined registers.
+
+# Make sure we reject a description missing standard registers,
+# like the PC.
+gdb_test "set tdesc file $srcdir/$subdir/single-reg.xml" \
+    "warning: Architecture rejected target-supplied description" \
+    "set tdesc file single-reg.xml"
+
+# Copy the core registers into the objdir if necessary, so that they
+# will be found by <xi:include>.
+file delete "core-regs.xml"
+file copy "$srcdir/../features/${core-regs}.xml" "core-regs.xml"
+
+# Similarly, we need to copy files under test into the objdir.
+proc load_description { file errmsg } {
+    global srcdir
+    global subdir
+    global gdb_prompt
+
+    file delete "regs.xml"
+    file copy "$srcdir/$subdir/$file" "regs.xml"
+
+    # Anchor the test output, so that error messages are detected.
+    set cmd "set tdesc filename regs.xml"
+    set msg "set tdesc filename $file"
+    set cmd_regex [string_to_regexp $cmd]
+    gdb_test_multiple $cmd $msg {
+	-re "^$cmd_regex\r\n$errmsg$gdb_prompt $" {
+	    pass $msg
+	}
+    }
+}
+
+load_description "extra-regs.xml" ""
+gdb_test "ptype \$extrareg" "type = (int|long|long long)"
+gdb_test "ptype \$uintreg" "type = uint32_t"
+gdb_test "ptype \$vecreg" "type = int8_t \\\[4\\\]"
+gdb_test "ptype \$unionreg" \
+    "type = union {\r\n *v4int8 v4;\r\n *v2int16 v2;\r\n}"
+gdb_test "ptype \$unionreg.v4" "type = int8_t \\\[4\\\]"
+
+load_description "core-only.xml" ""
+# The extra register from the previous description should be gone.
+gdb_test "ptype \$extrareg" "type = void"
+
+file delete "core-regs.xml"
+file delete "regs.xml"
Index: src/gdb/testsuite/gdb.xml/core-only.xml
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/testsuite/gdb.xml/core-only.xml	2007-01-29 12:39:17.000000000 -0500
@@ -0,0 +1,3 @@
+<target>
+  <xi:include href="core-regs.xml"/>
+</target>
Index: src/gdb/testsuite/gdb.xml/extra-regs.xml
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/testsuite/gdb.xml/extra-regs.xml	2007-01-29 12:39:17.000000000 -0500
@@ -0,0 +1,16 @@
+<target>
+  <xi:include href="core-regs.xml"/>
+  <feature name="extra">
+    <vector id="v4int8" type="int8" count="4"/>
+    <vector id="v2int16" type="int16" count="2"/>
+    <union id="vecint">
+      <field name="v4" type="v4int8"/>
+      <field name="v2" type="v2int16"/>
+    </union>
+
+    <reg name="extrareg" bitsize="32"/>
+    <reg name="uintreg" bitsize="32" type="uint32"/>
+    <reg name="vecreg" bitsize="32" type="v4int8"/>
+    <reg name="unionreg" bitsize="32" type="vecint"/>
+  </feature>
+</target>


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