diff --git a/gdb/arch/tdesc.h b/gdb/arch/tdesc.h
index 22da5efa48f8cf5e94c33c9eed4739127467c356..633853447d98c952cfed462939b486afd2738742 100644
--- a/gdb/arch/tdesc.h
+++ b/gdb/arch/tdesc.h
@@ -33,8 +33,6 @@ struct tdesc_reg;
 struct target_desc;
 struct type;

-#ifndef GDBSERVER
-
 /* The interface to visit different elements of target description.  */

 class tdesc_element_visitor
@@ -295,8 +293,6 @@ struct tdesc_arch_reg
   struct type *type;
 };

-#endif
-
 /* Allocate a new target_desc.  */
 target_desc *allocate_target_description (void);

diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 3ce086d70f23df445b174c49c489ec8415d7614a..8ae124875dd08f31e8424b18281cb1454ed40edb 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -194,6 +194,7 @@ SFILES = \
 	$(srcdir)/arch/arm.c \
 	$(srcdir)/arch/arm-get-next-pcs.c \
 	$(srcdir)/arch/arm-linux.c \
+	$(srcdir)/../arch/tdesc.c \
 	$(srcdir)/common/btrace-common.c \
 	$(srcdir)/common/buffer.c \
 	$(srcdir)/common/cleanups.c \
@@ -232,6 +233,7 @@ TAGFILES = $(SOURCES) ${HFILES} ${ALLPARAM} ${POSSLIBS}

 OBS = \
 	agent.o \
+	arch/tdesc.o \
 	ax.o \
 	btrace-common.o \
 	buffer.o \
@@ -391,6 +393,7 @@ gdbreplay$(EXEEXT): $(GDBREPLAY_OBS) $(LIBGNU) $(LIBIBERTY)
 	  $(XM_CLIBS) $(LIBGNU) $(LIBIBERTY)

 IPA_OBJS = \
+	arch/tdesc-ipa.o \
 	ax-ipa.o \
 	common-utils-ipa.o \
 	errors-ipa.o \
diff --git a/gdb/gdbserver/tdesc.h b/gdb/gdbserver/tdesc.h
index 783500598b5599e51f8e768a876fdfe499cdf0ef..499ed0e4598ae812f2d1ceb1fa8e8f1f50c14fff 100644
--- a/gdb/gdbserver/tdesc.h
+++ b/gdb/gdbserver/tdesc.h
@@ -24,13 +24,9 @@
 #include "regdef.h"
 #include <vector>

-struct tdesc_feature
-{};
+/* A target description.  */

-/* A target description.  Inherit from tdesc_feature so that target_desc
-   can be used as tdesc_feature.  */
-
-struct target_desc : tdesc_feature
+struct target_desc : tdesc_element
 {
   /* A vector of elements of register definitions that
      describe the inferior's register set.  */
@@ -52,70 +48,34 @@ struct target_desc : tdesc_feature
      It can be NULL, then, its content is got from the following three
      fields features, arch, and osabi in tdesc_get_features_xml.  */
   const char *xmltarget = NULL;
+#endif

   /* XML features in this target description.  */
-  VEC (char_ptr) *features = NULL;
+  std::vector<tdesc_feature_up> features;

+#ifndef IN_PROCESS_AGENT
   /* The value of <architecture> element in the XML, replying GDB.  */
   const char *arch = NULL;

   /* The value of <osabi> element in the XML, replying GDB.  */
   const char *osabi = NULL;
+#endif

 public:
   target_desc ()
     : registers_size (0)
   {}

-  ~target_desc ()
-  {
-    int i;
-
-    for (reg *reg : reg_defs)
-      xfree (reg);
+  ~target_desc ();

-    xfree ((char *) arch);
-    xfree ((char *) osabi);
+  void accept (tdesc_element_visitor &v) const override;

-    char *f;
-
-    for (i = 0; VEC_iterate (char_ptr, features, i, f); i++)
-      xfree (f);
-    VEC_free (char_ptr, features);
-  }
-
-  bool operator== (const target_desc &other) const
-  {
-    if (reg_defs.size () != other.reg_defs.size ())
-      return false;
-
-    for (int i = 0; i < reg_defs.size (); ++i)
-      {
-	struct reg *reg = reg_defs[i];
-	struct reg *reg2 = other.reg_defs[i];
-
-	if (reg != reg2 && *reg != *reg2)
-	  return false;
-      }
-
-    /* Compare expedite_regs.  */
-    int i = 0;
-    for (; expedite_regs[i] != NULL; i++)
-      {
-	if (strcmp (expedite_regs[i], other.expedite_regs[i]) != 0)
-	  return false;
-      }
-    if (other.expedite_regs[i] != NULL)
-      return false;
-
-    return true;
-  }
+  bool operator== (const target_desc &other) const;

   bool operator!= (const target_desc &other) const
   {
     return !(*this == other);
   }
-#endif
 };

 /* Copy target description SRC to DEST.  */
diff --git a/gdb/gdbserver/tdesc.c b/gdb/gdbserver/tdesc.c
index c39b5e7d27e879c5d3fb49b6e04d1eb6128f8eef..a96b3f07e7aff81f32a160d6498c8012d18bd0c7 100644
--- a/gdb/gdbserver/tdesc.c
+++ b/gdb/gdbserver/tdesc.c
@@ -19,16 +19,78 @@
 #include "tdesc.h"
 #include "regdef.h"

+target_desc::~target_desc ()
+{
+  for (reg *reg : reg_defs)
+    xfree (reg);
+
+#ifndef IN_PROCESS_AGENT
+  xfree ((char *) arch);
+  xfree ((char *) osabi);
+#endif
+}
+
+void target_desc::accept (tdesc_element_visitor &v) const
+{}
+
+bool target_desc::operator== (const target_desc &other) const
+{
+  if (reg_defs.size () != other.reg_defs.size ())
+    return false;
+
+  for (int i = 0; i < reg_defs.size (); ++i)
+    {
+      struct reg *reg = reg_defs[i];
+      struct reg *reg2 = other.reg_defs[i];
+
+      if (reg != reg2 && *reg != *reg2)
+	return false;
+    }
+
+#ifndef IN_PROCESS_AGENT
+  /* Compare expedite_regs.  */
+  int i = 0;
+  for (; expedite_regs[i] != NULL; i++)
+    {
+      if (strcmp (expedite_regs[i], other.expedite_regs[i]) != 0)
+	return false;
+    }
+  if (other.expedite_regs[i] != NULL)
+    return false;
+#endif
+
+  return true;
+}
+
 void
 init_target_desc (struct target_desc *tdesc)
 {
   int offset = 0;

-  for (reg *reg : tdesc->reg_defs)
-    {
-      reg->offset = offset;
-      offset += reg->size;
-    }
+  /* Go through all the features and populate reg_defs.  */
+  for (const tdesc_feature_up &feature : tdesc->features)
+    for (const tdesc_reg_up &treg : feature->registers)
+      {
+	/* Fill in any blank spaces.  */
+	while (tdesc->reg_defs.size () < treg->target_regnum)
+	  {
+	    struct reg *reg = XCNEW (struct reg);
+	    reg->name = "";
+	    reg->size = 0;
+	    reg->offset = offset;
+	    tdesc->reg_defs.push_back (reg);
+	  }
+
+	gdb_assert (treg->target_regnum == 0
+		    || treg->target_regnum == tdesc->reg_defs.size ());
+
+	struct reg *reg = XCNEW (struct reg);
+	reg->name = treg->name.c_str ();
+	reg->size = treg->bitsize;
+	reg->offset = offset;
+	tdesc->reg_defs.push_back (reg);
+	offset += reg->size;
+      }

   tdesc->registers_size = offset / 8;

@@ -91,7 +153,7 @@ tdesc_get_features_xml (target_desc *tdesc)
 {
   /* Either .xmltarget or .features is not NULL.  */
   gdb_assert (tdesc->xmltarget != NULL
-	      || (tdesc->features != NULL
+	      || (!tdesc->features.empty ()
 		  && tdesc->arch != NULL));

   if (tdesc->xmltarget == NULL)
@@ -111,12 +173,10 @@ tdesc_get_features_xml (target_desc *tdesc)
 	  buffer += "</osabi>";
 	}

-      char *xml;
-
-      for (int i = 0; VEC_iterate (char_ptr, tdesc->features, i, xml); i++)
+      for (const tdesc_feature_up &feature : tdesc->features)
 	{
 	  buffer += "<xi:include href=\"";
-	  buffer += xml;
+	  buffer += feature->name;
 	  buffer += "\"/>";
 	}

@@ -129,113 +189,28 @@ tdesc_get_features_xml (target_desc *tdesc)
 }
 #endif

-struct tdesc_type
-{};
-
 /* See arch/tdesc.h.  */

 struct tdesc_feature *
 tdesc_create_feature (struct target_desc *tdesc, const char *name,
 		      const char *xml)
 {
-#ifndef IN_PROCESS_AGENT
-  VEC_safe_push (char_ptr, tdesc->features, xstrdup (xml));
-#endif
-  return tdesc;
-}
-
-/* See arch/tdesc.h.  */
-
-tdesc_type_with_fields *
-tdesc_create_flags (struct tdesc_feature *feature, const char *name,
-		    int size)
-{
-  return NULL;
-}
-
-/* See arch/tdesc.h.  */
-
-void
-tdesc_add_flag (tdesc_type_with_fields *type, int start,
-		const char *flag_name)
-{}
-
-/* See arch/tdesc.h.  */
-
-struct tdesc_type *
-tdesc_named_type (const struct tdesc_feature *feature, const char *id)
-{
-  return NULL;
+  struct tdesc_feature *new_feature = new tdesc_feature (name);
+  tdesc->features.emplace_back (new_feature);
+  return new_feature;
 }

-/* See arch/tdesc.h.  */
-
-tdesc_type_with_fields *
-tdesc_create_union (struct tdesc_feature *feature, const char *id)
+type *tdesc_type_builtin::make_gdb_type (struct gdbarch *gdbarch) const
 {
-  return NULL;
-}
-
-/* See arch/tdesc.h.  */
-
-tdesc_type_with_fields *
-tdesc_create_struct (struct tdesc_feature *feature, const char *id)
-{
-  return NULL;
-}
-
-/* See arch/tdesc.h.  */
-
-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 target_desc *tdesc = (struct target_desc *) feature;
-
-  while (tdesc->reg_defs.size () < regnum)
-    {
-      struct reg *reg = XCNEW (struct reg);
-
-      reg->name = "";
-      reg->size = 0;
-      tdesc->reg_defs.push_back (reg);
-    }
-
-  gdb_assert (regnum == 0
-	      || regnum == tdesc->reg_defs.size ());
-
-  struct reg *reg = XCNEW (struct reg);
-
-  reg->name = name;
-  reg->size = bitsize;
-  tdesc->reg_defs.push_back (reg);
+  error (_("Cannot create gdbtypes."));
 }

-/* See arch/tdesc.h.  */
-
-struct tdesc_type *
-tdesc_create_vector (struct tdesc_feature *feature, const char *name,
-		     struct tdesc_type *field_type, int count)
+type *tdesc_type_vector::make_gdb_type (struct gdbarch *gdbarch) const
 {
-  return NULL;
+  error (_("Cannot create gdbtypes."));
 }

-void
-tdesc_add_bitfield (tdesc_type_with_fields *type, const char *field_name,
-		    int start, int end)
-{}
-
-/* See arch/tdesc.h.  */
-
-void
-tdesc_add_field (tdesc_type_with_fields *type, const char *field_name,
-		 struct tdesc_type *field_type)
-{}
-
-/* See arch/tdesc.h.  */
-
-void
-tdesc_set_struct_size (tdesc_type_with_fields *type, int size)
+type *tdesc_type_with_fields::make_gdb_type (struct gdbarch *gdbarch) const
 {
-}
+  error (_("Cannot create gdbtypes."));
+}
\ No newline at end of file
diff --git a/gdb/regformats/regdat.sh b/gdb/regformats/regdat.sh
index ce1627120d9439082709c82c5804724f39477eb1..8c6e191596350fb4e983f8736985d9832f41e2d3 100755
--- a/gdb/regformats/regdat.sh
+++ b/gdb/regformats/regdat.sh
@@ -131,7 +131,7 @@ do
     echo "{"
     echo "  static struct target_desc tdesc_${name}_s;"
     echo "  struct target_desc *result = &tdesc_${name}_s;"
-
+    echo "  struct tdesc_feature *feature = tdesc_create_feature (result, \"${name}\");"
     continue
   elif test "${type}" = "xmltarget"; then
     xmltarget="${entry}"
@@ -149,7 +149,7 @@ do
     echo "$0: $1 does not specify \`\`name''." 1>&2
     exit 1
   else
-    echo "  tdesc_create_reg ((struct tdesc_feature *) result, \"${entry}\","
+    echo "  tdesc_create_reg (feature, \"${entry}\","
     echo "  0, 0, NULL, ${type}, NULL);"

     offset=`expr ${offset} + ${type}`
