gdb: Fix build failure with GCC 7
[deliverable/binutils-gdb.git] / gdb / target-descriptions.c
index 5ba167fc87f941ccf87a8706c377bb20b383b9f9..bee8e004f4b04354383e7c09e71647a44b4acd7c 100644 (file)
@@ -1,6 +1,6 @@
 /* Target description support for GDB.
 
-   Copyright (C) 2006-2016 Free Software Foundation, Inc.
+   Copyright (C) 2006-2017 Free Software Foundation, Inc.
 
    Contributed by CodeSourcery.
 
 #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,8 +70,33 @@ 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_,
+            int bitsize_, const char *type_)
+    : name (xstrdup (name_)), target_regnum (regnum),
+      save_restore (save_restore_),
+      group (group_ != NULL ? xstrdup (group_) : NULL),
+      bitsize (bitsize_),
+      type (type_ != NULL ? xstrdup (type_) : xstrdup ("<unknown>"))
+  {
+    /* If the register's type is target-defined, look it up now.  We may not
+       have easy access to the containing feature when we want it later.  */
+    tdesc_type = tdesc_named_type (feature, type);
+  }
+
+  virtual ~tdesc_reg ()
+  {
+    xfree (name);
+    xfree (type);
+    xfree (group);
+  }
+
+  /* Disable copying.  */
+  tdesc_reg (const tdesc_reg &) = delete;
+  tdesc_reg &operator= (const tdesc_reg &) = delete;
+
   /* The name of this register.  In standard features, it may be
      recognized by the architecture support code, or it may be purely
      for the user.  */
@@ -81,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);
 
@@ -90,20 +159,17 @@ typedef struct tdesc_type_field
 {
   char *name;
   struct tdesc_type *type;
+  /* For non-enum-values, either both are -1 (non-bitfield), or both are
+     not -1 (bitfield).  For enum values, start is the value (which could be
+     -1), end is -1.  */
   int start, end;
 } tdesc_type_field;
 DEF_VEC_O(tdesc_type_field);
 
-typedef struct tdesc_type_flag
-{
-  char *name;
-  int start;
-} tdesc_type_flag;
-DEF_VEC_O(tdesc_type_flag);
-
 enum tdesc_type_kind
 {
   /* Predefined types.  */
+  TDESC_TYPE_BOOL,
   TDESC_TYPE_INT8,
   TDESC_TYPE_INT16,
   TDESC_TYPE_INT32,
@@ -125,13 +191,52 @@ enum tdesc_type_kind
   TDESC_TYPE_VECTOR,
   TDESC_TYPE_STRUCT,
   TDESC_TYPE_UNION,
-  TDESC_TYPE_FLAGS
+  TDESC_TYPE_FLAGS,
+  TDESC_TYPE_ENUM
 };
 
-typedef struct tdesc_type
+typedef struct tdesc_type : tdesc_element
 {
-  /* The name of this type.  */
-  char *name;
+  tdesc_type (const char *name_, enum tdesc_type_kind kind_)
+    : name (xstrdup (name_)), kind (kind_)
+  {
+    memset (&u, 0, sizeof (u));
+  }
+
+  virtual ~tdesc_type ()
+  {
+    switch (kind)
+      {
+      case TDESC_TYPE_STRUCT:
+      case TDESC_TYPE_UNION:
+      case TDESC_TYPE_FLAGS:
+      case TDESC_TYPE_ENUM:
+       {
+         struct tdesc_type_field *f;
+         int ix;
+
+         for (ix = 0;
+              VEC_iterate (tdesc_type_field, u.u.fields, ix, f);
+              ix++)
+           xfree (f->name);
+
+         VEC_free (tdesc_type_field, u.u.fields);
+       }
+       break;
+
+      default:
+       break;
+      }
+    xfree ((char *) name);
+  }
+  /* Disable copying.  */
+  tdesc_type (const tdesc_type &) = delete;
+  tdesc_type &operator= (const tdesc_type &) = delete;
+
+  /* The name of this type.  If this type is a built-in type, this is
+     a pointer to a constant string.  Otherwise, it's a
+     malloc-allocated string (and thus must be freed).  */
+  const char *name;
 
   /* Identify the kind of this type.  */
   enum tdesc_type_kind kind;
@@ -146,37 +251,140 @@ typedef struct tdesc_type
       int count;
     } v;
 
-    /* Struct or union type.  */
+    /* Struct, union, flags, or enum type.  */
     struct
     {
       VEC(tdesc_type_field) *fields;
-      LONGEST size;
+      int size;
     } u;
-
-    /* Flags type.  */
-    struct
-    {
-      VEC(tdesc_type_flag) *flags;
-      LONGEST size;
-    } f;
   } 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_))
+  {}
+
+  virtual ~tdesc_feature ()
+  {
+    struct tdesc_reg *reg;
+    struct tdesc_type *type;
+    int ix;
+
+    for (ix = 0; VEC_iterate (tdesc_reg_p, registers, ix, reg); ix++)
+      delete reg;
+    VEC_free (tdesc_reg_p, registers);
+
+    for (ix = 0; VEC_iterate (tdesc_type_p, types, ix, type); ix++)
+      delete type;
+    VEC_free (tdesc_type_p, types);
+
+    xfree (name);
+  }
+
+  /* Disable copying.  */
+  tdesc_feature (const tdesc_feature &) = delete;
+  tdesc_feature &operator= (const tdesc_feature &) = delete;
+
   /* The name of this feature.  It may be recognized by the architecture
      support code.  */
   char *name;
 
   /* The registers associated with this feature.  */
-  VEC(tdesc_reg_p) *registers;
+  VEC(tdesc_reg_p) *registers = NULL;
 
   /* The types associated with this feature.  */
-  VEC(tdesc_type_p) *types;
+  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);
 
@@ -186,23 +394,100 @@ DEF_VEC_P(arch_p);
 
 /* A target description.  */
 
-struct target_desc
+struct target_desc : tdesc_element
 {
+  target_desc ()
+  {}
+
+  virtual ~target_desc ()
+  {
+    struct tdesc_feature *feature;
+    struct property *prop;
+    int ix;
+
+    for (ix = 0;
+        VEC_iterate (tdesc_feature_p, features, ix, feature);
+        ix++)
+      delete feature;
+    VEC_free (tdesc_feature_p, features);
+
+    for (ix = 0;
+        VEC_iterate (property_s, properties, ix, prop);
+        ix++)
+      {
+       xfree (prop->key);
+       xfree (prop->value);
+      }
+
+    VEC_free (property_s, properties);
+    VEC_free (arch_p, compatible);
+  }
+
+  target_desc (const target_desc &) = delete;
+  void operator= (const target_desc &) = delete;
+
   /* The architecture reported by the target, if any.  */
-  const struct bfd_arch_info *arch;
+  const struct bfd_arch_info *arch = NULL;
 
   /* The osabi reported by the target, if any; GDB_OSABI_UNKNOWN
      otherwise.  */
-  enum gdb_osabi osabi;
+  enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
 
   /* The list of compatible architectures reported by the target.  */
-  VEC(arch_p) *compatible;
+  VEC(arch_p) *compatible = NULL;
 
   /* Any architecture-specific properties specified by the target.  */
-  VEC(property_s) *properties;
+  VEC(property_s) *properties = NULL;
 
   /* The features associated with this target.  */
-  VEC(tdesc_feature_p) *features;
+  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
@@ -527,6 +812,7 @@ tdesc_feature_name (const struct tdesc_feature *feature)
 /* Predefined types.  */
 static struct tdesc_type tdesc_predefined_types[] =
 {
+  { "bool", TDESC_TYPE_BOOL },
   { "int8", TDESC_TYPE_INT8 },
   { "int16", TDESC_TYPE_INT16 },
   { "int32", TDESC_TYPE_INT32 },
@@ -545,6 +831,21 @@ static struct tdesc_type tdesc_predefined_types[] =
   { "i387_ext", TDESC_TYPE_I387_EXT }
 };
 
+/* Lookup a predefined type.  */
+
+static struct tdesc_type *
+tdesc_predefined_type (enum tdesc_type_kind kind)
+{
+  int ix;
+  struct tdesc_type *type;
+
+  for (ix = 0; ix < ARRAY_SIZE (tdesc_predefined_types); ix++)
+    if (tdesc_predefined_types[ix].kind == kind)
+      return &tdesc_predefined_types[ix];
+
+  gdb_assert_not_reached ("bad predefined tdesc type");
+}
+
 /* Return the type associated with ID in the context of FEATURE, or
    NULL if none.  */
 
@@ -602,6 +903,9 @@ tdesc_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *tdesc_type)
   switch (tdesc_type->kind)
     {
     /* Predefined types.  */
+    case TDESC_TYPE_BOOL:
+      return builtin_type (gdbarch)->builtin_bool;
+
     case TDESC_TYPE_INT8:
       return builtin_type (gdbarch)->builtin_int8;
 
@@ -690,17 +994,18 @@ tdesc_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *tdesc_type)
             VEC_iterate (tdesc_type_field, tdesc_type->u.u.fields, ix, f);
             ix++)
          {
-           if (f->type == NULL)
+           if (f->start != -1 && f->end != -1)
              {
                /* Bitfield.  */
                struct field *fld;
                struct type *field_type;
                int bitsize, total_size;
 
-               /* This invariant should be preserved while creating
-                  types.  */
+               /* This invariant should be preserved while creating types.  */
                gdb_assert (tdesc_type->u.u.size != 0);
-               if (tdesc_type->u.u.size > 4)
+               if (f->type != NULL)
+                 field_type = tdesc_gdb_type (gdbarch, f->type);
+               else if (tdesc_type->u.u.size > 4)
                  field_type = builtin_type (gdbarch)->builtin_uint64;
                else
                  field_type = builtin_type (gdbarch)->builtin_uint32;
@@ -725,6 +1030,7 @@ tdesc_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *tdesc_type)
              }
            else
              {
+               gdb_assert (f->start == -1 && f->end == -1);
                field_type = tdesc_gdb_type (gdbarch, f->type);
                append_composite_type_field (type, xstrdup (f->name),
                                             field_type);
@@ -763,19 +1069,45 @@ tdesc_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *tdesc_type)
 
     case TDESC_TYPE_FLAGS:
       {
-       struct tdesc_type_flag *f;
+       struct tdesc_type_field *f;
        int ix;
 
        type = arch_flags_type (gdbarch, tdesc_type->name,
-                               tdesc_type->u.f.size);
+                               tdesc_type->u.u.size);
+       for (ix = 0;
+            VEC_iterate (tdesc_type_field, tdesc_type->u.u.fields, ix, f);
+            ix++)
+         {
+           struct type *field_type;
+           int bitsize = f->end - f->start + 1;
+
+           gdb_assert (f->type != NULL);
+           field_type = tdesc_gdb_type (gdbarch, f->type);
+           append_flags_type_field (type, f->start, bitsize,
+                                    field_type, f->name);
+         }
+
+       return type;
+      }
+
+    case TDESC_TYPE_ENUM:
+      {
+       struct tdesc_type_field *f;
+       int ix;
+
+       type = arch_type (gdbarch, TYPE_CODE_ENUM,
+                         tdesc_type->u.u.size, tdesc_type->name);
+       TYPE_UNSIGNED (type) = 1;
        for (ix = 0;
-            VEC_iterate (tdesc_type_flag, tdesc_type->u.f.flags, ix, f);
+            VEC_iterate (tdesc_type_field, tdesc_type->u.u.fields, ix, f);
             ix++)
-         /* Note that contrary to the function name, this call will
-            just set the properties of an already-allocated
-            field.  */
-         append_flags_type_flag (type, f->start,
-                                 *f->name ? f->name : NULL);
+         {
+           struct field *fld
+             = append_composite_type_field_raw (type, xstrdup (f->name),
+                                                NULL);
+
+           SET_FIELD_BITPOS (fld[0], f->start);
+         }
 
        return type;
       }
@@ -1234,88 +1566,23 @@ tdesc_use_registers (struct gdbarch *gdbarch,
 }
 \f
 
-/* Methods for constructing a target description.  */
-
-static void
-tdesc_free_reg (struct tdesc_reg *reg)
-{
-  xfree (reg->name);
-  xfree (reg->type);
-  xfree (reg->group);
-  xfree (reg);
-}
-
 void
 tdesc_create_reg (struct tdesc_feature *feature, const char *name,
                  int regnum, int save_restore, const char *group,
                  int bitsize, const char *type)
 {
-  struct tdesc_reg *reg = XCNEW (struct tdesc_reg);
-
-  reg->name = xstrdup (name);
-  reg->target_regnum = regnum;
-  reg->save_restore = save_restore;
-  reg->group = group ? xstrdup (group) : NULL;
-  reg->bitsize = bitsize;
-  reg->type = type ? xstrdup (type) : xstrdup ("<unknown>");
-
-  /* If the register's type is target-defined, look it up now.  We may not
-     have easy access to the containing feature when we want it later.  */
-  reg->tdesc_type = tdesc_named_type (feature, reg->type);
+  tdesc_reg *reg = new tdesc_reg (feature, name, regnum, save_restore,
+                                 group, bitsize, type);
 
   VEC_safe_push (tdesc_reg_p, feature->registers, reg);
 }
 
-static void
-tdesc_free_type (struct tdesc_type *type)
-{
-  switch (type->kind)
-    {
-    case TDESC_TYPE_STRUCT:
-    case TDESC_TYPE_UNION:
-      {
-       struct tdesc_type_field *f;
-       int ix;
-
-       for (ix = 0;
-            VEC_iterate (tdesc_type_field, type->u.u.fields, ix, f);
-            ix++)
-         xfree (f->name);
-
-       VEC_free (tdesc_type_field, type->u.u.fields);
-      }
-      break;
-
-    case TDESC_TYPE_FLAGS:
-      {
-       struct tdesc_type_flag *f;
-       int ix;
-
-       for (ix = 0;
-            VEC_iterate (tdesc_type_flag, type->u.f.flags, ix, f);
-            ix++)
-         xfree (f->name);
-
-       VEC_free (tdesc_type_flag, type->u.f.flags);
-      }
-      break;
-
-    default:
-      break;
-    }
-
-  xfree (type->name);
-  xfree (type);
-}
-
 struct tdesc_type *
 tdesc_create_vector (struct tdesc_feature *feature, const char *name,
                     struct tdesc_type *field_type, int count)
 {
-  struct tdesc_type *type = XCNEW (struct tdesc_type);
+  struct tdesc_type *type = new tdesc_type (name, TDESC_TYPE_VECTOR);
 
-  type->name = xstrdup (name);
-  type->kind = TDESC_TYPE_VECTOR;
   type->u.v.type = field_type;
   type->u.v.count = count;
 
@@ -1326,10 +1593,7 @@ tdesc_create_vector (struct tdesc_feature *feature, const char *name,
 struct tdesc_type *
 tdesc_create_struct (struct tdesc_feature *feature, const char *name)
 {
-  struct tdesc_type *type = XCNEW (struct tdesc_type);
-
-  type->name = xstrdup (name);
-  type->kind = TDESC_TYPE_STRUCT;
+  struct tdesc_type *type = new tdesc_type (name, TDESC_TYPE_STRUCT);
 
   VEC_safe_push (tdesc_type_p, feature->types, type);
   return type;
@@ -1340,19 +1604,17 @@ tdesc_create_struct (struct tdesc_feature *feature, const char *name)
    suffice.  */
 
 void
-tdesc_set_struct_size (struct tdesc_type *type, LONGEST size)
+tdesc_set_struct_size (struct tdesc_type *type, int size)
 {
   gdb_assert (type->kind == TDESC_TYPE_STRUCT);
+  gdb_assert (size > 0);
   type->u.u.size = size;
 }
 
 struct tdesc_type *
 tdesc_create_union (struct tdesc_feature *feature, const char *name)
 {
-  struct tdesc_type *type = XCNEW (struct tdesc_type);
-
-  type->name = xstrdup (name);
-  type->kind = TDESC_TYPE_UNION;
+  struct tdesc_type *type = new tdesc_type (name, TDESC_TYPE_UNION);
 
   VEC_safe_push (tdesc_type_p, feature->types, type);
   return type;
@@ -1360,21 +1622,33 @@ tdesc_create_union (struct tdesc_feature *feature, const char *name)
 
 struct tdesc_type *
 tdesc_create_flags (struct tdesc_feature *feature, const char *name,
-                   LONGEST size)
+                   int size)
 {
-  struct tdesc_type *type = XCNEW (struct tdesc_type);
+  struct tdesc_type *type = new tdesc_type (name, TDESC_TYPE_FLAGS);
 
-  type->name = xstrdup (name);
-  type->kind = TDESC_TYPE_FLAGS;
-  type->u.f.size = size;
+  gdb_assert (size > 0);
+
+  type->u.u.size = size;
 
   VEC_safe_push (tdesc_type_p, feature->types, type);
   return type;
 }
 
-/* Add a new field.  Return a temporary pointer to the field, which
-   is only valid until the next call to tdesc_add_field (the vector
-   might be reallocated).  */
+struct tdesc_type *
+tdesc_create_enum (struct tdesc_feature *feature, const char *name,
+                  int size)
+{
+  struct tdesc_type *type = new tdesc_type (name, TDESC_TYPE_ENUM);
+
+  gdb_assert (size > 0);
+
+  type->u.u.size = size;
+
+  VEC_safe_push (tdesc_type_p, feature->types, type);
+  return type;
+}
+
+/* Add a new field to TYPE.  */
 
 void
 tdesc_add_field (struct tdesc_type *type, const char *field_name,
@@ -1387,66 +1661,94 @@ tdesc_add_field (struct tdesc_type *type, const char *field_name,
 
   f.name = xstrdup (field_name);
   f.type = field_type;
+  /* Initialize these values so we know this is not a bit-field
+     when we print-c-tdesc.  */
+  f.start = -1;
+  f.end = -1;
 
   VEC_safe_push (tdesc_type_field, type->u.u.fields, &f);
 }
 
-/* Add a new bitfield.  */
+/* Add a new typed bitfield to TYPE.  */
 
 void
-tdesc_add_bitfield (struct tdesc_type *type, const char *field_name,
-                   int start, int end)
+tdesc_add_typed_bitfield (struct tdesc_type *type, const char *field_name,
+                         int start, int end, struct tdesc_type *field_type)
 {
   struct tdesc_type_field f = { 0 };
 
-  gdb_assert (type->kind == TDESC_TYPE_STRUCT);
+  gdb_assert (type->kind == TDESC_TYPE_STRUCT
+             || type->kind == TDESC_TYPE_FLAGS);
+  gdb_assert (start >= 0 && end >= start);
 
   f.name = xstrdup (field_name);
   f.start = start;
   f.end = end;
+  f.type = field_type;
 
   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.  */
+
+void
+tdesc_add_bitfield (struct tdesc_type *type, const char *field_name,
+                   int start, int end)
+{
+  struct tdesc_type *field_type;
+
+  gdb_assert (start >= 0 && end >= start);
+
+  if (type->u.u.size > 4)
+    field_type = tdesc_predefined_type (TDESC_TYPE_UINT64);
+  else
+    field_type = tdesc_predefined_type (TDESC_TYPE_UINT32);
+
+  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.  */
+
 void
 tdesc_add_flag (struct tdesc_type *type, int start,
                const char *flag_name)
 {
-  struct tdesc_type_flag f = { 0 };
+  struct tdesc_type_field f = { 0 };
 
-  gdb_assert (type->kind == TDESC_TYPE_FLAGS);
+  gdb_assert (type->kind == TDESC_TYPE_FLAGS
+             || type->kind == TDESC_TYPE_STRUCT);
 
   f.name = xstrdup (flag_name);
   f.start = start;
+  f.end = start;
+  f.type = tdesc_predefined_type (TDESC_TYPE_BOOL);
 
-  VEC_safe_push (tdesc_type_flag, type->u.f.flags, &f);
+  VEC_safe_push (tdesc_type_field, type->u.u.fields, &f);
 }
 
-static void
-tdesc_free_feature (struct tdesc_feature *feature)
+void
+tdesc_add_enum_value (struct tdesc_type *type, int value,
+                     const char *name)
 {
-  struct tdesc_reg *reg;
-  struct tdesc_type *type;
-  int ix;
+  struct tdesc_type_field f = { 0 };
 
-  for (ix = 0; VEC_iterate (tdesc_reg_p, feature->registers, ix, reg); ix++)
-    tdesc_free_reg (reg);
-  VEC_free (tdesc_reg_p, feature->registers);
+  gdb_assert (type->kind == TDESC_TYPE_ENUM);
 
-  for (ix = 0; VEC_iterate (tdesc_type_p, feature->types, ix, type); ix++)
-    tdesc_free_type (type);
-  VEC_free (tdesc_type_p, feature->types);
+  f.name = xstrdup (name);
+  f.start = value;
+  f.end = -1;
+  f.type = tdesc_predefined_type (TDESC_TYPE_INT32);
 
-  xfree (feature->name);
-  xfree (feature);
+  VEC_safe_push (tdesc_type_field, type->u.u.fields, &f);
 }
 
 struct tdesc_feature *
 tdesc_create_feature (struct target_desc *tdesc, const char *name)
 {
-  struct tdesc_feature *new_feature = XCNEW (struct tdesc_feature);
-
-  new_feature->name = xstrdup (name);
+  struct tdesc_feature *new_feature = new tdesc_feature (name);
 
   VEC_safe_push (tdesc_feature_p, tdesc->features, new_feature);
   return new_feature;
@@ -1455,35 +1757,15 @@ tdesc_create_feature (struct target_desc *tdesc, const char *name)
 struct target_desc *
 allocate_target_description (void)
 {
-  return XCNEW (struct target_desc);
+  return new target_desc ();
 }
 
 static void
 free_target_description (void *arg)
 {
   struct target_desc *target_desc = (struct target_desc *) arg;
-  struct tdesc_feature *feature;
-  struct property *prop;
-  int ix;
-
-  for (ix = 0;
-       VEC_iterate (tdesc_feature_p, target_desc->features, ix, feature);
-       ix++)
-    tdesc_free_feature (feature);
-  VEC_free (tdesc_feature_p, target_desc->features);
 
-  for (ix = 0;
-       VEC_iterate (property_s, target_desc->properties, ix, prop);
-       ix++)
-    {
-      xfree (prop->key);
-      xfree (prop->value);
-    }
-  VEC_free (property_s, target_desc->properties);
-
-  VEC_free (arch_p, target_desc->compatible);
-
-  xfree (target_desc);
+  delete target_desc;
 }
 
 struct cleanup *
@@ -1608,237 +1890,477 @@ 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;
-  struct tdesc_type_flag *flag;
-  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)
-              && VEC_length (tdesc_type_field, type->u.u.fields) > 0)
-             || (type->kind == TDESC_TYPE_FLAGS
-                 && VEC_length (tdesc_type_flag, type->u.f.flags) > 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 ()));
 
-      if (printed_desc_type)
-       break;
-    }
+    printf_unfiltered ("#include \"defs.h\"\n");
+    printf_unfiltered ("#include \"osabi.h\"\n");
+    printf_unfiltered ("#include \"target-descriptions.h\"\n");
+    printf_unfiltered ("\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 (tdesc) != NULL)
-    {
-      printf_unfiltered
-       ("  set_tdesc_architecture (result, bfd_scan_arch (\"%s\"));\n",
-        tdesc_architecture (tdesc)->printable_name);
-      printf_unfiltered ("\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 (tdesc_osabi (tdesc) > GDB_OSABI_UNKNOWN
-      && tdesc_osabi (tdesc) < GDB_OSABI_INVALID)
-    {
-      printf_unfiltered
-       ("  set_tdesc_osabi (result, osabi_from_tdesc_string (\"%s\"));\n",
-        gdbarch_osabi_name (tdesc_osabi (tdesc)));
+    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 (arch_p, tdesc->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");
+  }
 
-  for (ix = 0; VEC_iterate (property_s, tdesc->properties, ix, prop);
-       ix++)
-    {
-      printf_unfiltered ("  set_tdesc_property (result, \"%s\", \"%s\");\n",
-             prop->key, prop->value);
-    }
+  void visit_pre (const tdesc_feature *e) override
+  {
+    printf_unfiltered ("\n  feature = tdesc_create_feature (result, \"%s\");\n",
+                      e->name);
+  }
 
-  for (ix = 0;
-       VEC_iterate (tdesc_feature_p, tdesc->features, ix, feature);
-       ix++)
-    {
-      printf_unfiltered ("  \
-feature = tdesc_create_feature (result, \"%s\");\n",
-                        feature->name);
+  void visit_post (const tdesc_feature *e) override
+  {}
 
-      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:
+  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
-               ("  type = tdesc_create_struct (feature, \"%s\");\n",
-                type->name);
-             if (type->u.u.size != 0)
-               printf_unfiltered
-                 ("  tdesc_set_struct_size (type, %s);\n",
-                  plongest (type->u.u.size));
-             for (ix3 = 0;
-                  VEC_iterate (tdesc_type_field, type->u.u.fields, ix3, f);
-                  ix3++)
-               {
-                 /* Going first for implicitly sized types, else part handles
-                    bitfields.  As reported on xml-tdesc.c implicitly sized types
-                    cannot contain a bitfield.  */
-                 if (f->type != NULL)
-                   {
-                     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);
-                   }
-                 else
+               ("  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);
-               }
-             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_FLAGS:
-             printf_unfiltered
-               ("  type = tdesc_create_flags (feature, \"%s\", %d);\n",
-                type->name, (int) type->u.f.size);
-             for (ix3 = 0;
-                  VEC_iterate (tdesc_type_flag, type->u.f.flags, ix3,
-                               flag);
-                  ix3++)
+                 }
+               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
-                 ("  tdesc_add_flag (type, %d, \"%s\");\n",
-                  flag->start, flag->name);
-             break;
-           default:
-             error (_("C output is not supported type \"%s\"."), type->name);
-           }
-         printf_unfiltered ("\n");
-       }
+                 ("  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");
+  }
 
-      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);
-       }
+  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);
+  }
 
-      printf_unfiltered ("\n");
+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 \"target-descriptions.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\");\n",
+                      e->name);
+  }
+
+  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.  */
+
+    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 (args == NULL)
+    {
+      /* 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;
+    }
+  else
+    {
+      /* Use the target description from the XML file.  */
+      filename = args;
+      tdesc = file_read_description_xml (filename);
     }
 
-  printf_unfiltered ("  tdesc_%s = result;\n", function);
-  printf_unfiltered ("}\n");
+  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-"))
+    {
+      print_c_feature v (filename_after_features);
+
+      tdesc->accept (v);
+    }
+  else
+    {
+      print_c_tdesc v (filename_after_features);
+
+      tdesc->accept (v);
+    }
+}
+
+namespace selftests {
+
+static std::vector<std::pair<const char*, const target_desc *>> xml_tdesc;
+
+#if GDB_SELF_TEST
+
+/* 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.  */
+
+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.  */
@@ -1881,4 +2403,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.044188 seconds and 4 git commands to generate.