Patchwork [05/25] Use visitor pattern for "maint print c-tdesc"

login
register
mail settings
Submitter Yao Qi
Date June 12, 2017, 8:41 a.m.
Message ID <1497256916-4958-6-git-send-email-yao.qi@linaro.org>
Download mbox | patch
Permalink /patch/20924/
State New
Headers show

Comments

Yao Qi - June 12, 2017, 8:41 a.m.
Target description can be modeled as a tree, the target description
is the root node, features are children nodes, registers and types are
grand-children nodes.  So command "maint print c-tdesc" in effect
traverse/visit each node, and print them in c.  This can be
implemented by visitor pattern, this is the first reason.  Secondly,
I want to this command prints c files in a different way for some
specific xml files, but still print c files the same way for the rest
of xml files.  Third, I even want to print xml files from target
descriptions, so that GDBserver can use it to reply GDB's query
qXfer:features:read:target.xml.

After this change, all features/*.c should be re-generated, but
this patch only includes part changes features/*.c files.

gdb:

2017-05-25  Yao Qi  <yao.qi@linaro.org>

	* target-descriptions.c (tdesc_element_visitor): New class.
	(tdesc_element): New class.
	(tdesc_reg): Inherit from tdesc_element.
	(tdesc_reg::accept): New function.
	(tdesc_type): Inherit from tdesc_element.
	(tdesc_type::accept): New function.
	(tdesc_feature): Inherit from tdesc_element.
	(tdesc_feature::accept): New function.
	(target_desc): Inherit from tdesc_element.
	(target_desc::target_desc): New.
	(target_desc::~target_desc): New.
	(target_desc::accept): New.
	(allocate_target_description): Use new.
	(free_target_description): Use delete.
	(print_c_tdesc): New class.
	(maint_print_c_tdesc_cmd): Adjust.

	* features/i386/i386-avx-avx512-linux.c: Re-generated.
	* features/i386/i386-avx-linux.c: Re-generated.
	* features/i386/i386-avx-mpx-avx512-pku-linux.c: Re-generated.
	* features/i386/i386-avx-mpx-linux.c: Re-generated.
	* features/i386/i386-linux.c: Re-generated.
	* features/i386/i386-mmx-linux.c: Re-generated.
---
 gdb/features/i386/i386-avx-avx512-linux.c         |   8 +-
 gdb/features/i386/i386-avx-avx512.c               |   8 +-
 gdb/features/i386/i386-avx-linux.c                |   8 +-
 gdb/features/i386/i386-avx-mpx-avx512-pku-linux.c |   8 +-
 gdb/features/i386/i386-avx-mpx-avx512-pku.c       |   8 +-
 gdb/features/i386/i386-avx-mpx-linux.c            |   8 +-
 gdb/features/i386/i386-avx-mpx.c                  |   8 +-
 gdb/features/i386/i386-avx.c                      |   8 +-
 gdb/features/i386/i386-linux.c                    |   8 +-
 gdb/features/i386/i386-mmx-linux.c                |   8 +-
 gdb/features/i386/i386-mmx.c                      |   8 +-
 gdb/features/i386/i386-mpx-linux.c                |   8 +-
 gdb/features/i386/i386-mpx.c                      |   8 +-
 gdb/features/i386/i386.c                          |   8 +-
 gdb/target-descriptions.c                         | 657 ++++++++++++----------
 15 files changed, 427 insertions(+), 342 deletions(-)
Simon Marchi - June 20, 2017, 11:37 p.m.
On 2017-06-12 10:41, Yao Qi wrote:
> diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c
> index e2dcd1d..ac19792 100644
> --- a/gdb/target-descriptions.c
> +++ b/gdb/target-descriptions.c
> @@ -35,6 +35,23 @@
>  #include "hashtab.h"
>  #include "inferior.h"
> 
> +class tdesc_element_visitor
> +{
> +public:
> +  virtual void visit (const target_desc *e) = 0;
> +  virtual void visit_end (const target_desc *e) = 0;

For elements which children, and therefore can be visited before and 
after their children, I'd suggest using "visit_pre" and "visit_post" for 
the methods names.  It relates better to the terms pre-order and 
post-order.

> @@ -259,6 +287,30 @@ public:
> 
>    /* The types associated with this feature.  */
>    VEC(tdesc_type_p) *types = NULL;
> +
> +  void accept (tdesc_element_visitor &v) const override
> +  {
> +    v.visit (this);
> +
> +    struct tdesc_type *type;
> +
> +    for (int ix = 0;
> +	 VEC_iterate (tdesc_type_p, types, ix, type);
> +	 ix++)
> +      {
> +	type->accept (v);
> +      }

No need for braces here (and for all the ->accept calls in for loops).

> +
> +    struct tdesc_reg *reg;
> +
> +    for (int ix = 0;
> +	 VEC_iterate (tdesc_reg_p, registers, ix, reg);
> +	 ix++)
> +      {
> +	reg->accept (v);
> +      }
> +  }
> +
>  } *tdesc_feature_p;
>  DEF_VEC_P(tdesc_feature_p);
> 
> @@ -268,23 +320,67 @@ DEF_VEC_P(arch_p);
> 
>  /* A target description.  */
> 
> -struct target_desc
> +struct target_desc : tdesc_element
>  {

It's not a big deal, but the C++ification of target_desc would have 
fitted better in patch 03/25 I guess.

> +public:

You can remove public:.

> @@ -1707,279 +1783,288 @@ unset_tdesc_filename_cmd (char *args, int 
> from_tty)
>    target_find_description ();
>  }
> 
> -static void
> -maint_print_c_tdesc_cmd (char *args, int from_tty)
> +class print_c_tdesc : public tdesc_element_visitor

IWBN to have "visitor" in the class name: print_c_tdesc_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;
> +public:
> +  print_c_tdesc (std::string &filename_after_features)
> +    : m_filename_after_features (filename_after_features)

Could you document the parameter filename_after_features?

I didn't read the whole visitor code (it's getting late here...), but I 
like the idea and the pattern.

Simon

Patch

diff --git a/gdb/features/i386/i386-avx-avx512-linux.c b/gdb/features/i386/i386-avx-avx512-linux.c
index 81149d5..545149d 100644
--- a/gdb/features/i386/i386-avx-avx512-linux.c
+++ b/gdb/features/i386/i386-avx-avx512-linux.c
@@ -10,15 +10,15 @@  static void
 initialize_tdesc_i386_avx_avx512_linux (void)
 {
   struct target_desc *result = allocate_target_description ();
-  struct tdesc_feature *feature;
-  struct tdesc_type *field_type;
-  struct tdesc_type *type;
-
   set_tdesc_architecture (result, bfd_scan_arch ("i386"));
 
   set_tdesc_osabi (result, osabi_from_tdesc_string ("GNU/Linux"));
 
+  struct tdesc_feature *feature;
+
   feature = tdesc_create_feature (result, "org.gnu.gdb.i386.core");
+  struct tdesc_type *field_type;
+  struct tdesc_type *type;
   type = tdesc_create_flags (feature, "i386_eflags", 4);
   tdesc_add_flag (type, 0, "CF");
   tdesc_add_flag (type, 1, "");
diff --git a/gdb/features/i386/i386-avx-avx512.c b/gdb/features/i386/i386-avx-avx512.c
index 1075ca0..585a0ac 100644
--- a/gdb/features/i386/i386-avx-avx512.c
+++ b/gdb/features/i386/i386-avx-avx512.c
@@ -10,13 +10,13 @@  static void
 initialize_tdesc_i386_avx_avx512 (void)
 {
   struct target_desc *result = allocate_target_description ();
-  struct tdesc_feature *feature;
-  struct tdesc_type *field_type;
-  struct tdesc_type *type;
-
   set_tdesc_architecture (result, bfd_scan_arch ("i386"));
 
+  struct tdesc_feature *feature;
+
   feature = tdesc_create_feature (result, "org.gnu.gdb.i386.core");
+  struct tdesc_type *field_type;
+  struct tdesc_type *type;
   type = tdesc_create_flags (feature, "i386_eflags", 4);
   tdesc_add_flag (type, 0, "CF");
   tdesc_add_flag (type, 1, "");
diff --git a/gdb/features/i386/i386-avx-linux.c b/gdb/features/i386/i386-avx-linux.c
index 4a8c6b5..3ef087d 100644
--- a/gdb/features/i386/i386-avx-linux.c
+++ b/gdb/features/i386/i386-avx-linux.c
@@ -10,15 +10,15 @@  static void
 initialize_tdesc_i386_avx_linux (void)
 {
   struct target_desc *result = allocate_target_description ();
-  struct tdesc_feature *feature;
-  struct tdesc_type *field_type;
-  struct tdesc_type *type;
-
   set_tdesc_architecture (result, bfd_scan_arch ("i386"));
 
   set_tdesc_osabi (result, osabi_from_tdesc_string ("GNU/Linux"));
 
+  struct tdesc_feature *feature;
+
   feature = tdesc_create_feature (result, "org.gnu.gdb.i386.core");
+  struct tdesc_type *field_type;
+  struct tdesc_type *type;
   type = tdesc_create_flags (feature, "i386_eflags", 4);
   tdesc_add_flag (type, 0, "CF");
   tdesc_add_flag (type, 1, "");
diff --git a/gdb/features/i386/i386-avx-mpx-avx512-pku-linux.c b/gdb/features/i386/i386-avx-mpx-avx512-pku-linux.c
index f90c834..e6eebf1 100644
--- a/gdb/features/i386/i386-avx-mpx-avx512-pku-linux.c
+++ b/gdb/features/i386/i386-avx-mpx-avx512-pku-linux.c
@@ -10,15 +10,15 @@  static void
 initialize_tdesc_i386_avx_mpx_avx512_pku_linux (void)
 {
   struct target_desc *result = allocate_target_description ();
-  struct tdesc_feature *feature;
-  struct tdesc_type *field_type;
-  struct tdesc_type *type;
-
   set_tdesc_architecture (result, bfd_scan_arch ("i386"));
 
   set_tdesc_osabi (result, osabi_from_tdesc_string ("GNU/Linux"));
 
+  struct tdesc_feature *feature;
+
   feature = tdesc_create_feature (result, "org.gnu.gdb.i386.core");
+  struct tdesc_type *field_type;
+  struct tdesc_type *type;
   type = tdesc_create_flags (feature, "i386_eflags", 4);
   tdesc_add_flag (type, 0, "CF");
   tdesc_add_flag (type, 1, "");
diff --git a/gdb/features/i386/i386-avx-mpx-avx512-pku.c b/gdb/features/i386/i386-avx-mpx-avx512-pku.c
index 08d9b4b..d7dd3bb 100644
--- a/gdb/features/i386/i386-avx-mpx-avx512-pku.c
+++ b/gdb/features/i386/i386-avx-mpx-avx512-pku.c
@@ -10,13 +10,13 @@  static void
 initialize_tdesc_i386_avx_mpx_avx512_pku (void)
 {
   struct target_desc *result = allocate_target_description ();
-  struct tdesc_feature *feature;
-  struct tdesc_type *field_type;
-  struct tdesc_type *type;
-
   set_tdesc_architecture (result, bfd_scan_arch ("i386"));
 
+  struct tdesc_feature *feature;
+
   feature = tdesc_create_feature (result, "org.gnu.gdb.i386.core");
+  struct tdesc_type *field_type;
+  struct tdesc_type *type;
   type = tdesc_create_flags (feature, "i386_eflags", 4);
   tdesc_add_flag (type, 0, "CF");
   tdesc_add_flag (type, 1, "");
diff --git a/gdb/features/i386/i386-avx-mpx-linux.c b/gdb/features/i386/i386-avx-mpx-linux.c
index 4b27bfc..f62c487 100644
--- a/gdb/features/i386/i386-avx-mpx-linux.c
+++ b/gdb/features/i386/i386-avx-mpx-linux.c
@@ -10,15 +10,15 @@  static void
 initialize_tdesc_i386_avx_mpx_linux (void)
 {
   struct target_desc *result = allocate_target_description ();
-  struct tdesc_feature *feature;
-  struct tdesc_type *field_type;
-  struct tdesc_type *type;
-
   set_tdesc_architecture (result, bfd_scan_arch ("i386"));
 
   set_tdesc_osabi (result, osabi_from_tdesc_string ("GNU/Linux"));
 
+  struct tdesc_feature *feature;
+
   feature = tdesc_create_feature (result, "org.gnu.gdb.i386.core");
+  struct tdesc_type *field_type;
+  struct tdesc_type *type;
   type = tdesc_create_flags (feature, "i386_eflags", 4);
   tdesc_add_flag (type, 0, "CF");
   tdesc_add_flag (type, 1, "");
diff --git a/gdb/features/i386/i386-avx-mpx.c b/gdb/features/i386/i386-avx-mpx.c
index b27b40a..f479bda 100644
--- a/gdb/features/i386/i386-avx-mpx.c
+++ b/gdb/features/i386/i386-avx-mpx.c
@@ -10,13 +10,13 @@  static void
 initialize_tdesc_i386_avx_mpx (void)
 {
   struct target_desc *result = allocate_target_description ();
-  struct tdesc_feature *feature;
-  struct tdesc_type *field_type;
-  struct tdesc_type *type;
-
   set_tdesc_architecture (result, bfd_scan_arch ("i386"));
 
+  struct tdesc_feature *feature;
+
   feature = tdesc_create_feature (result, "org.gnu.gdb.i386.core");
+  struct tdesc_type *field_type;
+  struct tdesc_type *type;
   type = tdesc_create_flags (feature, "i386_eflags", 4);
   tdesc_add_flag (type, 0, "CF");
   tdesc_add_flag (type, 1, "");
diff --git a/gdb/features/i386/i386-avx.c b/gdb/features/i386/i386-avx.c
index 1cb0f9e..f888335 100644
--- a/gdb/features/i386/i386-avx.c
+++ b/gdb/features/i386/i386-avx.c
@@ -10,13 +10,13 @@  static void
 initialize_tdesc_i386_avx (void)
 {
   struct target_desc *result = allocate_target_description ();
-  struct tdesc_feature *feature;
-  struct tdesc_type *field_type;
-  struct tdesc_type *type;
-
   set_tdesc_architecture (result, bfd_scan_arch ("i386"));
 
+  struct tdesc_feature *feature;
+
   feature = tdesc_create_feature (result, "org.gnu.gdb.i386.core");
+  struct tdesc_type *field_type;
+  struct tdesc_type *type;
   type = tdesc_create_flags (feature, "i386_eflags", 4);
   tdesc_add_flag (type, 0, "CF");
   tdesc_add_flag (type, 1, "");
diff --git a/gdb/features/i386/i386-linux.c b/gdb/features/i386/i386-linux.c
index c7796c3..0394842 100644
--- a/gdb/features/i386/i386-linux.c
+++ b/gdb/features/i386/i386-linux.c
@@ -10,15 +10,15 @@  static void
 initialize_tdesc_i386_linux (void)
 {
   struct target_desc *result = allocate_target_description ();
-  struct tdesc_feature *feature;
-  struct tdesc_type *field_type;
-  struct tdesc_type *type;
-
   set_tdesc_architecture (result, bfd_scan_arch ("i386"));
 
   set_tdesc_osabi (result, osabi_from_tdesc_string ("GNU/Linux"));
 
+  struct tdesc_feature *feature;
+
   feature = tdesc_create_feature (result, "org.gnu.gdb.i386.core");
+  struct tdesc_type *field_type;
+  struct tdesc_type *type;
   type = tdesc_create_flags (feature, "i386_eflags", 4);
   tdesc_add_flag (type, 0, "CF");
   tdesc_add_flag (type, 1, "");
diff --git a/gdb/features/i386/i386-mmx-linux.c b/gdb/features/i386/i386-mmx-linux.c
index e53b55f..1577972 100644
--- a/gdb/features/i386/i386-mmx-linux.c
+++ b/gdb/features/i386/i386-mmx-linux.c
@@ -10,15 +10,15 @@  static void
 initialize_tdesc_i386_mmx_linux (void)
 {
   struct target_desc *result = allocate_target_description ();
-  struct tdesc_feature *feature;
-  struct tdesc_type *field_type;
-  struct tdesc_type *type;
-
   set_tdesc_architecture (result, bfd_scan_arch ("i386"));
 
   set_tdesc_osabi (result, osabi_from_tdesc_string ("GNU/Linux"));
 
+  struct tdesc_feature *feature;
+
   feature = tdesc_create_feature (result, "org.gnu.gdb.i386.core");
+  struct tdesc_type *field_type;
+  struct tdesc_type *type;
   type = tdesc_create_flags (feature, "i386_eflags", 4);
   tdesc_add_flag (type, 0, "CF");
   tdesc_add_flag (type, 1, "");
diff --git a/gdb/features/i386/i386-mmx.c b/gdb/features/i386/i386-mmx.c
index 74f67ed..02aee89 100644
--- a/gdb/features/i386/i386-mmx.c
+++ b/gdb/features/i386/i386-mmx.c
@@ -10,13 +10,13 @@  static void
 initialize_tdesc_i386_mmx (void)
 {
   struct target_desc *result = allocate_target_description ();
-  struct tdesc_feature *feature;
-  struct tdesc_type *field_type;
-  struct tdesc_type *type;
-
   set_tdesc_architecture (result, bfd_scan_arch ("i386"));
 
+  struct tdesc_feature *feature;
+
   feature = tdesc_create_feature (result, "org.gnu.gdb.i386.core");
+  struct tdesc_type *field_type;
+  struct tdesc_type *type;
   type = tdesc_create_flags (feature, "i386_eflags", 4);
   tdesc_add_flag (type, 0, "CF");
   tdesc_add_flag (type, 1, "");
diff --git a/gdb/features/i386/i386-mpx-linux.c b/gdb/features/i386/i386-mpx-linux.c
index 43ea192..6dea8e0 100644
--- a/gdb/features/i386/i386-mpx-linux.c
+++ b/gdb/features/i386/i386-mpx-linux.c
@@ -10,15 +10,15 @@  static void
 initialize_tdesc_i386_mpx_linux (void)
 {
   struct target_desc *result = allocate_target_description ();
-  struct tdesc_feature *feature;
-  struct tdesc_type *field_type;
-  struct tdesc_type *type;
-
   set_tdesc_architecture (result, bfd_scan_arch ("i386"));
 
   set_tdesc_osabi (result, osabi_from_tdesc_string ("GNU/Linux"));
 
+  struct tdesc_feature *feature;
+
   feature = tdesc_create_feature (result, "org.gnu.gdb.i386.core");
+  struct tdesc_type *field_type;
+  struct tdesc_type *type;
   type = tdesc_create_flags (feature, "i386_eflags", 4);
   tdesc_add_flag (type, 0, "CF");
   tdesc_add_flag (type, 1, "");
diff --git a/gdb/features/i386/i386-mpx.c b/gdb/features/i386/i386-mpx.c
index e832d2e..d08441b 100644
--- a/gdb/features/i386/i386-mpx.c
+++ b/gdb/features/i386/i386-mpx.c
@@ -10,13 +10,13 @@  static void
 initialize_tdesc_i386_mpx (void)
 {
   struct target_desc *result = allocate_target_description ();
-  struct tdesc_feature *feature;
-  struct tdesc_type *field_type;
-  struct tdesc_type *type;
-
   set_tdesc_architecture (result, bfd_scan_arch ("i386"));
 
+  struct tdesc_feature *feature;
+
   feature = tdesc_create_feature (result, "org.gnu.gdb.i386.core");
+  struct tdesc_type *field_type;
+  struct tdesc_type *type;
   type = tdesc_create_flags (feature, "i386_eflags", 4);
   tdesc_add_flag (type, 0, "CF");
   tdesc_add_flag (type, 1, "");
diff --git a/gdb/features/i386/i386.c b/gdb/features/i386/i386.c
index ede73fc..eb9a266 100644
--- a/gdb/features/i386/i386.c
+++ b/gdb/features/i386/i386.c
@@ -10,13 +10,13 @@  static void
 initialize_tdesc_i386 (void)
 {
   struct target_desc *result = allocate_target_description ();
-  struct tdesc_feature *feature;
-  struct tdesc_type *field_type;
-  struct tdesc_type *type;
-
   set_tdesc_architecture (result, bfd_scan_arch ("i386"));
 
+  struct tdesc_feature *feature;
+
   feature = tdesc_create_feature (result, "org.gnu.gdb.i386.core");
+  struct tdesc_type *field_type;
+  struct tdesc_type *type;
   type = tdesc_create_flags (feature, "i386_eflags", 4);
   tdesc_add_flag (type, 0, "CF");
   tdesc_add_flag (type, 1, "");
diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c
index e2dcd1d..ac19792 100644
--- a/gdb/target-descriptions.c
+++ b/gdb/target-descriptions.c
@@ -35,6 +35,23 @@ 
 #include "hashtab.h"
 #include "inferior.h"
 
+class tdesc_element_visitor
+{
+public:
+  virtual void visit (const target_desc *e) = 0;
+  virtual void visit_end (const target_desc *e) = 0;
+
+  virtual void visit (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.  */
 
 typedef struct property
@@ -46,7 +63,7 @@  DEF_VEC_O(property_s);
 
 /* An individual register from a target description.  */
 
-typedef struct tdesc_reg
+typedef struct tdesc_reg : tdesc_element
 {
 public:
   tdesc_reg (struct tdesc_feature *feature, const char *name_,
@@ -63,7 +80,7 @@  public:
     tdesc_type = tdesc_named_type (feature, type);
   }
 
-  ~tdesc_reg ()
+  virtual ~tdesc_reg ()
   {
     xfree (name);
     xfree (type);
@@ -107,6 +124,12 @@  public:
 
   /* 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);
+  }
+
 } *tdesc_reg_p;
 DEF_VEC_P(tdesc_reg_p);
 
@@ -152,7 +175,7 @@  enum tdesc_type_kind
   TDESC_TYPE_ENUM
 };
 
-typedef struct tdesc_type
+typedef struct tdesc_type : tdesc_element
 {
 public:
   tdesc_type (const char *name_, enum tdesc_type_kind kind_)
@@ -161,7 +184,7 @@  public:
     memset (&u, 0, sizeof (u));
   }
 
-  ~tdesc_type ()
+  virtual ~tdesc_type ()
   {
     switch (kind)
       {
@@ -216,20 +239,25 @@  public:
       int size;
     } u;
   } u;
+  void accept (tdesc_element_visitor &v) const override
+  {
+    v.visit (this);
+  }
+
 } *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
 {
 public:
   tdesc_feature (const char *name_)
     : name (xstrdup (name_))
   {}
 
-  ~tdesc_feature ()
+  virtual ~tdesc_feature ()
   {
     struct tdesc_reg *reg;
     struct tdesc_type *type;
@@ -259,6 +287,30 @@  public:
 
   /* The types associated with this feature.  */
   VEC(tdesc_type_p) *types = NULL;
+
+  void accept (tdesc_element_visitor &v) const override
+  {
+    v.visit (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);
+      }
+  }
+
 } *tdesc_feature_p;
 DEF_VEC_P(tdesc_feature_p);
 
@@ -268,23 +320,67 @@  DEF_VEC_P(arch_p);
 
 /* A target description.  */
 
-struct target_desc
+struct target_desc : tdesc_element
 {
+public:
+  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);
+  }
+
   /* 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 (this);
+
+    struct tdesc_feature *feature;
+
+    for (int ix = 0;
+	 VEC_iterate (tdesc_feature_p, features, ix, feature);
+	 ix++)
+      {
+	feature->accept (v);
+      }
+
+    v.visit_end (this);
+  }
 };
 
 /* Per-architecture data associated with a target description.  The
@@ -1554,35 +1650,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++)
-    delete 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 *
@@ -1707,279 +1783,288 @@  unset_tdesc_filename_cmd (char *args, int from_tty)
   target_find_description ();
 }
 
-static void
-maint_print_c_tdesc_cmd (char *args, int from_tty)
+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;
+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 ());
 
-  /* 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."));
+    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';
+
+    /* Standard boilerplate.  */
+    printf_unfiltered ("/* THIS FILE IS GENERATED.  "
+		       "-*- buffer-read-only: t -*- vi"
+		       ":set ro:\n");
+    printf_unfiltered ("  Original: %s */\n\n", filename);
+  }
 
-  if (target_description_filename == NULL)
-    error (_("The current target description did not come from an XML file."));
+  ~print_c_tdesc ()
+  {
+    xfree (m_function);
+  }
 
-  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;
+  void visit (const target_desc *e) override
+  {
+    printf_unfiltered ("#include \"defs.h\"\n");
+    printf_unfiltered ("#include \"osabi.h\"\n");
+    printf_unfiltered ("#include \"target-descriptions.h\"\n");
+    printf_unfiltered ("\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;
-	    }
+    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 ((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;
-	    }
-	}
+    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)
-	break;
-    }
+    int ix;
+    const struct bfd_arch_info *compatible;
+    struct property *prop;
 
-  printf_unfiltered ("\n");
+    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 (tdesc_architecture (tdesc) != NULL)
-    {
-      printf_unfiltered
-	("  set_tdesc_architecture (result, bfd_scan_arch (\"%s\"));\n",
-	 tdesc_architecture (tdesc)->printable_name);
+    if (ix)
       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)));
-      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 (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");
+  void visit (const tdesc_feature *e) override
+  {
+    printf_unfiltered ("\n  feature = tdesc_create_feature (result, \"%s\");\n",
+		       e->name);
+  }
 
-  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_end (const target_desc *e) override
+  {
+    printf_unfiltered ("\n  tdesc_%s = result;\n", m_function);
+    printf_unfiltered ("}\n");
+  }
 
-  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 (const tdesc_type *type) override
+  {
+    struct tdesc_type_field *f;
 
-      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);
+    /* 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_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)
+		("  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_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++)
+		      ("  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
-		  ("  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");
-	}
+		  ("  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");
-    }
+private:
+  char *m_function;
+  std::string m_filename_after_features;
+  bool m_printed_field_type = false;
+  bool m_printed_type = false;
+};
+
+static void
+maint_print_c_tdesc_cmd (char *args, int from_tty)
+{
+  const struct target_desc *tdesc;
+
+  /* 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."));
+
+  if (target_description_filename == NULL)
+    error (_("The current target description did not come from an XML file."));
+
+  std::string filename_after_features (target_description_filename);
+  auto loc = filename_after_features.rfind ("/features/");
+
+  if (loc != std::string::npos)
+    filename_after_features = filename_after_features.substr (loc + 10);
+
+  print_c_tdesc v (filename_after_features);
 
-  printf_unfiltered ("  tdesc_%s = result;\n", function);
-  printf_unfiltered ("}\n");
+  tdesc->accept (v);
 }
 
 /* Provide a prototype to silence -Wmissing-prototypes.  */