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]

Re: [rfc] Let the remote protocol report the target's arch


On Sat, Jan 06, 2007 at 12:29:01PM +0200, Eli Zaretskii wrote:
> > Date: Fri, 5 Jan 2007 14:15:11 -0500
> > From: Daniel Jacobowitz <drow@false.org>
> > Cc: gdb-patches@sourceware.org
> > 
> > Do you think that "set tdesc filename" without a path, or "unset tdesc
> > filename", is clearer?
> 
> Yes, I think using unset is better here.  There's a sentence in your
> patch that says:
> 
>   Show the filename to read for a target description, if set.
> 
> So you also refer to it as ``unset'' in some sense.

In that case, could you take a brief look at this revised version? 
I've made only minimal changes to add "unset tdesc filename" (and
corrected two embarrassing problems with "show tdesc filename"...).

I like this version better than the one with an optional filename.

-- 
Daniel Jacobowitz
CodeSourcery

2006-12-07  Daniel Jacobowitz  <dan@codesourcery.com>

	* NEWS: Mention target descriptions, "set tdesc filename",
	"unset tdesc filename", "show tdesc filename", and
	qXfer:features:read.
	* arch-utils.c (choose_architecture_for_target): New function.
	(gdbarch_info_fill): Call it.
	* target-descriptions.c (struct property): Make members non-const.
	(struct target_desc): Add arch member.
	(target_description_filename): New variable.
	(target_find_description): Try via XML first.
	(tdesc_architecture): New.
	(free_target_description, make_cleanup_free_target_description): New.
	(set_tdesc_property): Call xstrdup.
	(set_tdesc_architecture, tdesc_set_cmdlist, tdesc_show_cmdlist)
	(tdesc_unset_cmdlist, unset_tdesc_cmd, unset_tdesc_filename_cmd)
	(set_tdesc_cmd, show_tdesc_cmd, set_tdesc_filename_cmd)
	(show_tdesc_filename_cmd, _initialize_target_descriptions): New.
	* target-descriptions.h (tdesc_architecture)
	(make_cleanup_free_target_description, set_tdesc_architecture): New
	prototypes.
	* Makefile.in (SFILES): Add xml-tdesc.c.
	(COMMON_OBS): Add xml-tdesc.o.
	(target-descriptions.o): Update.
	(xml-tdesc.o): New rule.
	* xml-tdesc.c, xml-tdesc.h: New files.
	* remote.c (PACKET_qXfer_features): New enum.
	(remote_protocol_features): Add qXfer:features:read.
	(remote_xfer_partial): Handle TARGET_OBJECT_AVAILABLE_FEATURES.
	(_initialize_remote): Register qXfer:features:read.
	* target.h (enum target_object): Add TARGET_OBJECT_AVAILABLE_FEATURES.
	* features/gdb-target.dtd: New file.

2006-12-07  Daniel Jacobowitz  <dan@codesourcery.com>

	* linux-i386-low.c (the_low_target): Set arch_string.
	* linux-x86-64-low.c (the_low_target): Likewise.
	* linux-low.c (linux_arch_string): New.
	(linux_target_ops): Add it.
	* linux-low.h (struct linux_target_ops): Add arch_string.
	* server.c (write_qxfer_response): Use const void * for DATA.
	(get_features_xml): New.
	(handle_query): Handle qXfer:features:read.  Report it for qSupported.
	* target.h (struct target_ops): Add arch_string method.

2006-12-07  Daniel Jacobowitz  <dan@codesourcery.com>

	* gdb.texinfo (Target Descriptions): New section.
	(General Query Packets): Add QPassSignals anchor.  Mention
	qXfer:features:read under qSupported.  Expand mentions of
	qXfer:memory-map:read and QPassSignals.  Document
	qXfer:features:read.

---
 gdb/Makefile.in                  |    9 +
 gdb/NEWS                         |   13 ++
 gdb/arch-utils.c                 |   73 ++++++++++++
 gdb/doc/gdb.texinfo              |  155 +++++++++++++++++++++++++
 gdb/features/gdb-target.dtd      |    9 +
 gdb/gdbserver/linux-i386-low.c   |    6 +
 gdb/gdbserver/linux-low.c        |    7 +
 gdb/gdbserver/linux-low.h        |    4 
 gdb/gdbserver/linux-x86-64-low.c |    6 +
 gdb/gdbserver/server.c           |   69 +++++++++++
 gdb/gdbserver/target.h           |    4 
 gdb/remote.c                     |   11 +
 gdb/target-descriptions.c        |  169 +++++++++++++++++++++++++++-
 gdb/target-descriptions.h        |    9 +
 gdb/target.h                     |    6 -
 gdb/xml-tdesc.c                  |  233 +++++++++++++++++++++++++++++++++++++++
 gdb/xml-tdesc.h                  |   36 ++++++
 17 files changed, 806 insertions(+), 13 deletions(-)

Index: src/gdb/arch-utils.c
===================================================================
--- src.orig/gdb/arch-utils.c	2007-01-09 13:13:14.000000000 -0500
+++ src/gdb/arch-utils.c	2007-01-09 13:16:08.000000000 -0500
@@ -409,6 +409,75 @@ set_endian (char *ignore_args, int from_
   show_endian (gdb_stdout, from_tty, NULL, NULL);
 }
 
+/* Given SELECTED, a currently selected BFD architecture, and
+   FROM_TARGET, a BFD architecture reported by the target description,
+   return what architecture to use.  Either may be NULL; if both are
+   specified, we use the more specific.  If the two are obviously
+   incompatible, warn the user.  */
+
+static const struct bfd_arch_info *
+choose_architecture_for_target (const struct bfd_arch_info *selected,
+				const struct bfd_arch_info *from_target)
+{
+  const struct bfd_arch_info *compat1, *compat2;
+
+  if (selected == NULL)
+    return from_target;
+
+  if (from_target == NULL)
+    return selected;
+
+  /* struct bfd_arch_info objects are singletons: that is, there's
+     supposed to be exactly one instance for a given machine.  So you
+     can tell whether two are equivalent by comparing pointers.  */
+  if (from_target == selected)
+    return selected;
+
+  /* BFD's 'A->compatible (A, B)' functions return zero if A and B are
+     incompatible.  But if they are compatible, it returns the 'more
+     featureful' of the two arches.  That is, if A can run code
+     written for B, but B can't run code written for A, then it'll
+     return A.
+
+     Some targets (e.g. MIPS as of 2006-12-04) don't fully
+     implement this, instead always returning NULL or the first
+     argument.  We detect that case by checking both directions.  */
+
+  compat1 = selected->compatible (selected, from_target);
+  compat2 = from_target->compatible (from_target, selected);
+
+  if (compat1 == NULL && compat2 == NULL)
+    {
+      warning (_("Selected architecture %s is not compatible "
+		 "with reported target architecture %s"),
+	       selected->printable_name, from_target->printable_name);
+      return selected;
+    }
+
+  if (compat1 == NULL)
+    return compat2;
+  if (compat2 == NULL)
+    return compat1;
+  if (compat1 == compat2)
+    return compat1;
+
+  /* If the two didn't match, but one of them was a default architecture,
+     assume the more specific one is correct.  This handles the case
+     where an executable or target description just says "mips", but
+     the other knows which MIPS variant.  */
+  if (compat1->the_default)
+    return compat2;
+  if (compat2->the_default)
+    return compat1;
+
+  /* We have no idea which one is better.  This is a bug, but not
+     a critical problem; warn the user.  */
+  warning (_("Selected architecture %s is ambiguous with "
+	     "reported target architecture %s"),
+	   selected->printable_name, from_target->printable_name);
+  return selected;
+}
+
 /* Functions to manipulate the architecture of the target */
 
 enum set_arch { set_arch_auto, set_arch_manual };
@@ -703,6 +772,10 @@ gdbarch_info_fill (struct gdbarch_info *
       && bfd_get_arch (info->abfd) != bfd_arch_unknown
       && bfd_get_arch (info->abfd) != bfd_arch_obscure)
     info->bfd_arch_info = bfd_get_arch_info (info->abfd);
+  /* From the target.  */
+  if (info->target_desc != NULL)
+    info->bfd_arch_info = choose_architecture_for_target
+      (info->bfd_arch_info, tdesc_architecture (info->target_desc));
   /* From the default.  */
   if (info->bfd_arch_info == NULL)
     info->bfd_arch_info = default_bfd_arch;
Index: src/gdb/target-descriptions.c
===================================================================
--- src.orig/gdb/target-descriptions.c	2007-01-09 13:13:34.000000000 -0500
+++ src/gdb/target-descriptions.c	2007-01-09 14:42:29.000000000 -0500
@@ -23,9 +23,11 @@
 
 #include "defs.h"
 #include "arch-utils.h"
+#include "gdbcmd.h"
 #include "target.h"
 #include "target-descriptions.h"
 #include "vec.h"
+#include "xml-tdesc.h"
 
 #include "gdb_assert.h"
 
@@ -33,13 +35,16 @@
 
 typedef struct property
 {
-  const char *key;
-  const char *value;
+  char *key;
+  char *value;
 } property_s;
 DEF_VEC_O(property_s);
 
 struct target_desc
 {
+  /* The architecture reported by the target, if any.  */
+  const struct bfd_arch_info *arch;
+
   /* Any architecture-specific properties specified by the target.  */
   VEC(property_s) *properties;
 };
@@ -61,6 +66,12 @@ static int target_desc_fetched;
 
 static const struct target_desc *current_target_desc;
 
+/* Other global variables.  */
+
+/* The filename to read a target description from.  */
+
+static char *target_description_filename;
+
 /* Fetch the current target's description, and switch the current
    architecture to one which incorporates that description.  */
 
@@ -79,7 +90,22 @@ target_find_description (void)
      disconnected from the previous target.  */
   gdb_assert (gdbarch_target_desc (current_gdbarch) == NULL);
 
-  current_target_desc = target_read_description (&current_target);
+  /* First try to fetch an XML description from the user-specified
+     file.  */
+  current_target_desc = NULL;
+  if (target_description_filename != NULL
+      && *target_description_filename != '\0')
+    current_target_desc
+      = file_read_description_xml (target_description_filename);
+
+  /* Next try to read the description from the current target using
+     target objects.  */
+  if (current_target_desc == NULL)
+    current_target_desc = target_read_description_xml (&current_target);
+
+  /* If that failed try a target-specific hook.  */
+  if (current_target_desc == NULL)
+    current_target_desc = target_read_description (&current_target);
 
   /* If a non-NULL description was returned, then update the current
      architecture.  */
@@ -130,6 +156,9 @@ target_current_description (void)
 
   return NULL;
 }
+
+
+/* Direct accessors for feature sets.  */
 
 /* Return the string value of a property named KEY, or NULL if the
    property was not specified.  */
@@ -148,6 +177,16 @@ tdesc_property (const struct target_desc
   return NULL;
 }
 
+/* Return the BFD architecture associated with this target
+   description, or NULL if no architecture was specified.  */
+
+const struct bfd_arch_info *
+tdesc_architecture (const struct target_desc *target_desc)
+{
+  return target_desc->arch;
+}
+
+
 /* Methods for constructing a target description.  */
 
 struct target_desc *
@@ -156,6 +195,31 @@ allocate_target_description (void)
   return XZALLOC (struct target_desc);
 }
 
+static void
+free_target_description (void *arg)
+{
+  struct target_desc *target_desc = arg;
+  struct property *prop;
+  int ix;
+
+  for (ix = 0;
+       VEC_iterate (property_s, target_desc->properties, ix, prop);
+       ix++)
+    {
+      xfree (prop->key);
+      xfree (prop->value);
+    }
+  VEC_free (property_s, target_desc->properties);
+
+  xfree (target_desc);
+}
+
+struct cleanup *
+make_cleanup_free_target_description (struct target_desc *target_desc)
+{
+  return make_cleanup (free_target_description, target_desc);
+}
+
 void
 set_tdesc_property (struct target_desc *target_desc,
 		    const char *key, const char *value)
@@ -171,7 +235,102 @@ set_tdesc_property (struct target_desc *
       internal_error (__FILE__, __LINE__,
 		      _("Attempted to add duplicate property \"%s\""), key);
 
-  new_prop.key = key;
-  new_prop.value = value;
+  new_prop.key = xstrdup (key);
+  new_prop.value = xstrdup (value);
   VEC_safe_push (property_s, target_desc->properties, &new_prop);
 }
+
+void
+set_tdesc_architecture (struct target_desc *target_desc,
+			const struct bfd_arch_info *arch)
+{
+  target_desc->arch = arch;
+}
+
+
+static struct cmd_list_element *tdesc_set_cmdlist, *tdesc_show_cmdlist;
+static struct cmd_list_element *tdesc_unset_cmdlist;
+
+/* Helper functions for the CLI commands.  */
+
+static void
+set_tdesc_cmd (char *args, int from_tty)
+{
+  help_list (tdesc_set_cmdlist, "set tdesc ", -1, gdb_stdout);
+}
+
+static void
+show_tdesc_cmd (char *args, int from_tty)
+{
+  cmd_show_list (tdesc_show_cmdlist, from_tty, "");
+}
+
+static void
+unset_tdesc_cmd (char *args, int from_tty)
+{
+  help_list (tdesc_unset_cmdlist, "unset tdesc ", -1, gdb_stdout);
+}
+
+static void
+set_tdesc_filename_cmd (char *args, int from_tty,
+			struct cmd_list_element *c)
+{
+  target_clear_description ();
+  target_find_description ();
+}
+
+static void
+show_tdesc_filename_cmd (struct ui_file *file, int from_tty,
+			 struct cmd_list_element *c,
+			 const char *value)
+{
+  if (value != NULL && *value != '\0')
+    printf_filtered (_("\
+The target description will be read from \"%s\".\n"),
+		     value);
+  else
+    printf_filtered (_("\
+The target description will be read from the target.\n"));
+}
+
+static void
+unset_tdesc_filename_cmd (char *args, int from_tty)
+{
+  xfree (target_description_filename);
+  target_description_filename = NULL;
+  target_clear_description ();
+  target_find_description ();
+}
+
+void
+_initialize_target_descriptions (void)
+{
+  add_prefix_cmd ("tdesc", class_maintenance, set_tdesc_cmd, _("\
+Set target description specific variables."),
+		  &tdesc_set_cmdlist, "set tdesc ",
+		  0 /* allow-unknown */, &setlist);
+  add_prefix_cmd ("tdesc", class_maintenance, show_tdesc_cmd, _("\
+Show target description specific variables."),
+		  &tdesc_show_cmdlist, "show tdesc ",
+		  0 /* allow-unknown */, &showlist);
+  add_prefix_cmd ("tdesc", class_maintenance, unset_tdesc_cmd, _("\
+Unset target description specific variables."),
+		  &tdesc_unset_cmdlist, "unset tdesc ",
+		  0 /* allow-unknown */, &unsetlist);
+
+  add_setshow_filename_cmd ("filename", class_obscure,
+			    &target_description_filename,
+			    _("\
+Set the file to read for an XML target description"), _("\
+Show the file to read for an XML target description"), _("\
+When set, GDB will read the target description from a local\n\
+file instead of querying the remote target."),
+			    set_tdesc_filename_cmd,
+			    show_tdesc_filename_cmd,
+			    &tdesc_set_cmdlist, &tdesc_show_cmdlist);
+
+  add_cmd ("filename", class_obscure, unset_tdesc_filename_cmd, _("\
+Unset the file to read for an XML target description.  When unset,\n\
+GDB will read the description from the target."),
+	   &tdesc_unset_cmdlist);
+}
Index: src/gdb/target-descriptions.h
===================================================================
--- src.orig/gdb/target-descriptions.h	2007-01-09 13:13:34.000000000 -0500
+++ src/gdb/target-descriptions.h	2007-01-09 13:16:08.000000000 -0500
@@ -44,6 +44,12 @@ const struct target_desc *target_current
 
 /* Accessors for target descriptions.  */
 
+/* Return the BFD architecture associated with this target
+   description, or NULL if no architecture was specified.  */
+
+const struct bfd_arch_info *tdesc_architecture
+  (const struct target_desc *);
+
 /* Return the string value of a property named KEY, or NULL if the
    property was not specified.  */
 
@@ -53,6 +59,9 @@ const char *tdesc_property (const struct
 /* 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);
Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in	2007-01-09 13:13:13.000000000 -0500
+++ src/gdb/Makefile.in	2007-01-09 13:16:08.000000000 -0500
@@ -563,7 +563,7 @@ SFILES = ada-exp.y ada-lang.c ada-typepr
 	user-regs.c \
 	valarith.c valops.c valprint.c value.c varobj.c vec.c \
 	wrapper.c \
-	xml-support.c
+	xml-tdesc.c xml-support.c
 
 LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
@@ -972,7 +972,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $
 	tramp-frame.o \
 	solib.o solib-null.o \
 	prologue-value.o memory-map.o xml-support.o \
-	target-descriptions.o target-memory.o
+	target-descriptions.o target-memory.o xml-tdesc.o
 
 TSOBS = inflow.o
 
@@ -2776,7 +2776,8 @@ target.o: target.c $(defs_h) $(gdb_strin
 	$(gdb_wait_h) $(dcache_h) $(regcache_h) $(gdb_assert_h) $(gdbcore_h) \
 	$(exceptions_h) $(target_descriptions_h)
 target-descriptions.o: target-descriptions.c $(defs_h) $(arch_utils_h) \
-	$(target_h) $(target_descriptions_h) $(vec_h) $(gdb_assert_h)
+	$(target_h) $(target_descriptions_h) $(vec_h) $(xml_tdesc_h) \
+	$(gdbcmd_h) $(gdb_assert_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) \
@@ -2874,6 +2875,8 @@ xcoffread.o: xcoffread.c $(defs_h) $(bfd
 	$(complaints_h) $(gdb_stabs_h) $(aout_stab_gnu_h)
 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) $(gdb_assert_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-tdesc.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/xml-tdesc.c	2007-01-09 13:16:08.000000000 -0500
@@ -0,0 +1,233 @@
+/* XML target description support for GDB.
+
+   Copyright (C) 2006
+   Free Software Foundation, Inc.
+
+   Contributed by CodeSourcery.
+
+   This file is part of GDB.
+
+   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., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "defs.h"
+#include "target.h"
+#include "target-descriptions.h"
+#include "xml-support.h"
+#include "xml-tdesc.h"
+
+#include "gdb_assert.h"
+
+#if !defined(HAVE_LIBEXPAT)
+
+/* Parse DOCUMENT into a target description.  Or don't, since we don't have
+   an XML parser.  */
+
+static struct target_desc *
+tdesc_parse_xml (const char *document)
+{
+  static int have_warned;
+
+  if (!have_warned)
+    {
+      have_warned = 1;
+      warning (_("Can not parse XML target description; XML support was "
+		 "disabled at compile time"));
+    }
+
+  return NULL;
+}
+
+#else /* HAVE_LIBEXPAT */
+
+/* Callback data for target description parsing.  */
+
+struct tdesc_parsing_data
+{
+  /* The target description we are building.  */
+  struct target_desc *tdesc;
+};
+
+/* Handle the end of an <architecture> element and its value.  */
+
+static void
+tdesc_end_arch (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;
+  const struct bfd_arch_info *arch;
+
+  arch = bfd_scan_arch (body_text);
+  if (arch == NULL)
+    gdb_xml_error (parser, _("Target description specified unknown "
+			     "architecture \"%s\""), body_text);
+  set_tdesc_architecture (data->tdesc, arch);
+}
+
+/* The elements and attributes of an XML target description.  */
+
+const struct gdb_xml_element target_children[] = {
+  { "architecture", NULL, NULL, GDB_XML_EF_OPTIONAL,
+    NULL, tdesc_end_arch },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+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 }
+};
+
+/* Parse DOCUMENT into a target description and return it.  */
+
+static struct target_desc *
+tdesc_parse_xml (const char *document)
+{
+  struct cleanup *back_to, *result_cleanup;
+  struct gdb_xml_parser *parser;
+  struct tdesc_parsing_data data;
+
+  memset (&data, 0, sizeof (struct tdesc_parsing_data));
+
+  back_to = make_cleanup (null_cleanup, NULL);
+  parser = gdb_xml_create_parser_and_cleanup (_("target description"),
+					      tdesc_elements, &data);
+
+  data.tdesc = allocate_target_description ();
+  result_cleanup = make_cleanup_free_target_description (data.tdesc);
+
+  if (gdb_xml_parse (parser, document) == 0)
+    {
+      /* Parsed successfully.  */
+      discard_cleanups (result_cleanup);
+      do_cleanups (back_to);
+      return data.tdesc;
+    }
+  else
+    {
+      warning (_("Could not load XML target description; ignoring"));
+      do_cleanups (back_to);
+      return NULL;
+    }
+}
+
+#endif /* HAVE_LIBEXPAT */
+
+
+/* Close FILE.  */
+
+static void
+do_cleanup_fclose (void *file)
+{
+  fclose (file);
+}
+
+/* Open FILENAME, read all its text into memory, close it, and return
+   the text.  If something goes wrong, return NULL and warn.  */
+
+static char *
+fetch_xml_from_file (const char *filename)
+{
+  FILE *file;
+  struct cleanup *back_to;
+  char *text;
+  size_t len, offset;
+
+  file = fopen (filename, FOPEN_RT);
+  if (file == NULL)
+    {
+      warning (_("Could not open \"%s\""), filename);
+      return NULL;
+    }
+  back_to = make_cleanup (do_cleanup_fclose, file);
+
+  /* Read in the whole file, one chunk at a time.  */
+  len = 4096;
+  offset = 0;
+  text = xmalloc (len);
+  make_cleanup (free_current_contents, &text);
+  while (1)
+    {
+      size_t bytes_read;
+
+      /* Continue reading where the last read left off.  Leave at least
+	 one byte so that we can NUL-terminate the result.  */
+      bytes_read = fread (text + offset, 1, len - offset - 1, file);
+      if (ferror (file))
+	{
+	  warning (_("Read error from \"%s\""), filename);
+	  do_cleanups (back_to);
+	  return NULL;
+	}
+
+      offset += bytes_read;
+
+      if (feof (file))
+	break;
+
+      len = len * 2;
+      text = xrealloc (text, len);
+    }
+
+  fclose (file);
+  discard_cleanups (back_to);
+
+  text[offset] = '\0';
+  return text;
+}
+
+/* Read an XML target description from FILENAME.  Parse it, and return
+   the parsed description.  */
+
+const struct target_desc *
+file_read_description_xml (const char *filename)
+{
+  struct target_desc *tdesc;
+  char *tdesc_str;
+  struct cleanup *back_to;
+
+  tdesc_str = fetch_xml_from_file (filename);
+  if (tdesc_str == NULL)
+    return NULL;
+
+  back_to = make_cleanup (xfree, tdesc_str);
+  tdesc = tdesc_parse_xml (tdesc_str);
+  do_cleanups (back_to);
+
+  return tdesc;
+}
+
+/* Read an XML target description using OPS.  Parse it, and return the
+   parsed description.  */
+
+const struct target_desc *
+target_read_description_xml (struct target_ops *ops)
+{
+  struct target_desc *tdesc;
+  char *tdesc_str;
+  struct cleanup *back_to;
+
+  tdesc_str = target_read_stralloc (ops, TARGET_OBJECT_AVAILABLE_FEATURES,
+				    "target.xml");
+  if (tdesc_str == NULL)
+    return NULL;
+
+  back_to = make_cleanup (xfree, tdesc_str);
+  tdesc = tdesc_parse_xml (tdesc_str);
+  do_cleanups (back_to);
+
+  return tdesc;
+}
Index: src/gdb/xml-tdesc.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/xml-tdesc.h	2007-01-09 13:16:08.000000000 -0500
@@ -0,0 +1,36 @@
+/* XML target description support for GDB.
+
+   Copyright (C) 2006
+   Free Software Foundation, Inc.
+
+   Contributed by CodeSourcery.
+
+   This file is part of GDB.
+
+   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., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+struct target_ops;
+struct target_desc;
+
+/* Read an XML target description from FILENAME.  Parse it, and return
+   the parsed description.  */
+
+const struct target_desc *file_read_description_xml (const char *filename);
+
+/* Read an XML target description using OPS.  Parse it, and return the
+   parsed description.  */
+
+const struct target_desc *target_read_description_xml (struct target_ops *);
Index: src/gdb/remote.c
===================================================================
--- src.orig/gdb/remote.c	2007-01-09 13:13:30.000000000 -0500
+++ src/gdb/remote.c	2007-01-09 13:16:08.000000000 -0500
@@ -893,6 +893,7 @@ enum {
   PACKET_Z3,
   PACKET_Z4,
   PACKET_qXfer_auxv,
+  PACKET_qXfer_features,
   PACKET_qXfer_memory_map,
   PACKET_qGetTLSAddr,
   PACKET_qSupported,
@@ -2294,6 +2295,8 @@ static struct protocol_feature remote_pr
   { "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
   { "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
     PACKET_qXfer_auxv },
+  { "qXfer:features:read", PACKET_DISABLE, remote_supported_packet,
+    PACKET_qXfer_features },
   { "qXfer:memory-map:read", PACKET_DISABLE, remote_supported_packet,
     PACKET_qXfer_memory_map },
   { "QPassSignals", PACKET_DISABLE, remote_supported_packet,
@@ -5716,6 +5719,11 @@ remote_xfer_partial (struct target_ops *
       return remote_read_qxfer (ops, "auxv", annex, readbuf, offset, len,
 				&remote_protocol_packets[PACKET_qXfer_auxv]);
 
+    case TARGET_OBJECT_AVAILABLE_FEATURES:
+      return remote_read_qxfer
+	(ops, "features", annex, readbuf, offset, len,
+	 &remote_protocol_packets[PACKET_qXfer_features]);
+
     case TARGET_OBJECT_MEMORY_MAP:
       gdb_assert (annex == NULL);
       return remote_read_qxfer (ops, "memory-map", annex, readbuf, offset, len,
@@ -6589,6 +6597,9 @@ Show the maximum size of the address (in
   add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_auxv],
 			 "qXfer:auxv:read", "read-aux-vector", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_features],
+			 "qXfer:features:read", "target-features", 0);
+
   add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_memory_map],
 			 "qXfer:memory-map:read", "memory-map", 0);
 
Index: src/gdb/target.h
===================================================================
--- src.orig/gdb/target.h	2007-01-09 13:13:34.000000000 -0500
+++ src/gdb/target.h	2007-01-09 13:16:08.000000000 -0500
@@ -206,8 +206,10 @@ enum target_object
      a previously erased flash memory.  Using it without erasing
      flash can have unexpected results.  Addresses are physical
      address on target, and not relative to flash start.  */
-  TARGET_OBJECT_FLASH
-
+  TARGET_OBJECT_FLASH,
+  /* Available target-specific features, e.g. registers and coprocessors.
+     See "target-descriptions.c".  ANNEX should never be empty.  */
+  TARGET_OBJECT_AVAILABLE_FEATURES
   /* Possible future objects: TARGET_OBJECT_FILE, TARGET_OBJECT_PROC, ... */
 };
 
Index: src/gdb/gdbserver/linux-i386-low.c
===================================================================
--- src.orig/gdb/gdbserver/linux-i386-low.c	2007-01-09 13:13:37.000000000 -0500
+++ src/gdb/gdbserver/linux-i386-low.c	2007-01-09 13:16:08.000000000 -0500
@@ -198,4 +198,10 @@ struct linux_target_ops the_low_target =
   NULL,
   1,
   i386_breakpoint_at,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  0,
+  "i386"
 };
Index: src/gdb/gdbserver/linux-low.c
===================================================================
--- src.orig/gdb/gdbserver/linux-low.c	2007-01-09 13:13:38.000000000 -0500
+++ src/gdb/gdbserver/linux-low.c	2007-01-09 13:16:08.000000000 -0500
@@ -1641,6 +1641,12 @@ linux_read_offsets (CORE_ADDR *text_p, C
 }
 #endif
 
+static const char *
+linux_arch_string (void)
+{
+  return the_low_target.arch_string;
+}
+
 static struct target_ops linux_target_ops = {
   linux_create_inferior,
   linux_attach,
@@ -1670,6 +1676,7 @@ static struct target_ops linux_target_op
 #else
   NULL,
 #endif
+  linux_arch_string,
 };
 
 static void
Index: src/gdb/gdbserver/linux-low.h
===================================================================
--- src.orig/gdb/gdbserver/linux-low.h	2007-01-09 13:13:38.000000000 -0500
+++ src/gdb/gdbserver/linux-low.h	2007-01-09 13:16:08.000000000 -0500
@@ -71,6 +71,10 @@ struct linux_target_ops
   /* Whether to left-pad registers for PEEKUSR/POKEUSR if they are smaller
      than an xfer unit.  */
   int left_pad_xfer;
+
+  /* What string to report to GDB when it asks for the architecture,
+     or NULL not to answer.  */
+  const char *arch_string;
 };
 
 extern struct linux_target_ops the_low_target;
Index: src/gdb/gdbserver/linux-x86-64-low.c
===================================================================
--- src.orig/gdb/gdbserver/linux-x86-64-low.c	2007-01-09 13:13:38.000000000 -0500
+++ src/gdb/gdbserver/linux-x86-64-low.c	2007-01-09 13:16:08.000000000 -0500
@@ -172,4 +172,10 @@ struct linux_target_ops the_low_target =
   NULL,                                 
   1,
   x86_64_breakpoint_at,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  0,
+  "i386:x86-64",
 };
Index: src/gdb/gdbserver/server.c
===================================================================
--- src.orig/gdb/gdbserver/server.c	2007-01-09 13:13:38.000000000 -0500
+++ src/gdb/gdbserver/server.c	2007-01-09 13:16:08.000000000 -0500
@@ -145,7 +145,7 @@ decode_xfer_read (char *buf, char **anne
    to as much of DATA/LEN as we could fit.  IS_MORE controls
    the first character of the response.  */
 static int
-write_qxfer_response (char *buf, unsigned char *data, int len, int is_more)
+write_qxfer_response (char *buf, const void *data, int len, int is_more)
 {
   int out_len;
 
@@ -192,6 +192,31 @@ handle_general_set (char *own_buf)
   own_buf[0] = 0;
 }
 
+static const char *
+get_features_xml (void)
+{
+  static int features_supported = -1;
+  static char *document;
+
+  if (features_supported == -1)
+    {
+      const char *arch = (*the_target->arch_string) ();
+
+      if (arch == NULL)
+	features_supported = 0;
+      else
+	{
+	  features_supported = 1;
+	  document = malloc (64 + strlen (arch));
+	  snprintf (document, 64 + strlen (arch),
+		    "<target><architecture>%s</architecture></target>",
+		    arch);
+	}
+    }
+
+  return document;
+}
+
 /* Handle all of the extended 'q' packets.  */
 void
 handle_query (char *own_buf, int *new_packet_len_p)
@@ -279,6 +304,45 @@ handle_query (char *own_buf, int *new_pa
       return;
     }
 
+  if (strncmp ("qXfer:features:read:", own_buf, 20) == 0)
+    {
+      CORE_ADDR ofs;
+      unsigned int len, total_len;
+      const char *document;
+      char *annex;
+
+      document = get_features_xml ();
+      if (document == NULL)
+	{
+	  own_buf[0] = '\0';
+	  return;
+	}
+
+      /* Reject any annex other than target.xml; grab the offset and
+	 length.  */
+      if (decode_xfer_read (own_buf + 20, &annex, &ofs, &len) < 0
+	  || strcmp (annex, "target.xml") != 0)
+	{
+	  strcpy (own_buf, "E00");
+	  return;
+	}
+
+      total_len = strlen (document);
+      if (len > PBUFSIZ - 2)
+	len = PBUFSIZ - 2;
+
+      if (ofs > total_len)
+	write_enn (own_buf);
+      else if (len < total_len - ofs)
+	*new_packet_len_p = write_qxfer_response (own_buf, document + ofs,
+						  len, 1);
+      else
+	*new_packet_len_p = write_qxfer_response (own_buf, document + ofs,
+						  total_len - ofs, 0);
+
+      return;
+    }
+
   /* Protocol features query.  */
   if (strncmp ("qSupported", own_buf, 10) == 0
       && (own_buf[10] == ':' || own_buf[10] == '\0'))
@@ -288,6 +352,9 @@ handle_query (char *own_buf, int *new_pa
       if (the_target->read_auxv != NULL)
 	strcat (own_buf, ";qXfer:auxv:read+");
 
+      if (get_features_xml () != NULL)
+	strcat (own_buf, ";qXfer:features:read+");
+
       return;
     }
 
Index: src/gdb/gdbserver/target.h
===================================================================
--- src.orig/gdb/gdbserver/target.h	2007-01-09 13:13:38.000000000 -0500
+++ src/gdb/gdbserver/target.h	2007-01-09 13:16:08.000000000 -0500
@@ -171,6 +171,10 @@ struct target_ops
 
   int (*get_tls_address) (struct thread_info *thread, CORE_ADDR offset,
 			  CORE_ADDR load_module, CORE_ADDR *address);
+
+  /* Return a string identifying the current architecture, or NULL if
+     this operation is not supported.  */
+  const char *(*arch_string) (void);
 };
 
 extern struct target_ops *the_target;
Index: src/gdb/doc/gdb.texinfo
===================================================================
--- src.orig/gdb/doc/gdb.texinfo	2007-01-09 09:52:58.000000000 -0500
+++ src/gdb/doc/gdb.texinfo	2007-01-09 14:40:42.000000000 -0500
@@ -159,6 +159,8 @@ Copyright (C) 1988-2006 Free Software Fo
 * Maintenance Commands::        Maintenance Commands
 * Remote Protocol::             GDB Remote Serial Protocol
 * Agent Expressions::           The GDB Agent Expression Mechanism
+* Target Descriptions::         How targets can describe themselves to
+                                @value{GDBN}
 * Copying::			GNU General Public License says
                                 how you can copy and share GDB
 * GNU Free Documentation License::  The license for this documentation
@@ -23702,6 +23704,7 @@ Reply: see @code{remote.c:remote_unpack_
 @item QPassSignals: @var{signal} @r{[};@var{signal}@r{]}@dots{}
 @cindex pass signals to inferior, remote request
 @cindex @samp{QPassSignals} packet
+@anchor{QPassSignals}
 Each listed @var{signal} should be passed directly to the inferior process. 
 Signals are numbered identically to continue packets and stop replies
 (@pxref{Stop Reply Packets}).  Each @var{signal} list item should be
@@ -23868,6 +23871,11 @@ These are the currently defined stub fea
 @tab @samp{-}
 @tab Yes
 
+@item @samp{qXfer:features:read}
+@tab No
+@tab @samp{-}
+@tab Yes
+
 @item @samp{qXfer:memory-map:read}
 @tab No
 @tab @samp{-}
@@ -23898,6 +23906,18 @@ byte in its buffer for the NUL.  If this
 The remote stub understands the @samp{qXfer:auxv:read} packet
 (@pxref{qXfer auxiliary vector read}).
 
+@item qXfer:features:read
+The remote stub understands the @samp{qXfer:features:read} packet
+(@pxref{qXfer target description read}).
+
+@item qXfer:memory-map:read
+The remote stub understands the @samp{qXfer:memory-map:read} packet
+(@pxref{qXfer memory map read}).
+
+@item QPassSignals
+The remote stub understands the @samp{QPassSignals} packet
+(@pxref{QPassSignals}).
+
 @end table
 
 @item qSymbol::
@@ -23994,9 +24014,16 @@ auxiliary vector}.  Note @var{annex} mus
 
 This packet is not probed by default; the remote stub must request it,
 by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
-@end table
 
-@table @samp
+@item qXfer:features:read:@var{annex}:@var{offset},@var{length}
+@anchor{qXfer target description read}
+Access the @dfn{target description}.  @xref{Target Descriptions}.  The
+annex specifies which XML document to access.  The main description is
+always loaded from the @samp{target.xml} annex.
+
+This packet is not probed by default; the remote stub must request it,
+by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
+
 @item qXfer:memory-map:read::@var{offset},@var{length}
 @anchor{qXfer memory map read}
 Access the target's @dfn{memory-map}.  @xref{Memory map format}.  The
@@ -25571,6 +25598,130 @@ The formal DTD for memory map format is 
 
 @include agentexpr.texi
 
+@node Target Descriptions
+@appendix Target Descriptions
+@cindex target descriptions
+
+@strong{Warning:} target descriptions are still under active development,
+and the contents and format may change between @value{GDBN} releases.
+The format is expected to stabilize in the future.
+
+One of the challenges of using @value{GDBN} to debug embedded systems
+is that there are so many minor variants of each processor
+architecture in use.  It is common practice for vendors to start with
+a standard processor core --- ARM, PowerPC, or MIPS, for example ---
+and then make changes to adapt it to a particular market niche.  Some
+architectures have hundreds of variants, available from dozens of
+vendors.  This leads to a number of problems:
+
+@itemize @bullet
+@item
+With so many different customized processors, it is difficult for
+the @value{GDBN} maintainers to keep up with the changes.
+@item
+Since individual variants may have short lifetimes or limited
+audiences, it may not be worthwhile to carry information about every
+variant in the @value{GDBN} source tree.
+@item
+When @value{GDBN} does support the architecture of the embedded system
+at hand, the task of finding the correct architecture name to give the
+@command{set architecture} command can be error-prone.
+@end itemize
+
+To address these problems, the @value{GDBN} remote protocol allows a
+target system to not only identify itself to @value{GDBN}, but to
+actually describe its own features.  This lets @value{GDBN} support
+processor variants it has never seen before --- to the extent that the
+descriptions are accurate, and that @value{GDBN} understands them.
+
+@menu
+* Retrieving Descriptions::         How descriptions are fetched from a target.
+* Target Description Format::       The contents of a target description.
+@end menu
+
+@node Retrieving Descriptions
+@section Retrieving Descriptions
+
+Target descriptions can be read from the target automatically, or
+specified by the user manually.  The default behavior is to read the
+description from the target.  @value{GDBN} retrieves it via the remote
+protocol using @samp{qXfer} requests (@pxref{General Query Packets,
+qXfer}).  The @var{annex} in the @samp{qXfer} packet will be
+@samp{target.xml}.  The contents of the @samp{target.xml} annex are an
+XML document, of the form described in @ref{Target Description
+Format}.
+
+Alternatively, you can specify a file to read for the target description.
+If a file is set, the target will not be queried.  The commands to
+specify a file are:
+
+@table @code
+@cindex set tdesc filename
+@item set tdesc filename @var{path}
+Read the target description from @var{path}.
+
+@cindex unset tdesc filename
+@item unset tdesc filename
+Do not read the XML target description from a file.  @value{GDBN}
+will use the description supplied by the current target.
+
+@cindex show tdesc filename
+@item show tdesc filename
+Show the filename to read for a target description, if any.
+@end table
+
+
+@node Target Description Format
+@section Target Description Format
+@cindex target descriptions, XML format
+
+A target description annex is an @uref{http://www.w3.org/XML/, XML}
+document which complies with the Document Type Definition provided in
+the @value{GDBN} sources in @file{gdb/features/gdb-target.dtd}.  This
+means you can use generally available tools like @command{xmllint} to
+check that your feature descriptions are well-formed and valid.
+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.
+
+Here is a simple target description:
+
+@example
+<target>
+  <architecture>i386:x86-64</architecture>
+</target>
+@end example
+
+@noindent
+This minimal description only says that the target uses
+the x86-64 architecture.
+
+A target description has the overall form:
+
+@example
+<?xml version="1.0"?>
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>@var{arch name}</architecture>
+</target>
+@end example
+
+@noindent
+The description is generally insensitive to whitespace and line
+breaks, under the usual common-sense rules.  The XML version
+declaration and document type declaration can generally be omitted
+(@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}).
+
+
 @include gpl.texi
 
 @raisesections
Index: src/gdb/NEWS
===================================================================
--- src.orig/gdb/NEWS	2007-01-09 09:52:58.000000000 -0500
+++ src/gdb/NEWS	2007-01-09 14:40:33.000000000 -0500
@@ -11,6 +11,10 @@ frequency signals (e.g. SIGALRM) via the
 
 * Support for C++ member pointers has been improved.
 
+* GDB now understands XML target descriptions, which specify the
+target's overall architecture.  GDB can read a description from
+a local file or over the remote serial protocol.
+
 * New commands
 
 set mem inaccessible-by-default
@@ -47,6 +51,12 @@ show sysroot
 
 OpenBSD/sh			sh*-*openbsd*
 
+set tdesc filename
+unset tdesc filename
+show tdesc filename
+  Use the specified local file as an XML target description, and do
+  not query the target for its built-in description.
+
 * New targets
 
 OpenBSD/sh			sh*-*-openbsd*
@@ -58,6 +68,9 @@ QPassSignals:
   Ignore the specified signals; pass them directly to the debugged program
   without stopping other threads or reporting them to GDB.
 
+qXfer:features:read:
+  Read an XML target description from the target, which describes its
+  features.
 
 *** Changes in GDB 6.6
 
Index: src/gdb/features/gdb-target.dtd
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/features/gdb-target.dtd	2007-01-09 13:16:08.000000000 -0500
@@ -0,0 +1,9 @@
+<!-- The root element of a GDB target description is <target>.  -->
+
+<!ELEMENT target	(architecture?)>
+<!ATTLIST target
+	xmlns:xi	CDATA	#FIXED "http://www.w3.org/2001/XInclude";>
+
+<!ELEMENT architecture	(#PCDATA)>
+
+


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