Dynamically composite xml in reply to GDB
[deliverable/binutils-gdb.git] / gdb / target-descriptions.c
index 9484f01c9a420e3164f5d471f30f0d2ad4cab269..6135e0d99eea359bf6ccd2e7c541e58c57baed7b 100644 (file)
 #include "gdb_obstack.h"
 #include "hashtab.h"
 #include "inferior.h"
+#include <algorithm>
+#include "completer.h"
+#include "readline/tilde.h" /* tilde_expand */
+
+/* The interface to visit different elements of target description.  */
+
+class tdesc_element_visitor
+{
+public:
+  virtual void visit_pre (const target_desc *e) = 0;
+  virtual void visit_post (const target_desc *e) = 0;
+
+  virtual void visit_pre (const tdesc_feature *e) = 0;
+  virtual void visit_post (const tdesc_feature *e) = 0;
+
+  virtual void visit (const tdesc_type *e) = 0;
+  virtual void visit (const tdesc_reg *e) = 0;
+};
+
+class tdesc_element
+{
+public:
+  virtual void accept (tdesc_element_visitor &v) const = 0;
+};
 
 /* Types.  */
 
@@ -46,7 +70,7 @@ DEF_VEC_O(property_s);
 
 /* An individual register from a target description.  */
 
-typedef struct tdesc_reg
+typedef struct tdesc_reg : tdesc_element
 {
   tdesc_reg (struct tdesc_feature *feature, const char *name_,
             int regnum, int save_restore_, const char *group_,
@@ -62,7 +86,7 @@ typedef struct tdesc_reg
     tdesc_type = tdesc_named_type (feature, type);
   }
 
-  ~tdesc_reg ()
+  virtual ~tdesc_reg ()
   {
     xfree (name);
     xfree (type);
@@ -106,6 +130,26 @@ typedef struct tdesc_reg
 
   /* The target-described type corresponding to TYPE, if found.  */
   struct tdesc_type *tdesc_type;
+
+  void accept (tdesc_element_visitor &v) const override
+  {
+    v.visit (this);
+  }
+
+  bool operator== (const tdesc_reg &other) const
+  {
+    return (streq (name, other.name)
+           && target_regnum == other.target_regnum
+           && save_restore == other.save_restore
+           && bitsize == other.bitsize
+           && (group == other.group || streq (group, other.group))
+           && streq (type, other.type));
+  }
+
+  bool operator!= (const tdesc_reg &other) const
+  {
+    return !(*this == other);
+  }
 } *tdesc_reg_p;
 DEF_VEC_P(tdesc_reg_p);
 
@@ -151,7 +195,7 @@ enum tdesc_type_kind
   TDESC_TYPE_ENUM
 };
 
-typedef struct tdesc_type
+typedef struct tdesc_type : tdesc_element
 {
   tdesc_type (const char *name_, enum tdesc_type_kind kind_)
     : name (xstrdup (name_)), kind (kind_)
@@ -159,7 +203,7 @@ typedef struct tdesc_type
     memset (&u, 0, sizeof (u));
   }
 
-  ~tdesc_type ()
+  virtual ~tdesc_type ()
   {
     switch (kind)
       {
@@ -214,19 +258,34 @@ typedef struct tdesc_type
       int size;
     } u;
   } u;
+
+  void accept (tdesc_element_visitor &v) const override
+  {
+    v.visit (this);
+  }
+
+  bool operator== (const tdesc_type &other) const
+  {
+    return (streq (name, other.name) && kind == other.kind);
+  }
+
+  bool operator!= (const tdesc_type &other) const
+  {
+    return !(*this == other);
+  }
 } *tdesc_type_p;
 DEF_VEC_P(tdesc_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
+typedef struct tdesc_feature : tdesc_element
 {
   tdesc_feature (const char *name_)
     : name (xstrdup (name_))
   {}
 
-  ~tdesc_feature ()
+  virtual ~tdesc_feature ()
   {
     struct tdesc_reg *reg;
     struct tdesc_type *type;
@@ -256,6 +315,76 @@ typedef struct tdesc_feature
 
   /* The types associated with this feature.  */
   VEC(tdesc_type_p) *types = NULL;
+
+  void accept (tdesc_element_visitor &v) const override
+  {
+    v.visit_pre (this);
+
+    struct tdesc_type *type;
+
+    for (int ix = 0;
+        VEC_iterate (tdesc_type_p, types, ix, type);
+        ix++)
+      type->accept (v);
+
+    struct tdesc_reg *reg;
+
+    for (int ix = 0;
+        VEC_iterate (tdesc_reg_p, registers, ix, reg);
+        ix++)
+      reg->accept (v);
+
+
+    v.visit_post (this);
+  }
+
+  bool operator== (const tdesc_feature &other) const
+  {
+    if (strcmp (name, other.name) != 0)
+      return false;
+
+    if (VEC_length (tdesc_reg_p, registers)
+       != VEC_length (tdesc_reg_p, other.registers))
+      return false;
+
+    struct tdesc_reg *reg;
+
+    for (int ix = 0;
+        VEC_iterate (tdesc_reg_p, registers, ix, reg);
+        ix++)
+      {
+       tdesc_reg *reg2
+         = VEC_index (tdesc_reg_p, other.registers, ix);
+
+       if (reg != reg2 && *reg != *reg2)
+         return false;
+      }
+
+    if (VEC_length (tdesc_type_p, types)
+       != VEC_length (tdesc_type_p, other.types))
+      return false;
+
+    tdesc_type *type;
+
+    for (int ix = 0;
+        VEC_iterate (tdesc_type_p, types, ix, type);
+        ix++)
+      {
+       tdesc_type *type2
+         = VEC_index (tdesc_type_p, other.types, ix);
+
+       if (type != type2 && *type != *type2)
+         return false;
+      }
+
+    return true;
+  }
+
+  bool operator!= (const tdesc_feature &other) const
+  {
+    return !(*this == other);
+  }
+
 } *tdesc_feature_p;
 DEF_VEC_P(tdesc_feature_p);
 
@@ -265,12 +394,12 @@ DEF_VEC_P(arch_p);
 
 /* A target description.  */
 
-struct target_desc
+struct target_desc : tdesc_element
 {
   target_desc ()
   {}
 
-  ~target_desc ()
+  virtual ~target_desc ()
   {
     struct tdesc_feature *feature;
     struct property *prop;
@@ -312,6 +441,53 @@ struct target_desc
 
   /* The features associated with this target.  */
   VEC(tdesc_feature_p) *features = NULL;
+
+  void accept (tdesc_element_visitor &v) const override
+  {
+    v.visit_pre (this);
+
+    struct tdesc_feature *feature;
+
+    for (int ix = 0;
+        VEC_iterate (tdesc_feature_p, features, ix, feature);
+        ix++)
+      feature->accept (v);
+
+    v.visit_post (this);
+  }
+
+  bool operator== (const target_desc &other) const
+  {
+    if (arch != other.arch)
+      return false;
+
+    if (osabi != other.osabi)
+      return false;
+
+    if (VEC_length (tdesc_feature_p, features)
+       != VEC_length (tdesc_feature_p, other.features))
+      return false;
+
+    struct tdesc_feature *feature;
+
+    for (int ix = 0;
+        VEC_iterate (tdesc_feature_p, features, ix, feature);
+        ix++)
+      {
+       struct tdesc_feature *feature2
+         = VEC_index (tdesc_feature_p, other.features, ix);
+
+       if (feature != feature2 && *feature != *feature2)
+         return false;
+      }
+
+    return true;
+  }
+
+  bool operator!= (const target_desc &other) const
+  {
+    return !(*this == other);
+  }
 };
 
 /* Per-architecture data associated with a target description.  The
@@ -670,8 +846,7 @@ tdesc_predefined_type (enum tdesc_type_kind kind)
   gdb_assert_not_reached ("bad predefined tdesc type");
 }
 
-/* Return the type associated with ID in the context of FEATURE, or
-   NULL if none.  */
+/* See arch/tdesc.h.  */
 
 struct tdesc_type *
 tdesc_named_type (const struct tdesc_feature *feature, const char *id)
@@ -1390,6 +1565,8 @@ tdesc_use_registers (struct gdbarch *gdbarch,
 }
 \f
 
+/* See arch/tdesc.h.  */
+
 void
 tdesc_create_reg (struct tdesc_feature *feature, const char *name,
                  int regnum, int save_restore, const char *group,
@@ -1401,6 +1578,8 @@ tdesc_create_reg (struct tdesc_feature *feature, const char *name,
   VEC_safe_push (tdesc_reg_p, feature->registers, reg);
 }
 
+/* See arch/tdesc.h.  */
+
 struct tdesc_type *
 tdesc_create_vector (struct tdesc_feature *feature, const char *name,
                     struct tdesc_type *field_type, int count)
@@ -1414,6 +1593,8 @@ tdesc_create_vector (struct tdesc_feature *feature, const char *name,
   return type;
 }
 
+/* See arch/tdesc.h.  */
+
 struct tdesc_type *
 tdesc_create_struct (struct tdesc_feature *feature, const char *name)
 {
@@ -1423,9 +1604,7 @@ tdesc_create_struct (struct tdesc_feature *feature, const char *name)
   return type;
 }
 
-/* Set the total length of TYPE.  Structs which contain bitfields may
-   omit the reserved bits, so the end of the last field may not
-   suffice.  */
+/* See arch/tdesc.h.  */
 
 void
 tdesc_set_struct_size (struct tdesc_type *type, int size)
@@ -1435,6 +1614,8 @@ tdesc_set_struct_size (struct tdesc_type *type, int size)
   type->u.u.size = size;
 }
 
+/* See arch/tdesc.h.  */
+
 struct tdesc_type *
 tdesc_create_union (struct tdesc_feature *feature, const char *name)
 {
@@ -1444,6 +1625,8 @@ tdesc_create_union (struct tdesc_feature *feature, const char *name)
   return type;
 }
 
+/* See arch/tdesc.h.  */
+
 struct tdesc_type *
 tdesc_create_flags (struct tdesc_feature *feature, const char *name,
                    int size)
@@ -1472,7 +1655,7 @@ tdesc_create_enum (struct tdesc_feature *feature, const char *name,
   return type;
 }
 
-/* Add a new field to TYPE.  */
+/* See arch/tdesc.h.  */
 
 void
 tdesc_add_field (struct tdesc_type *type, const char *field_name,
@@ -1493,8 +1676,6 @@ tdesc_add_field (struct tdesc_type *type, const char *field_name,
   VEC_safe_push (tdesc_type_field, type->u.u.fields, &f);
 }
 
-/* Add a new typed bitfield to TYPE.  */
-
 void
 tdesc_add_typed_bitfield (struct tdesc_type *type, const char *field_name,
                          int start, int end, struct tdesc_type *field_type)
@@ -1513,9 +1694,7 @@ tdesc_add_typed_bitfield (struct tdesc_type *type, const char *field_name,
   VEC_safe_push (tdesc_type_field, type->u.u.fields, &f);
 }
 
-/* Add a new untyped bitfield to TYPE.
-   Untyped bitfields become either uint32 or uint64 depending on the size
-   of the underlying type.  */
+/* See arch/tdesc.h.  */
 
 void
 tdesc_add_bitfield (struct tdesc_type *type, const char *field_name,
@@ -1533,8 +1712,7 @@ tdesc_add_bitfield (struct tdesc_type *type, const char *field_name,
   tdesc_add_typed_bitfield (type, field_name, start, end, field_type);
 }
 
-/* A flag is just a typed(bool) single-bit bitfield.
-   This function is kept to minimize changes in generated files.  */
+/* See arch/tdesc.h.  */
 
 void
 tdesc_add_flag (struct tdesc_type *type, int start,
@@ -1569,8 +1747,11 @@ tdesc_add_enum_value (struct tdesc_type *type, int value,
   VEC_safe_push (tdesc_type_field, type->u.u.fields, &f);
 }
 
+/* See arch/tdesc.h.  */
+
 struct tdesc_feature *
-tdesc_create_feature (struct target_desc *tdesc, const char *name)
+tdesc_create_feature (struct target_desc *tdesc, const char *name,
+                     const char *xml)
 {
   struct tdesc_feature *new_feature = new tdesc_feature (name);
 
@@ -1714,279 +1895,479 @@ unset_tdesc_filename_cmd (char *args, int from_tty)
   target_find_description ();
 }
 
-static void
-maint_print_c_tdesc_cmd (char *args, int from_tty)
+/* Print target description in C.  */
+
+class print_c_tdesc : public tdesc_element_visitor
 {
-  const struct target_desc *tdesc;
-  const struct bfd_arch_info *compatible;
-  const char *filename, *inp;
-  char *function, *outp;
-  struct property *prop;
-  struct tdesc_feature *feature;
-  struct tdesc_reg *reg;
-  struct tdesc_type *type;
-  struct tdesc_type_field *f;
-  int ix, ix2, ix3;
-  int printed_field_type = 0;
-
-  /* Use the global target-supplied description, not the current
-     architecture's.  This lets a GDB for one architecture generate C
-     for another architecture's description, even though the gdbarch
-     initialization code will reject the new description.  */
-  tdesc = current_target_desc;
-  if (tdesc == NULL)
-    error (_("There is no target description to print."));
+public:
+  print_c_tdesc (std::string &filename_after_features)
+    : m_filename_after_features (filename_after_features)
+  {
+    const char *inp;
+    char *outp;
+    const char *filename = lbasename (m_filename_after_features.c_str ());
 
-  if (target_description_filename == NULL)
-    error (_("The current target description did not come from an XML file."));
+    m_function = (char *) xmalloc (strlen (filename) + 1);
+    for (inp = filename, outp = m_function; *inp != '\0'; inp++)
+      if (*inp == '.')
+       break;
+      else if (*inp == '-')
+       *outp++ = '_';
+      else
+       *outp++ = *inp;
+    *outp = '\0';
 
-  filename = lbasename (target_description_filename);
-  function = (char *) alloca (strlen (filename) + 1);
-  for (inp = filename, outp = function; *inp != '\0'; inp++)
-    if (*inp == '.')
-      break;
-    else if (*inp == '-')
-      *outp++ = '_';
-    else
-      *outp++ = *inp;
-  *outp = '\0';
-
-  /* Standard boilerplate.  */
-  printf_unfiltered ("/* THIS FILE IS GENERATED.  "
-                    "-*- buffer-read-only: t -*- vi"
-                    ":set ro:\n");
-  printf_unfiltered ("  Original: %s */\n\n", filename);
-  printf_unfiltered ("#include \"defs.h\"\n");
-  printf_unfiltered ("#include \"osabi.h\"\n");
-  printf_unfiltered ("#include \"target-descriptions.h\"\n");
-  printf_unfiltered ("\n");
-
-  printf_unfiltered ("struct target_desc *tdesc_%s;\n", function);
-  printf_unfiltered ("static void\n");
-  printf_unfiltered ("initialize_tdesc_%s (void)\n", function);
-  printf_unfiltered ("{\n");
-  printf_unfiltered
-    ("  struct target_desc *result = allocate_target_description ();\n");
-  printf_unfiltered ("  struct tdesc_feature *feature;\n");
-
-  /* Now we do some "filtering" in order to know which variables to
-     declare.  This is needed because otherwise we would declare unused
-     variables `field_type' and `type'.  */
-  for (ix = 0;
-       VEC_iterate (tdesc_feature_p, tdesc->features, ix, feature);
-       ix++)
-    {
-      int printed_desc_type = 0;
+    /* Standard boilerplate.  */
+    printf_unfiltered ("/* THIS FILE IS GENERATED.  "
+                      "-*- buffer-read-only: t -*- vi"
+                      ":set ro:\n");
+  }
 
-      for (ix2 = 0;
-          VEC_iterate (tdesc_type_p, feature->types, ix2, type);
-          ix2++)
-       {
-         if (!printed_field_type)
-           {
-             printf_unfiltered ("  struct tdesc_type *field_type;\n");
-             printed_field_type = 1;
-           }
+  ~print_c_tdesc ()
+  {
+    xfree (m_function);
+  }
 
-         if ((type->kind == TDESC_TYPE_UNION
-              || type->kind == TDESC_TYPE_STRUCT
-              || type->kind == TDESC_TYPE_FLAGS
-              || type->kind == TDESC_TYPE_ENUM)
-             && VEC_length (tdesc_type_field, type->u.u.fields) > 0)
-           {
-             printf_unfiltered ("  struct tdesc_type *type;\n");
-             printed_desc_type = 1;
-             break;
-           }
-       }
+  void visit_pre (const target_desc *e) override
+  {
+    printf_unfiltered ("  Original: %s */\n\n",
+                      lbasename (m_filename_after_features.c_str ()));
+
+    printf_unfiltered ("#include \"defs.h\"\n");
+    printf_unfiltered ("#include \"osabi.h\"\n");
+    printf_unfiltered ("#include \"target-descriptions.h\"\n");
+    printf_unfiltered ("\n");
+
+    printf_unfiltered ("struct target_desc *tdesc_%s;\n", m_function);
+    printf_unfiltered ("static void\n");
+    printf_unfiltered ("initialize_tdesc_%s (void)\n", m_function);
+    printf_unfiltered ("{\n");
+    printf_unfiltered
+      ("  struct target_desc *result = allocate_target_description ();\n");
+
+    if (tdesc_architecture (e) != NULL)
+      {
+       printf_unfiltered
+         ("  set_tdesc_architecture (result, bfd_scan_arch (\"%s\"));\n",
+          tdesc_architecture (e)->printable_name);
+       printf_unfiltered ("\n");
+      }
+    if (tdesc_osabi (e) > GDB_OSABI_UNKNOWN
+       && tdesc_osabi (e) < GDB_OSABI_INVALID)
+      {
+       printf_unfiltered
+         ("  set_tdesc_osabi (result, osabi_from_tdesc_string (\"%s\"));\n",
+          gdbarch_osabi_name (tdesc_osabi (e)));
+       printf_unfiltered ("\n");
+      }
 
-      if (printed_desc_type)
+    int ix;
+    const struct bfd_arch_info *compatible;
+    struct property *prop;
+
+    for (ix = 0; VEC_iterate (arch_p, e->compatible, ix, compatible);
+        ix++)
+      {
+       printf_unfiltered
+         ("  tdesc_add_compatible (result, bfd_scan_arch (\"%s\"));\n",
+          compatible->printable_name);
+      }
+
+    if (ix)
+      printf_unfiltered ("\n");
+
+    for (ix = 0; VEC_iterate (property_s, e->properties, ix, prop);
+        ix++)
+      {
+       printf_unfiltered ("  set_tdesc_property (result, \"%s\", \"%s\");\n",
+                          prop->key, prop->value);
+      }
+    printf_unfiltered ("  struct tdesc_feature *feature;\n");
+  }
+
+  void visit_pre (const tdesc_feature *e) override
+  {
+    printf_unfiltered ("\n  feature = tdesc_create_feature (result, \"%s\");\n",
+                      e->name);
+  }
+
+  void visit_post (const tdesc_feature *e) override
+  {}
+
+  void visit_post (const target_desc *e) override
+  {
+    printf_unfiltered ("\n  tdesc_%s = result;\n", m_function);
+    printf_unfiltered ("}\n");
+  }
+
+  void visit (const tdesc_type *type) override
+  {
+    struct tdesc_type_field *f;
+
+    /* Now we do some "filtering" in order to know which variables to
+       declare.  This is needed because otherwise we would declare unused
+       variables `field_type' and `type'.  */
+    if (!m_printed_field_type)
+      {
+       printf_unfiltered ("  struct tdesc_type *field_type;\n");
+       m_printed_field_type = true;
+      }
+
+    if ((type->kind == TDESC_TYPE_UNION
+        || type->kind == TDESC_TYPE_STRUCT
+        || type->kind == TDESC_TYPE_FLAGS
+        || type->kind == TDESC_TYPE_ENUM)
+       && VEC_length (tdesc_type_field, type->u.u.fields) > 0
+       && !m_printed_type)
+      {
+       printf_unfiltered ("  struct tdesc_type *type;\n");
+       m_printed_type = true;
+      }
+
+    switch (type->kind)
+      {
+      case TDESC_TYPE_VECTOR:
+       printf_unfiltered
+         ("  field_type = tdesc_named_type (feature, \"%s\");\n",
+          type->u.v.type->name);
+       printf_unfiltered
+         ("  tdesc_create_vector (feature, \"%s\", field_type, %d);\n",
+          type->name, type->u.v.count);
        break;
-    }
+      case TDESC_TYPE_STRUCT:
+      case TDESC_TYPE_FLAGS:
+       if (type->kind == TDESC_TYPE_STRUCT)
+         {
+           printf_unfiltered
+             ("  type = tdesc_create_struct (feature, \"%s\");\n",
+              type->name);
+           if (type->u.u.size != 0)
+             printf_unfiltered
+               ("  tdesc_set_struct_size (type, %d);\n",
+                type->u.u.size);
+         }
+       else
+         {
+           printf_unfiltered
+             ("  type = tdesc_create_flags (feature, \"%s\", %d);\n",
+              type->name, type->u.u.size);
+         }
+       for (int ix3 = 0;
+            VEC_iterate (tdesc_type_field, type->u.u.fields, ix3, f);
+            ix3++)
+         {
+           const char *type_name;
+
+           gdb_assert (f->type != NULL);
+           type_name = f->type->name;
+
+           /* To minimize changes to generated files, don't emit type
+              info for fields that have defaulted types.  */
+           if (f->start != -1)
+             {
+               gdb_assert (f->end != -1);
+               if (f->type->kind == TDESC_TYPE_BOOL)
+                 {
+                   gdb_assert (f->start == f->end);
+                   printf_unfiltered
+                     ("  tdesc_add_flag (type, %d, \"%s\");\n",
+                      f->start, f->name);
+                 }
+               else if ((type->u.u.size == 4
+                         && f->type->kind == TDESC_TYPE_UINT32)
+                        || (type->u.u.size == 8
+                            && f->type->kind == TDESC_TYPE_UINT64))
+                 {
+                   printf_unfiltered
+                     ("  tdesc_add_bitfield (type, \"%s\", %d, %d);\n",
+                      f->name, f->start, f->end);
+                 }
+               else
+                 {
+                   printf_unfiltered
+                     ("  field_type = tdesc_named_type (feature,"
+                      " \"%s\");\n",
+                      type_name);
+                   printf_unfiltered
+                     ("  tdesc_add_typed_bitfield (type, \"%s\","
+                      " %d, %d, field_type);\n",
+                      f->name, f->start, f->end);
+                 }
+             }
+           else /* Not a bitfield.  */
+             {
+               gdb_assert (f->end == -1);
+               gdb_assert (type->kind == TDESC_TYPE_STRUCT);
+               printf_unfiltered
+                 ("  field_type = tdesc_named_type (feature,"
+                  " \"%s\");\n",
+                  type_name);
+               printf_unfiltered
+                 ("  tdesc_add_field (type, \"%s\", field_type);\n",
+                  f->name);
+             }
+         }
+       break;
+      case TDESC_TYPE_UNION:
+       printf_unfiltered
+         ("  type = tdesc_create_union (feature, \"%s\");\n",
+          type->name);
+       for (int ix3 = 0;
+            VEC_iterate (tdesc_type_field, type->u.u.fields, ix3, f);
+            ix3++)
+         {
+           printf_unfiltered
+             ("  field_type = tdesc_named_type (feature, \"%s\");\n",
+              f->type->name);
+           printf_unfiltered
+             ("  tdesc_add_field (type, \"%s\", field_type);\n",
+              f->name);
+         }
+       break;
+      case TDESC_TYPE_ENUM:
+       printf_unfiltered
+         ("  type = tdesc_create_enum (feature, \"%s\", %d);\n",
+          type->name, type->u.u.size);
+       for (int ix3 = 0;
+            VEC_iterate (tdesc_type_field, type->u.u.fields, ix3, f);
+            ix3++)
+         printf_unfiltered
+           ("  tdesc_add_enum_value (type, %d, \"%s\");\n",
+            f->start, f->name);
+       break;
+      default:
+       error (_("C output is not supported type \"%s\"."), type->name);
+      }
+    printf_unfiltered ("\n");
+  }
+
+  void visit (const tdesc_reg *reg) override
+  {
+    printf_unfiltered ("  tdesc_create_reg (feature, \"%s\", %ld, %d, ",
+                      reg->name, reg->target_regnum, reg->save_restore);
+    if (reg->group)
+      printf_unfiltered ("\"%s\", ", reg->group);
+    else
+      printf_unfiltered ("NULL, ");
+    printf_unfiltered ("%d, \"%s\");\n", reg->bitsize, reg->type);
+  }
+
+protected:
+  std::string m_filename_after_features;
+
+private:
+  char *m_function;
+  bool m_printed_field_type = false;
+  bool m_printed_type = false;
+};
+
+/* Print target description feature in C.  */
+
+class print_c_feature : public print_c_tdesc
+{
+public:
+  print_c_feature (std::string &file)
+    : print_c_tdesc (file)
+  {
+    /* Trim ".tmp".  */
+    auto const pos = m_filename_after_features.find_last_of ('.');
+
+    m_filename_after_features = m_filename_after_features.substr (0, pos);
+  }
+
+  void visit_pre (const target_desc *e) override
+  {
+    printf_unfiltered ("  Original: %s */\n\n",
+                      lbasename (m_filename_after_features.c_str ()));
+
+    printf_unfiltered ("#include \"arch/tdesc.h\"\n");
+    printf_unfiltered ("\n");
+  }
+
+  void visit_post (const target_desc *e) override
+  {}
+
+  void visit_pre (const tdesc_feature *e) override
+  {
+    std::string name (m_filename_after_features);
+
+    auto pos = name.find_first_of ('.');
+
+    name = name.substr (0, pos);
+    std::replace (name.begin (), name.end (), '/', '_');
+    std::replace (name.begin (), name.end (), '-', '_');
+
+    printf_unfiltered ("static int\n");
+    printf_unfiltered ("create_feature_%s ", name.c_str ());
+    printf_unfiltered ("(struct target_desc *result, long regnum)\n");
+
+    printf_unfiltered ("{\n");
+    printf_unfiltered ("  struct tdesc_feature *feature;\n");
+
+    printf_unfiltered
+      ("\n  feature = tdesc_create_feature (result, \"%s\", \"%s\");\n",
+       e->name, lbasename (m_filename_after_features.c_str ()));
+  }
+
+  void visit_post (const tdesc_feature *e) override
+  {
+    printf_unfiltered ("  return regnum;\n");
+    printf_unfiltered ("}\n");
+  }
+
+  void visit (const tdesc_reg *reg) override
+  {
+    /* Most "reg" in XML target descriptions don't have "regnum"
+       attribute, so the register number is allocated sequentially.
+       In case that reg has "regnum" attribute, register number
+       should be set by that explicitly.  */
 
-  printf_unfiltered ("\n");
+    if (reg->target_regnum < m_next_regnum)
+      {
+       /* The integrity check, it can catch some errors on register
+          number collision, like this,
+
+         <reg name="x0" bitsize="32"/>
+         <reg name="x1" bitsize="32"/>
+         <reg name="x2" bitsize="32"/>
+         <reg name="x3" bitsize="32"/>
+         <reg name="ps" bitsize="32" regnum="3"/>
+
+         but it also has false negatives.  The target description
+         below is correct,
+
+         <reg name="x1" bitsize="32" regnum="1"/>
+         <reg name="x3" bitsize="32" regnum="3"/>
+         <reg name="x2" bitsize="32" regnum="2"/>
+         <reg name="x4" bitsize="32" regnum="4"/>
+
+         but it is not a good practice, so still error on this,
+         and also print the message so that it can be saved in the
+         generated c file.  */
+
+       printf_unfiltered ("ERROR: \"regnum\" attribute %ld ",
+                          reg->target_regnum);
+       printf_unfiltered ("is not the largest number (%d).\n",
+                          m_next_regnum);
+       error (_("\"regnum\" attribute %ld is not the largest number (%d)."),
+              reg->target_regnum, m_next_regnum);
+      }
+
+    if (reg->target_regnum > m_next_regnum)
+      {
+       printf_unfiltered ("  regnum = %ld;\n", reg->target_regnum);
+       m_next_regnum = reg->target_regnum;
+      }
+
+    printf_unfiltered ("  tdesc_create_reg (feature, \"%s\", regnum++, %d, ",
+                      reg->name, reg->save_restore);
+    if (reg->group)
+      printf_unfiltered ("\"%s\", ", reg->group);
+    else
+      printf_unfiltered ("NULL, ");
+    printf_unfiltered ("%d, \"%s\");\n", reg->bitsize, reg->type);
+
+    m_next_regnum++;
+  }
+
+private:
+  /* The register number to use for the next register we see.  */
+  int m_next_regnum = 0;
+};
+
+static void
+maint_print_c_tdesc_cmd (char *args, int from_tty)
+{
+  const struct target_desc *tdesc;
+  const char *filename;
 
-  if (tdesc_architecture (tdesc) != NULL)
+  if (args == NULL)
     {
-      printf_unfiltered
-       ("  set_tdesc_architecture (result, bfd_scan_arch (\"%s\"));\n",
-        tdesc_architecture (tdesc)->printable_name);
-      printf_unfiltered ("\n");
+      /* Use the global target-supplied description, not the current
+        architecture's.  This lets a GDB for one architecture generate C
+        for another architecture's description, even though the gdbarch
+        initialization code will reject the new description.  */
+      tdesc = current_target_desc;
+      filename = target_description_filename;
     }
-
-  if (tdesc_osabi (tdesc) > GDB_OSABI_UNKNOWN
-      && tdesc_osabi (tdesc) < GDB_OSABI_INVALID)
+  else
     {
-      printf_unfiltered
-       ("  set_tdesc_osabi (result, osabi_from_tdesc_string (\"%s\"));\n",
-        gdbarch_osabi_name (tdesc_osabi (tdesc)));
-      printf_unfiltered ("\n");
+      /* Use the target description from the XML file.  */
+      filename = args;
+      tdesc = file_read_description_xml (filename);
     }
 
-  for (ix = 0; VEC_iterate (arch_p, tdesc->compatible, ix, compatible);
-       ix++)
+  if (tdesc == NULL)
+    error (_("There is no target description to print."));
+
+  if (filename == NULL)
+    error (_("The current target description did not come from an XML file."));
+
+  std::string filename_after_features (filename);
+  auto loc = filename_after_features.rfind ("/features/");
+
+  if (loc != std::string::npos)
+    filename_after_features = filename_after_features.substr (loc + 10);
+
+  /* Print c files for target features instead of target descriptions,
+     because c files got from target features are more flexible than the
+     counterparts.  */
+  if (startswith (filename_after_features.c_str (), "i386/32bit-"))
     {
-      printf_unfiltered
-       ("  tdesc_add_compatible (result, bfd_scan_arch (\"%s\"));\n",
-        compatible->printable_name);
-    }
-  if (ix)
-    printf_unfiltered ("\n");
+      print_c_feature v (filename_after_features);
 
-  for (ix = 0; VEC_iterate (property_s, tdesc->properties, ix, prop);
-       ix++)
+      tdesc->accept (v);
+    }
+  else
     {
-      printf_unfiltered ("  set_tdesc_property (result, \"%s\", \"%s\");\n",
-             prop->key, prop->value);
+      print_c_tdesc v (filename_after_features);
+
+      tdesc->accept (v);
     }
+}
 
-  for (ix = 0;
-       VEC_iterate (tdesc_feature_p, tdesc->features, ix, feature);
-       ix++)
-    {
-      printf_unfiltered ("  \
-feature = tdesc_create_feature (result, \"%s\");\n",
-                        feature->name);
+namespace selftests {
 
-      for (ix2 = 0;
-          VEC_iterate (tdesc_type_p, feature->types, ix2, type);
-          ix2++)
-       {
-         switch (type->kind)
-           {
-           case TDESC_TYPE_VECTOR:
-             printf_unfiltered
-               ("  field_type = tdesc_named_type (feature, \"%s\");\n",
-                type->u.v.type->name);
-             printf_unfiltered
-               ("  tdesc_create_vector (feature, \"%s\", field_type, %d);\n",
-                type->name, type->u.v.count);
-             break;
-           case TDESC_TYPE_STRUCT:
-           case TDESC_TYPE_FLAGS:
-             if (type->kind == TDESC_TYPE_STRUCT)
-               {
-                 printf_unfiltered
-                   ("  type = tdesc_create_struct (feature, \"%s\");\n",
-                    type->name);
-                 if (type->u.u.size != 0)
-                   printf_unfiltered
-                     ("  tdesc_set_struct_size (type, %d);\n",
-                      type->u.u.size);
-               }
-             else
-               {
-                 printf_unfiltered
-                   ("  type = tdesc_create_flags (feature, \"%s\", %d);\n",
-                    type->name, type->u.u.size);
-               }
-             for (ix3 = 0;
-                  VEC_iterate (tdesc_type_field, type->u.u.fields, ix3, f);
-                  ix3++)
-               {
-                 const char *type_name;
-
-                 gdb_assert (f->type != NULL);
-                 type_name = f->type->name;
-
-                 /* To minimize changes to generated files, don't emit type
-                    info for fields that have defaulted types.  */
-                 if (f->start != -1)
-                   {
-                     gdb_assert (f->end != -1);
-                     if (f->type->kind == TDESC_TYPE_BOOL)
-                       {
-                         gdb_assert (f->start == f->end);
-                         printf_unfiltered
-                           ("  tdesc_add_flag (type, %d, \"%s\");\n",
-                            f->start, f->name);
-                       }
-                     else if ((type->u.u.size == 4
-                               && f->type->kind == TDESC_TYPE_UINT32)
-                              || (type->u.u.size == 8
-                                  && f->type->kind == TDESC_TYPE_UINT64))
-                       {
-                         printf_unfiltered
-                           ("  tdesc_add_bitfield (type, \"%s\", %d, %d);\n",
-                            f->name, f->start, f->end);
-                       }
-                     else
-                       {
-                         printf_unfiltered
-                           ("  field_type = tdesc_named_type (feature,"
-                            " \"%s\");\n",
-                            type_name);
-                         printf_unfiltered
-                           ("  tdesc_add_typed_bitfield (type, \"%s\","
-                            " %d, %d, field_type);\n",
-                            f->name, f->start, f->end);
-                       }
-                   }
-                 else /* Not a bitfield.  */
-                   {
-                     gdb_assert (f->end == -1);
-                     gdb_assert (type->kind == TDESC_TYPE_STRUCT);
-                     printf_unfiltered
-                       ("  field_type = tdesc_named_type (feature,"
-                        " \"%s\");\n",
-                        type_name);
-                     printf_unfiltered
-                       ("  tdesc_add_field (type, \"%s\", field_type);\n",
-                        f->name);
-                   }
-               }
-             break;
-           case TDESC_TYPE_UNION:
-             printf_unfiltered
-               ("  type = tdesc_create_union (feature, \"%s\");\n",
-                type->name);
-             for (ix3 = 0;
-                  VEC_iterate (tdesc_type_field, type->u.u.fields, ix3, f);
-                  ix3++)
-               {
-                 printf_unfiltered
-                   ("  field_type = tdesc_named_type (feature, \"%s\");\n",
-                    f->type->name);
-                 printf_unfiltered
-                   ("  tdesc_add_field (type, \"%s\", field_type);\n",
-                    f->name);
-               }
-             break;
-           case TDESC_TYPE_ENUM:
-             printf_unfiltered
-               ("  type = tdesc_create_enum (feature, \"%s\", %d);\n",
-                type->name, type->u.u.size);
-             for (ix3 = 0;
-                  VEC_iterate (tdesc_type_field, type->u.u.fields, ix3, f);
-                  ix3++)
-               printf_unfiltered
-                 ("  tdesc_add_enum_value (type, %d, \"%s\");\n",
-                  f->start, f->name);
-             break;
-           default:
-             error (_("C output is not supported type \"%s\"."), type->name);
-           }
-         printf_unfiltered ("\n");
-       }
+static std::vector<std::pair<const char*, const target_desc *>> xml_tdesc;
 
-      for (ix2 = 0;
-          VEC_iterate (tdesc_reg_p, feature->registers, ix2, reg);
-          ix2++)
-       {
-         printf_unfiltered ("  tdesc_create_reg (feature, \"%s\", %ld, %d, ",
-                            reg->name, reg->target_regnum, reg->save_restore);
-         if (reg->group)
-           printf_unfiltered ("\"%s\", ", reg->group);
-         else
-           printf_unfiltered ("NULL, ");
-         printf_unfiltered ("%d, \"%s\");\n", reg->bitsize, reg->type);
-       }
+#if GDB_SELF_TEST
 
-      printf_unfiltered ("\n");
-    }
+/* See target-descritpions.h.  */
+
+void
+record_xml_tdesc (const char *xml_file, const struct target_desc *tdesc)
+{
+  xml_tdesc.emplace_back (xml_file, tdesc);
+}
+#endif
+
+}
+
+/* Check that the target descriptions created dynamically by
+   architecture-specific code equal the descriptions created from XML files
+   found in the specified directory DIR.  */
 
-  printf_unfiltered ("  tdesc_%s = result;\n", function);
-  printf_unfiltered ("}\n");
+static void
+maintenance_check_xml_descriptions (char *dir, int from_tty)
+{
+  if (dir == NULL)
+    error (_("Missing dir name"));
+
+  gdb::unique_xmalloc_ptr<char> dir1 (tilde_expand (dir));
+  std::string feature_dir (dir1.get ());
+  unsigned int failed = 0;
+
+  for (auto const &e : selftests::xml_tdesc)
+    {
+      std::string tdesc_xml = (feature_dir + SLASH_STRING + e.first);
+      const target_desc *tdesc
+       = file_read_description_xml (tdesc_xml.data ());
+
+      if (tdesc == NULL || *tdesc != *e.second)
+       failed++;
+    }
+  printf_filtered (_("Tested %lu XML files, %d failed\n"),
+                  (long) selftests::xml_tdesc.size (), failed);
 }
 
 /* Provide a prototype to silence -Wmissing-prototypes.  */
@@ -2029,4 +2410,14 @@ GDB will read the description from the target."),
   add_cmd ("c-tdesc", class_maintenance, maint_print_c_tdesc_cmd, _("\
 Print the current target description as a C source file."),
           &maintenanceprintlist);
+
+  cmd_list_element *cmd;
+
+  cmd = add_cmd ("xml-descriptions", class_maintenance,
+                maintenance_check_xml_descriptions, _("\
+Check the target descriptions created in GDB equal the descriptions\n\
+created from XML files in the directory.\n\
+The parameter is the directory name."),
+                &maintenancechecklist);
+  set_cmd_completer (cmd, filename_completer);
 }
This page took 0.037352 seconds and 4 git commands to generate.