Create xml from target descriptions
authorAlan Hayward <alan.hayward@arm.com>
Wed, 18 Apr 2018 19:09:12 +0000 (20:09 +0100)
committerAlan Hayward <alan.hayward@arm.com>
Wed, 18 Apr 2018 19:44:39 +0000 (20:44 +0100)
Add a print_xml_feature visitor class which turns a
target description into xml. Both gdb and gdbserver can do this.

gdb/
* common/tdesc.c (print_xml_feature::visit_pre): Add xml parsing.
(print_xml_feature::visit_post): Likewise.
(print_xml_feature::visit): Likewise.
* common/tdesc.h (tdesc_get_features_xml): Use const tdesc.
(print_xml_feature): Add new class.
* regformats/regdat.sh: Null xmltarget on feature targets.
* target-descriptions.c (struct target_desc): Add xmltarget.
(maintenance_check_tdesc_xml_convert): Add unittest function.
(tdesc_get_features_xml): Add function to get xml.
(maintenance_check_xml_descriptions): Test xml generation.
* xml-tdesc.c (string_read_description_xml): Add function.
* xml-tdesc.h (string_read_description_xml): Add declaration.

gdbserver/
* gdb/gdbserver/server.c (get_features_xml): Remove cast.
* tdesc.c (void target_desc::accept): Fill in function.
(tdesc_get_features_xml): Remove old xml creation.
(print_xml_feature::visit_pre): Add xml vistor.
* tdesc.h (struct target_desc): Make xmltarget mutable.
(tdesc_get_features_xml): Remove declaration.

gdb/ChangeLog
gdb/common/tdesc.c
gdb/common/tdesc.h
gdb/gdbserver/ChangeLog
gdb/gdbserver/server.c
gdb/gdbserver/tdesc.c
gdb/gdbserver/tdesc.h
gdb/regformats/regdat.sh
gdb/target-descriptions.c
gdb/xml-tdesc.c
gdb/xml-tdesc.h

index 23a5b0d4dbe7cc9f2c43b012afbf086482afae4b..361608091f37caac6e8bf9e83681fdfe2ebc3e3d 100644 (file)
@@ -1,3 +1,18 @@
+2018-04-18  Alan Hayward  <alan.hayward@arm.com>
+
+       * common/tdesc.c (print_xml_feature::visit_pre): Add xml parsing.
+       (print_xml_feature::visit_post): Likewise.
+       (print_xml_feature::visit): Likewise.
+       * common/tdesc.h (tdesc_get_features_xml): Use const tdesc.
+       (print_xml_feature): Add new class.
+       * regformats/regdat.sh: Null xmltarget on feature targets.
+       * target-descriptions.c (struct target_desc): Add xmltarget.
+       (maintenance_check_tdesc_xml_convert): Add unittest function.
+       (tdesc_get_features_xml): Add function to get xml.
+       (maintenance_check_xml_descriptions): Test xml generation.
+       * xml-tdesc.c (string_read_description_xml): Add function.
+       * xml-tdesc.h (string_read_description_xml): Add declaration.
+
 2018-04-18  Alan Hayward  <alan.hayward@arm.com>
 
        * features/Makefile: Add feature marker to targets with new style
index b9e9ddb3fa6252403215e6e1d65ac9cda245dab2..68584a7f94f12840a9655d71edeb21b0859e9302 100644 (file)
@@ -290,3 +290,112 @@ tdesc_add_enum_value (tdesc_type_with_fields *type, int value,
                             tdesc_predefined_type (TDESC_TYPE_INT32),
                             value, -1);
 }
+
+void print_xml_feature::visit_pre (const tdesc_feature *e)
+{
+  string_appendf (*m_buffer, "<feature name=\"%s\">\n", e->name.c_str ());
+}
+
+void print_xml_feature::visit_post (const tdesc_feature *e)
+{
+  string_appendf (*m_buffer, "</feature>\n");
+}
+
+void print_xml_feature::visit (const tdesc_type_builtin *t)
+{
+  error (_("xml output is not supported for type \"%s\"."), t->name.c_str ());
+}
+
+void print_xml_feature::visit (const tdesc_type_vector *t)
+{
+  string_appendf (*m_buffer, "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>\n",
+                 t->name.c_str (), t->element_type->name.c_str (), t->count);
+}
+
+void print_xml_feature::visit (const tdesc_type_with_fields *t)
+{
+  struct tdesc_type_field *f;
+  const static char *types[] = { "struct", "union", "flags", "enum" };
+
+  gdb_assert (t->kind >= TDESC_TYPE_STRUCT && t->kind <= TDESC_TYPE_ENUM);
+
+  string_appendf (*m_buffer,
+                 "<%s id=\"%s\"", types[t->kind - TDESC_TYPE_STRUCT],
+                 t->name.c_str ());
+
+  switch (t->kind)
+    {
+    case TDESC_TYPE_STRUCT:
+    case TDESC_TYPE_FLAGS:
+      if (t->size > 0)
+       string_appendf (*m_buffer, " size=\"%d\"", t->size);
+      string_appendf (*m_buffer, ">\n");
+
+      for (const tdesc_type_field &f : t->fields)
+       {
+         string_appendf (*m_buffer, "  <field name=\"%s\" ", f.name.c_str ());
+         if (f.start == -1)
+           string_appendf (*m_buffer, "type=\"%s\"/>\n",
+                           f.type->name.c_str ());
+         else
+           string_appendf (*m_buffer, "start=\"%d\" end=\"%d\"/>\n", f.start,
+                           f.end);
+       }
+      break;
+
+    case TDESC_TYPE_ENUM:
+      string_appendf (*m_buffer, ">\n");
+      for (const tdesc_type_field &f : t->fields)
+       string_appendf (*m_buffer, "  <field name=\"%s\" start=\"%d\"/>\n",
+                       f.name.c_str (), f.start);
+      break;
+
+    case TDESC_TYPE_UNION:
+      string_appendf (*m_buffer, ">\n");
+      for (const tdesc_type_field &f : t->fields)
+       string_appendf (*m_buffer, "  <field name=\"%s\" type=\"%s\"/>\n",
+                       f.name.c_str (), f.type->name.c_str ());
+      break;
+
+    default:
+      error (_("xml output is not supported for type \"%s\"."),
+            t->name.c_str ());
+    }
+
+  string_appendf (*m_buffer, "</%s>\n", types[t->kind - TDESC_TYPE_STRUCT]);
+}
+
+void print_xml_feature::visit (const tdesc_reg *r)
+{
+  string_appendf (*m_buffer,
+                 "<reg name=\"%s\" bitsize=\"%d\" type=\"%s\" regnum=\"%ld\"",
+                 r->name.c_str (), r->bitsize, r->type.c_str (),
+                 r->target_regnum);
+
+  if (r->group.length () > 0)
+    string_appendf (*m_buffer, " group=\"%s\"", r->group.c_str ());
+
+  if (r->save_restore == 0)
+    string_appendf (*m_buffer, " save-restore=\"no\"");
+
+  string_appendf (*m_buffer, "/>\n");
+}
+
+void print_xml_feature::visit_pre (const target_desc *e)
+{
+#ifndef IN_PROCESS_AGENT
+  string_appendf (*m_buffer, "<?xml version=\"1.0\"?>\n");
+  string_appendf (*m_buffer, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">\n");
+  string_appendf (*m_buffer, "<target>\n<architecture>%s</architecture>\n",
+                 tdesc_architecture_name (e));
+
+  const char *osabi = tdesc_osabi_name (e);
+  if (osabi != nullptr)
+    string_appendf (*m_buffer, "<osabi>%s</osabi>", osabi);
+#endif
+}
+
+void print_xml_feature::visit_post (const target_desc *e)
+{
+  string_appendf (*m_buffer, "</target>\n");
+}
index 8b826ec436c519113ec242afcb43ad67183a6042..6868bf47d9af60fa44099b08bca994b49bfebb05 100644 (file)
@@ -380,4 +380,30 @@ void tdesc_create_reg (struct tdesc_feature *feature, const char *name,
                       int regnum, int save_restore, const char *group,
                       int bitsize, const char *type);
 
+/* Return the tdesc in string XML format.  */
+
+const char *tdesc_get_features_xml (const target_desc *tdesc);
+
+/* Print target description as xml.  */
+
+class print_xml_feature : public tdesc_element_visitor
+{
+public:
+  print_xml_feature (std::string *buffer_)
+    : m_buffer (buffer_)
+  {}
+
+  void visit_pre (const target_desc *e) override;
+  void visit_post (const target_desc *e) override;
+  void visit_pre (const tdesc_feature *e) override;
+  void visit_post (const tdesc_feature *e) override;
+  void visit (const tdesc_type_builtin *type) override;
+  void visit (const tdesc_type_vector *type) override;
+  void visit (const tdesc_type_with_fields *type) override;
+  void visit (const tdesc_reg *reg) override;
+
+private:
+  std::string *m_buffer;
+};
+
 #endif /* ARCH_TDESC_H */
index 96dc83cc7ee28f0545384678883222bb181de452..43fa090b1ae9ed7ec22d5cd5497395ed97501a95 100644 (file)
@@ -1,3 +1,12 @@
+2018-04-18  Alan Hayward  <alan.hayward@arm.com>
+
+       * server.c (get_features_xml): Remove cast.
+       * tdesc.c (void target_desc::accept): Fill in function.
+       (tdesc_get_features_xml): Remove old xml creation.
+       (print_xml_feature::visit_pre): Add xml vistor.
+       * tdesc.h (struct target_desc): Make xmltarget mutable.
+       (tdesc_get_features_xml): Remove declaration.
+
 2018-04-18  Alan Hayward  <alan.hayward@arm.com>
 
        * tdesc.c (tdesc_architecture_name): Add new function.
index 64c72bdd58c3cc505832d488efe07c36bbeaf711..5027df5e10e59713024093981c198dd34d52db65 100644 (file)
@@ -940,7 +940,7 @@ get_features_xml (const char *annex)
 
   if (strcmp (annex, "target.xml") == 0)
     {
-      const char *ret = tdesc_get_features_xml ((target_desc*) desc);
+      const char *ret = tdesc_get_features_xml (desc);
 
       if (*ret == '@')
        return ret + 1;
index 7603a90a59cd7650ceaf3fe1af70c7095d2e00cc..126589f3e3e92e2500183e6a8988318d7591cfdb 100644 (file)
@@ -47,6 +47,18 @@ bool target_desc::operator== (const target_desc &other) const
 
 #endif
 
+void target_desc::accept (tdesc_element_visitor &v) const
+{
+#ifndef IN_PROCESS_AGENT
+  v.visit_pre (this);
+
+  for (const tdesc_feature_up &feature : features)
+    feature->accept (v);
+
+  v.visit_post (this);
+#endif
+}
+
 void
 init_target_desc (struct target_desc *tdesc)
 {
@@ -138,11 +150,10 @@ set_tdesc_osabi (struct target_desc *target_desc, const char *name)
   target_desc->osabi = xstrdup (name);
 }
 
-/* Return a string which is of XML format, including XML target
-   description to be sent to GDB.  */
+/* See common/tdesc.h.  */
 
 const char *
-tdesc_get_features_xml (target_desc *tdesc)
+tdesc_get_features_xml (const target_desc *tdesc)
 {
   /* Either .xmltarget or .features is not NULL.  */
   gdb_assert (tdesc->xmltarget != NULL
@@ -151,31 +162,9 @@ tdesc_get_features_xml (target_desc *tdesc)
 
   if (tdesc->xmltarget == NULL)
     {
-      std::string buffer ("@<?xml version=\"1.0\"?>");
-
-      buffer += "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">";
-      buffer += "<target>";
-      buffer += "<architecture>";
-      buffer += tdesc_architecture_name (tdesc);
-      buffer += "</architecture>";
-
-      const char *osabi = tdesc_osabi_name (tdesc);
-      if (osabi != nullptr)
-       {
-         buffer += "<osabi>";
-         buffer += osabi;
-         buffer += "</osabi>";
-       }
-
-      for (const tdesc_feature_up &feature : tdesc->features)
-       {
-         buffer += "<xi:include href=\"";
-         buffer += feature->name;
-         buffer += "\"/>";
-       }
-
-      buffer += "</target>";
-
+      std::string buffer ("@");
+      print_xml_feature v (&buffer);
+      tdesc->accept (v);
       tdesc->xmltarget = xstrdup (buffer.c_str ());
     }
 
index 197fb5912753af3d84ff568b8689af0a40c41265..61a3e4ecdd2ce5fbbca2e0f196bb3243c7d55b47 100644 (file)
@@ -27,7 +27,7 @@
 /* A target description.  Inherit from tdesc_feature so that target_desc
    can be used as tdesc_feature.  */
 
-struct target_desc
+struct target_desc : tdesc_element
 {
   /* A vector of elements of register definitions that
      describe the inferior's register set.  */
@@ -49,9 +49,9 @@ struct target_desc
      verbatim XML code (prefixed with a '@') or else the name of the
      actual XML file to be used in place of "target.xml".
 
-     It can be NULL, then, its content is got from the following three
-     fields features, arch, and osabi in tdesc_get_features_xml.  */
-  const char *xmltarget = NULL;
+     If NULL then its content will be generated by parsing the target
+     description into xml.  */
+  mutable const char *xmltarget = NULL;
 
   /* The value of <architecture> element in the XML, replying GDB.  */
   const char *arch = NULL;
@@ -73,6 +73,8 @@ public:
     return !(*this == other);
   }
 #endif
+
+  void accept (tdesc_element_visitor &v) const override;
 };
 
 /* Copy target description SRC to DEST.  */
@@ -89,8 +91,4 @@ void init_target_desc (struct target_desc *tdesc);
 
 const struct target_desc *current_target_desc (void);
 
-#ifndef IN_PROCESS_AGENT
-const char *tdesc_get_features_xml (struct target_desc *tdesc);
-#endif
-
 #endif /* TDESC_H */
index 18108d77ebbad4b692b764c8cfb8bfa6109f8347..8f546fe276961e87d29fcc08000f43def93b7de6 100755 (executable)
@@ -163,7 +163,9 @@ done
 
 echo
 echo "static const char *expedite_regs_${name}[] = { \"`echo ${expedite} | sed 's/,/", "/g'`\", 0 };"
-if test "${xmltarget}" = x; then
+if test "${feature}" != x; then
+  echo "static const char *xmltarget_${name} = 0;"
+elif test "${xmltarget}" = x; then
   if test "${xmlarch}" = x && test "${xmlosabi}" = x; then
     echo "static const char *xmltarget_${name} = 0;"
   else
index da2c1ce34531c1b23281c42f2dacbc85444ef544..c0f85112b1ab260f67e5329bae22dac2e1304d7f 100644 (file)
@@ -333,6 +333,9 @@ struct target_desc : tdesc_element
   /* The features associated with this target.  */
   std::vector<tdesc_feature_up> features;
 
+  /* Used to cache the generated xml version of the target description.  */
+  mutable char *xmltarget = nullptr;
+
   void accept (tdesc_element_visitor &v) const override
   {
     v.visit_pre (this);
@@ -1667,6 +1670,21 @@ private:
   int m_next_regnum = 0;
 };
 
+/* See common/tdesc.h.  */
+
+const char *
+tdesc_get_features_xml (const target_desc *tdesc)
+{
+  if (tdesc->xmltarget == nullptr)
+    {
+      std::string buffer ("@");
+      print_xml_feature v (&buffer);
+      tdesc->accept (v);
+      tdesc->xmltarget = xstrdup (buffer.c_str ());
+    }
+  return tdesc->xmltarget;
+}
+
 static void
 maint_print_c_tdesc_cmd (const char *args, int from_tty)
 {
@@ -1739,6 +1757,39 @@ record_xml_tdesc (const char *xml_file, const struct target_desc *tdesc)
 
 }
 
+/* Test the convesion process of a target description to/from xml: Take a target
+   description TDESC, convert to xml, back to a description, and confirm the new
+   tdesc is identical to the original.  */
+static bool
+maintenance_check_tdesc_xml_convert (const target_desc *tdesc, const char *name)
+{
+  const char *xml = tdesc_get_features_xml (tdesc);
+
+  if (xml == nullptr || *xml != '@')
+    {
+      printf_filtered (_("Could not convert description for %s to xml.\n"),
+                      name);
+      return false;
+    }
+
+  const target_desc *tdesc_trans = string_read_description_xml (xml + 1);
+
+  if (tdesc_trans == nullptr)
+    {
+      printf_filtered (_("Could not convert description for %s from xml.\n"),
+                      name);
+      return false;
+    }
+  else if (*tdesc != *tdesc_trans)
+    {
+      printf_filtered (_("Converted description for %s does not match.\n"),
+                      name);
+      return false;
+    }
+  return true;
+}
+
+
 /* Check that the target descriptions created dynamically by
    architecture-specific code equal the descriptions created from XML files
    found in the specified directory DIR.  */
@@ -1760,6 +1811,12 @@ maintenance_check_xml_descriptions (const char *dir, int from_tty)
        = file_read_description_xml (tdesc_xml.data ());
 
       if (tdesc == NULL || *tdesc != *e.second)
+       {
+         printf_filtered ( _("Descriptions for %s do not match.\n"), e.first);
+         failed++;
+       }
+      else if (!maintenance_check_tdesc_xml_convert (tdesc, e.first)
+              || !maintenance_check_tdesc_xml_convert (e.second, e.first))
        failed++;
     }
   printf_filtered (_("Tested %lu XML files, %d failed\n"),
index 1c3409d53b684250d9192a43339ff75459abc695..87c6be428f67840dc4b9d2eb99f00f6919524d8d 100644 (file)
@@ -752,3 +752,15 @@ target_fetch_description_xml (struct target_ops *ops)
   return output;
 #endif
 }
+
+/* See xml-tdesc.h.  */
+
+const struct target_desc *
+string_read_description_xml (const char *xml)
+{
+  return tdesc_parse_xml (xml, [] (const char *href, void *baton)
+    {
+      error (_("xincludes are unsupported with this method"));
+      return gdb::optional<gdb::char_vector> ();
+    }, nullptr);
+}
index 8f0679707ad0f1e04d803f955f7fb98b4cc0c8c8..1e3caba745ead8922b3a0271cb9f932214e42564 100644 (file)
@@ -44,5 +44,10 @@ const struct target_desc *target_read_description_xml (struct target_ops *);
    otherwise.  */
 gdb::optional<std::string> target_fetch_description_xml (target_ops *ops);
 
+/* Take an xml string, parse it, and return the parsed description.  Does not
+   handle a string containing includes.  */
+
+const struct target_desc *string_read_description_xml (const char *xml);
+
 #endif /* XML_TDESC_H */