| /* Target description support for GDB. | 
 |  | 
 |    Copyright (C) 2006-2021 Free Software Foundation, Inc. | 
 |  | 
 |    Contributed by CodeSourcery. | 
 |  | 
 |    This file is part of GDB. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include "defs.h" | 
 | #include "arch-utils.h" | 
 | #include "gdbcmd.h" | 
 | #include "gdbtypes.h" | 
 | #include "reggroups.h" | 
 | #include "target.h" | 
 | #include "target-descriptions.h" | 
 | #include "xml-support.h" | 
 | #include "xml-tdesc.h" | 
 | #include "osabi.h" | 
 |  | 
 | #include "gdb_obstack.h" | 
 | #include "hashtab.h" | 
 | #include "inferior.h" | 
 | #include <algorithm> | 
 | #include "completer.h" | 
 | #include "readline/tilde.h" /* tilde_expand */ | 
 |  | 
 | /* Types.  */ | 
 |  | 
 | struct property | 
 | { | 
 |   property (const std::string &key_, const std::string &value_) | 
 |   : key (key_), value (value_) | 
 |   {} | 
 |  | 
 |   std::string key; | 
 |   std::string value; | 
 | }; | 
 |  | 
 | /* Convert a tdesc_type to a gdb type.  */ | 
 |  | 
 | static type * | 
 | make_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *ttype) | 
 | { | 
 |   class gdb_type_creator : public tdesc_element_visitor | 
 |   { | 
 |   public: | 
 |     gdb_type_creator (struct gdbarch *gdbarch) | 
 |       : m_gdbarch (gdbarch) | 
 |     {} | 
 |  | 
 |     type *get_type () | 
 |     { | 
 |       return m_type; | 
 |     } | 
 |  | 
 |     void visit (const tdesc_type_builtin *e) override | 
 |     { | 
 |       switch (e->kind) | 
 | 	{ | 
 | 	  /* Predefined types.  */ | 
 | 	case TDESC_TYPE_BOOL: | 
 | 	  m_type = builtin_type (m_gdbarch)->builtin_bool; | 
 | 	  return; | 
 | 	case TDESC_TYPE_INT8: | 
 | 	  m_type = builtin_type (m_gdbarch)->builtin_int8; | 
 | 	  return; | 
 | 	case TDESC_TYPE_INT16: | 
 | 	  m_type = builtin_type (m_gdbarch)->builtin_int16; | 
 | 	  return; | 
 | 	case TDESC_TYPE_INT32: | 
 | 	  m_type = builtin_type (m_gdbarch)->builtin_int32; | 
 | 	  return; | 
 | 	case TDESC_TYPE_INT64: | 
 | 	  m_type = builtin_type (m_gdbarch)->builtin_int64; | 
 | 	  return; | 
 | 	case TDESC_TYPE_INT128: | 
 | 	  m_type = builtin_type (m_gdbarch)->builtin_int128; | 
 | 	  return; | 
 | 	case TDESC_TYPE_UINT8: | 
 | 	  m_type = builtin_type (m_gdbarch)->builtin_uint8; | 
 | 	  return; | 
 | 	case TDESC_TYPE_UINT16: | 
 | 	  m_type = builtin_type (m_gdbarch)->builtin_uint16; | 
 | 	  return; | 
 | 	case TDESC_TYPE_UINT32: | 
 | 	  m_type = builtin_type (m_gdbarch)->builtin_uint32; | 
 | 	  return; | 
 | 	case TDESC_TYPE_UINT64: | 
 | 	  m_type = builtin_type (m_gdbarch)->builtin_uint64; | 
 | 	  return; | 
 | 	case TDESC_TYPE_UINT128: | 
 | 	  m_type = builtin_type (m_gdbarch)->builtin_uint128; | 
 | 	  return; | 
 | 	case TDESC_TYPE_CODE_PTR: | 
 | 	  m_type = builtin_type (m_gdbarch)->builtin_func_ptr; | 
 | 	  return; | 
 | 	case TDESC_TYPE_DATA_PTR: | 
 | 	  m_type = builtin_type (m_gdbarch)->builtin_data_ptr; | 
 | 	  return; | 
 | 	} | 
 |  | 
 |       m_type = tdesc_find_type (m_gdbarch, e->name.c_str ()); | 
 |       if (m_type != NULL) | 
 | 	return; | 
 |  | 
 |       switch (e->kind) | 
 | 	{ | 
 | 	case TDESC_TYPE_IEEE_HALF: | 
 | 	  m_type = arch_float_type (m_gdbarch, -1, "builtin_type_ieee_half", | 
 | 				    floatformats_ieee_half); | 
 | 	  return; | 
 |  | 
 | 	case TDESC_TYPE_IEEE_SINGLE: | 
 | 	  m_type = arch_float_type (m_gdbarch, -1, "builtin_type_ieee_single", | 
 | 				    floatformats_ieee_single); | 
 | 	  return; | 
 |  | 
 | 	case TDESC_TYPE_IEEE_DOUBLE: | 
 | 	  m_type = arch_float_type (m_gdbarch, -1, "builtin_type_ieee_double", | 
 | 				    floatformats_ieee_double); | 
 | 	  return; | 
 | 	case TDESC_TYPE_ARM_FPA_EXT: | 
 | 	  m_type = arch_float_type (m_gdbarch, -1, "builtin_type_arm_ext", | 
 | 				    floatformats_arm_ext); | 
 | 	  return; | 
 |  | 
 | 	case TDESC_TYPE_I387_EXT: | 
 | 	  m_type = arch_float_type (m_gdbarch, -1, "builtin_type_i387_ext", | 
 | 				    floatformats_i387_ext); | 
 | 	  return; | 
 |  | 
 | 	case TDESC_TYPE_BFLOAT16: | 
 | 	  m_type = arch_float_type (m_gdbarch, -1, "builtin_type_bfloat16", | 
 | 				    floatformats_bfloat16); | 
 | 	  return; | 
 | 	} | 
 |  | 
 |       internal_error (__FILE__, __LINE__, | 
 | 		      "Type \"%s\" has an unknown kind %d", | 
 | 		      e->name.c_str (), e->kind); | 
 |     } | 
 |  | 
 |     void visit (const tdesc_type_vector *e) override | 
 |     { | 
 |       m_type = tdesc_find_type (m_gdbarch, e->name.c_str ()); | 
 |       if (m_type != NULL) | 
 | 	return; | 
 |  | 
 |       type *element_gdb_type = make_gdb_type (m_gdbarch, e->element_type); | 
 |       m_type = init_vector_type (element_gdb_type, e->count); | 
 |       m_type->set_name (xstrdup (e->name.c_str ())); | 
 |       return; | 
 |     } | 
 |  | 
 |     void visit (const tdesc_type_with_fields *e) override | 
 |     { | 
 |       m_type = tdesc_find_type (m_gdbarch, e->name.c_str ()); | 
 |       if (m_type != NULL) | 
 | 	return; | 
 |  | 
 |       switch (e->kind) | 
 | 	{ | 
 | 	case TDESC_TYPE_STRUCT: | 
 | 	  make_gdb_type_struct (e); | 
 | 	  return; | 
 | 	case TDESC_TYPE_UNION: | 
 | 	  make_gdb_type_union (e); | 
 | 	  return; | 
 | 	case TDESC_TYPE_FLAGS: | 
 | 	  make_gdb_type_flags (e); | 
 | 	  return; | 
 | 	case TDESC_TYPE_ENUM: | 
 | 	  make_gdb_type_enum (e); | 
 | 	  return; | 
 | 	} | 
 |  | 
 |       internal_error (__FILE__, __LINE__, | 
 | 		      "Type \"%s\" has an unknown kind %d", | 
 | 		      e->name.c_str (), e->kind); | 
 |     } | 
 |  | 
 |   private: | 
 |  | 
 |     void make_gdb_type_struct (const tdesc_type_with_fields *e) | 
 |     { | 
 |       m_type = arch_composite_type (m_gdbarch, NULL, TYPE_CODE_STRUCT); | 
 |       m_type->set_name (xstrdup (e->name.c_str ())); | 
 |  | 
 |       for (const tdesc_type_field &f : e->fields) | 
 | 	{ | 
 | 	  if (f.start != -1 && f.end != -1) | 
 | 	    { | 
 | 	      /* Bitfield.  */ | 
 | 	      struct field *fld; | 
 | 	      struct type *field_gdb_type; | 
 | 	      int bitsize, total_size; | 
 |  | 
 | 	      /* This invariant should be preserved while creating types.  */ | 
 | 	      gdb_assert (e->size != 0); | 
 | 	      if (f.type != NULL) | 
 | 		field_gdb_type = make_gdb_type (m_gdbarch, f.type); | 
 | 	      else if (e->size > 4) | 
 | 		field_gdb_type = builtin_type (m_gdbarch)->builtin_uint64; | 
 | 	      else | 
 | 		field_gdb_type = builtin_type (m_gdbarch)->builtin_uint32; | 
 |  | 
 | 	      fld = append_composite_type_field_raw | 
 | 		      (m_type, xstrdup (f.name.c_str ()), field_gdb_type); | 
 |  | 
 | 	      /* For little-endian, BITPOS counts from the LSB of | 
 | 		 the structure and marks the LSB of the field.  For | 
 | 		 big-endian, BITPOS counts from the MSB of the | 
 | 		 structure and marks the MSB of the field.  Either | 
 | 		 way, it is the number of bits to the "left" of the | 
 | 		 field.  To calculate this in big-endian, we need | 
 | 		 the total size of the structure.  */ | 
 | 	      bitsize = f.end - f.start + 1; | 
 | 	      total_size = e->size * TARGET_CHAR_BIT; | 
 | 	      if (gdbarch_byte_order (m_gdbarch) == BFD_ENDIAN_BIG) | 
 | 		SET_FIELD_BITPOS (fld[0], total_size - f.start - bitsize); | 
 | 	      else | 
 | 		SET_FIELD_BITPOS (fld[0], f.start); | 
 | 	      FIELD_BITSIZE (fld[0]) = bitsize; | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      gdb_assert (f.start == -1 && f.end == -1); | 
 | 	      type *field_gdb_type = make_gdb_type (m_gdbarch, f.type); | 
 | 	      append_composite_type_field (m_type, | 
 | 					   xstrdup (f.name.c_str ()), | 
 | 					   field_gdb_type); | 
 | 	    } | 
 | 	} | 
 |  | 
 |       if (e->size != 0) | 
 | 	TYPE_LENGTH (m_type) = e->size; | 
 |     } | 
 |  | 
 |     void make_gdb_type_union (const tdesc_type_with_fields *e) | 
 |     { | 
 |       m_type = arch_composite_type (m_gdbarch, NULL, TYPE_CODE_UNION); | 
 |       m_type->set_name (xstrdup (e->name.c_str ())); | 
 |  | 
 |       for (const tdesc_type_field &f : e->fields) | 
 | 	{ | 
 | 	  type* field_gdb_type = make_gdb_type (m_gdbarch, f.type); | 
 | 	  append_composite_type_field (m_type, xstrdup (f.name.c_str ()), | 
 | 				       field_gdb_type); | 
 |  | 
 | 	  /* If any of the children of a union are vectors, flag the | 
 | 	     union as a vector also.  This allows e.g. a union of two | 
 | 	     vector types to show up automatically in "info vector".  */ | 
 | 	  if (field_gdb_type->is_vector ()) | 
 | 	    m_type->set_is_vector (true); | 
 | 	} | 
 |     } | 
 |  | 
 |     void make_gdb_type_flags (const tdesc_type_with_fields *e) | 
 |     { | 
 |       m_type = arch_flags_type (m_gdbarch, e->name.c_str (), | 
 | 				e->size * TARGET_CHAR_BIT); | 
 |  | 
 |       for (const tdesc_type_field &f : e->fields) | 
 | 	{ | 
 | 	  int bitsize = f.end - f.start + 1; | 
 |  | 
 | 	  gdb_assert (f.type != NULL); | 
 | 	  type *field_gdb_type = make_gdb_type (m_gdbarch, f.type); | 
 | 	  append_flags_type_field (m_type, f.start, bitsize, | 
 | 				   field_gdb_type, f.name.c_str ()); | 
 | 	} | 
 |     } | 
 |  | 
 |     void make_gdb_type_enum (const tdesc_type_with_fields *e) | 
 |     { | 
 |       m_type = arch_type (m_gdbarch, TYPE_CODE_ENUM, e->size * TARGET_CHAR_BIT, | 
 | 			  e->name.c_str ()); | 
 |  | 
 |       m_type->set_is_unsigned (true); | 
 |  | 
 |       for (const tdesc_type_field &f : e->fields) | 
 | 	{ | 
 | 	  struct field *fld | 
 | 	    = append_composite_type_field_raw (m_type, | 
 | 					       xstrdup (f.name.c_str ()), | 
 | 					       NULL); | 
 |  | 
 | 	  SET_FIELD_BITPOS (fld[0], f.start); | 
 | 	} | 
 |     } | 
 |  | 
 |     /* The gdbarch used.  */ | 
 |     struct gdbarch *m_gdbarch; | 
 |  | 
 |     /* The type created.  */ | 
 |     type *m_type; | 
 |   }; | 
 |  | 
 |   gdb_type_creator gdb_type (gdbarch); | 
 |   ttype->accept (gdb_type); | 
 |   return gdb_type.get_type (); | 
 | } | 
 |  | 
 | /* Wrapper around bfd_arch_info_type.  A class with this name is used in | 
 |    the API that is shared between gdb and gdbserver code, but gdbserver | 
 |    doesn't use compatibility information, so its version of this class is | 
 |    empty.  */ | 
 |  | 
 | class tdesc_compatible_info | 
 | { | 
 | public: | 
 |   /* Constructor.  */ | 
 |   explicit tdesc_compatible_info (const bfd_arch_info_type *arch) | 
 |     : m_arch (arch) | 
 |   { /* Nothing.  */ } | 
 |  | 
 |   /* Access the contained pointer.  */ | 
 |   const bfd_arch_info_type *arch () const | 
 |   { return m_arch; } | 
 |  | 
 | private: | 
 |   /* Architecture information looked up from the <compatible> entity within | 
 |      a target description.  */ | 
 |   const bfd_arch_info_type *m_arch; | 
 | }; | 
 |  | 
 | /* A target description.  */ | 
 |  | 
 | struct target_desc : tdesc_element | 
 | { | 
 |   target_desc () | 
 |   {} | 
 |  | 
 |   virtual ~target_desc () = default; | 
 |  | 
 |   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 = NULL; | 
 |  | 
 |   /* The osabi reported by the target, if any; GDB_OSABI_UNKNOWN | 
 |      otherwise.  */ | 
 |   enum gdb_osabi osabi = GDB_OSABI_UNKNOWN; | 
 |  | 
 |   /* The list of compatible architectures reported by the target.  */ | 
 |   std::vector<tdesc_compatible_info_up> compatible; | 
 |  | 
 |   /* Any architecture-specific properties specified by the target.  */ | 
 |   std::vector<property> properties; | 
 |  | 
 |   /* The features associated with this target.  */ | 
 |   std::vector<tdesc_feature_up> features; | 
 |  | 
 |   /* Used to cache the generated xml version of the target description.  */ | 
 |   mutable char *xmltarget = nullptr; | 
 |  | 
 |   void accept (tdesc_element_visitor &v) const override | 
 |   { | 
 |     v.visit_pre (this); | 
 |  | 
 |     for (const tdesc_feature_up &feature : features) | 
 |       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 (features.size () != other.features.size ()) | 
 |       return false; | 
 |  | 
 |     for (int ix = 0; ix < features.size (); ix++) | 
 |       { | 
 | 	const tdesc_feature_up &feature1 = features[ix]; | 
 | 	const tdesc_feature_up &feature2 = other.features[ix]; | 
 |  | 
 | 	if (feature1 != feature2 && *feature1 != *feature2) | 
 | 	  return false; | 
 |       } | 
 |  | 
 |     return true; | 
 |   } | 
 |  | 
 |   bool operator!= (const target_desc &other) const | 
 |   { | 
 |     return !(*this == other); | 
 |   } | 
 | }; | 
 |  | 
 | /* Per-architecture data associated with a target description.  The | 
 |    target description may be shared by multiple architectures, but | 
 |    this data is private to one gdbarch.  */ | 
 |  | 
 | struct tdesc_arch_reg | 
 | { | 
 |   tdesc_arch_reg (tdesc_reg *reg_, struct type *type_) | 
 |   : reg (reg_), type (type_) | 
 |   {} | 
 |  | 
 |   struct tdesc_reg *reg; | 
 |   struct type *type; | 
 | }; | 
 |  | 
 | struct tdesc_arch_data | 
 | { | 
 |   /* A list of register/type pairs, indexed by GDB's internal register number. | 
 |      During initialization of the gdbarch this list is used to store | 
 |      registers which the architecture assigns a fixed register number. | 
 |      Registers which are NULL in this array, or off the end, are | 
 |      treated as zero-sized and nameless (i.e. placeholders in the | 
 |      numbering).  */ | 
 |   std::vector<tdesc_arch_reg> arch_regs; | 
 |  | 
 |   /* Functions which report the register name, type, and reggroups for | 
 |      pseudo-registers.  */ | 
 |   gdbarch_register_name_ftype *pseudo_register_name = NULL; | 
 |   gdbarch_register_type_ftype *pseudo_register_type = NULL; | 
 |   gdbarch_register_reggroup_p_ftype *pseudo_register_reggroup_p = NULL; | 
 | }; | 
 |  | 
 | /* Info about an inferior's target description.  There's one of these | 
 |    for each inferior.  */ | 
 |  | 
 | struct target_desc_info | 
 | { | 
 |   /* A flag indicating that a description has already been fetched | 
 |      from the target, so it should not be queried again.  */ | 
 |  | 
 |   bool fetched = false; | 
 |  | 
 |   /* The description fetched from the target, or NULL if the target | 
 |      did not supply any description.  Only valid when | 
 |      FETCHED is set.  Only the description initialization | 
 |      code should access this; normally, the description should be | 
 |      accessed through the gdbarch object.  */ | 
 |  | 
 |   const struct target_desc *tdesc = nullptr; | 
 |  | 
 |   /* If not empty, the filename to read a target description from, as set by | 
 |      "set tdesc filename ...". | 
 |  | 
 |      If empty, there is not filename specified by the user.  */ | 
 |  | 
 |   std::string filename; | 
 | }; | 
 |  | 
 | /* Get the inferior INF's target description info, allocating one on | 
 |    the stop if necessary.  */ | 
 |  | 
 | static struct target_desc_info * | 
 | get_tdesc_info (struct inferior *inf) | 
 | { | 
 |   if (inf->tdesc_info == NULL) | 
 |     inf->tdesc_info = new target_desc_info; | 
 |  | 
 |   return inf->tdesc_info; | 
 | } | 
 |  | 
 | /* A handle for architecture-specific data associated with the | 
 |    target description (see struct tdesc_arch_data).  */ | 
 |  | 
 | static struct gdbarch_data *tdesc_data; | 
 |  | 
 | /* See target-descriptions.h.  */ | 
 |  | 
 | int | 
 | target_desc_info_from_user_p (struct target_desc_info *info) | 
 | { | 
 |   return info != nullptr && !info->filename.empty (); | 
 | } | 
 |  | 
 | /* See target-descriptions.h.  */ | 
 |  | 
 | void | 
 | copy_inferior_target_desc_info (struct inferior *destinf, struct inferior *srcinf) | 
 | { | 
 |   struct target_desc_info *src = get_tdesc_info (srcinf); | 
 |   struct target_desc_info *dest = get_tdesc_info (destinf); | 
 |  | 
 |   *dest = *src; | 
 | } | 
 |  | 
 | /* See target-descriptions.h.  */ | 
 |  | 
 | void | 
 | target_desc_info_free (struct target_desc_info *tdesc_info) | 
 | { | 
 |   delete tdesc_info; | 
 | } | 
 |  | 
 | /* The string manipulated by the "set tdesc filename ..." command.  */ | 
 |  | 
 | static char *tdesc_filename_cmd_string; | 
 |  | 
 | /* Fetch the current target's description, and switch the current | 
 |    architecture to one which incorporates that description.  */ | 
 |  | 
 | void | 
 | target_find_description (void) | 
 | { | 
 |   target_desc_info *tdesc_info = get_tdesc_info (current_inferior ()); | 
 |  | 
 |   /* If we've already fetched a description from the target, don't do | 
 |      it again.  This allows a target to fetch the description early, | 
 |      during its to_open or to_create_inferior, if it needs extra | 
 |      information about the target to initialize.  */ | 
 |   if (tdesc_info->fetched) | 
 |     return; | 
 |  | 
 |   /* The current architecture should not have any target description | 
 |      specified.  It should have been cleared, e.g. when we | 
 |      disconnected from the previous target.  */ | 
 |   gdb_assert (gdbarch_target_desc (target_gdbarch ()) == NULL); | 
 |  | 
 |   /* First try to fetch an XML description from the user-specified | 
 |      file.  */ | 
 |   tdesc_info->tdesc = nullptr; | 
 |   if (!tdesc_info->filename.empty ()) | 
 |     tdesc_info->tdesc = file_read_description_xml (tdesc_info->filename.data ()); | 
 |  | 
 |   /* Next try to read the description from the current target using | 
 |      target objects.  */ | 
 |   if (tdesc_info->tdesc == nullptr) | 
 |     tdesc_info->tdesc = target_read_description_xml | 
 |       (current_inferior ()->top_target ()); | 
 |  | 
 |   /* If that failed try a target-specific hook.  */ | 
 |   if (tdesc_info->tdesc == nullptr) | 
 |     tdesc_info->tdesc = target_read_description | 
 |       (current_inferior ()->top_target ()); | 
 |  | 
 |   /* If a non-NULL description was returned, then update the current | 
 |      architecture.  */ | 
 |   if (tdesc_info->tdesc != nullptr) | 
 |     { | 
 |       struct gdbarch_info info; | 
 |  | 
 |       info.target_desc = tdesc_info->tdesc; | 
 |       if (!gdbarch_update_p (info)) | 
 | 	warning (_("Architecture rejected target-supplied description")); | 
 |       else | 
 | 	{ | 
 | 	  struct tdesc_arch_data *data; | 
 |  | 
 | 	  data = ((struct tdesc_arch_data *) | 
 | 		  gdbarch_data (target_gdbarch (), tdesc_data)); | 
 | 	  if (tdesc_has_registers (tdesc_info->tdesc) | 
 | 	      && data->arch_regs.empty ()) | 
 | 	    warning (_("Target-supplied registers are not supported " | 
 | 		       "by the current architecture")); | 
 | 	} | 
 |     } | 
 |  | 
 |   /* Now that we know this description is usable, record that we | 
 |      fetched it.  */ | 
 |   tdesc_info->fetched = true; | 
 | } | 
 |  | 
 | /* Discard any description fetched from the current target, and switch | 
 |    the current architecture to one with no target description.  */ | 
 |  | 
 | void | 
 | target_clear_description (void) | 
 | { | 
 |   target_desc_info *tdesc_info = get_tdesc_info (current_inferior ()); | 
 |  | 
 |   if (!tdesc_info->fetched) | 
 |     return; | 
 |  | 
 |   tdesc_info->fetched = false; | 
 |   tdesc_info->tdesc = nullptr; | 
 |  | 
 |   gdbarch_info info; | 
 |   if (!gdbarch_update_p (info)) | 
 |     internal_error (__FILE__, __LINE__, | 
 | 		    _("Could not remove target-supplied description")); | 
 | } | 
 |  | 
 | /* Return the global current target description.  This should only be | 
 |    used by gdbarch initialization code; most access should be through | 
 |    an existing gdbarch.  */ | 
 |  | 
 | const struct target_desc * | 
 | target_current_description (void) | 
 | { | 
 |   target_desc_info *tdesc_info = get_tdesc_info (current_inferior ()); | 
 |  | 
 |   if (tdesc_info->fetched) | 
 |     return tdesc_info->tdesc; | 
 |  | 
 |   return NULL; | 
 | } | 
 |  | 
 | /* Return non-zero if this target description is compatible | 
 |    with the given BFD architecture.  */ | 
 |  | 
 | int | 
 | tdesc_compatible_p (const struct target_desc *target_desc, | 
 | 		    const struct bfd_arch_info *arch) | 
 | { | 
 |   for (const tdesc_compatible_info_up &compat : target_desc->compatible) | 
 |     { | 
 |       if (compat->arch () == arch | 
 | 	  || arch->compatible (arch, compat->arch ()) | 
 | 	  || compat->arch ()->compatible (compat->arch (), arch)) | 
 | 	return 1; | 
 |     } | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 |  | 
 | /* Direct accessors for target descriptions.  */ | 
 |  | 
 | /* Return the string value of a property named KEY, or NULL if the | 
 |    property was not specified.  */ | 
 |  | 
 | const char * | 
 | tdesc_property (const struct target_desc *target_desc, const char *key) | 
 | { | 
 |   for (const property &prop : target_desc->properties) | 
 |     if (prop.key == key) | 
 |       return prop.value.c_str (); | 
 |  | 
 |   return NULL; | 
 | } | 
 |  | 
 | /* Return the BFD architecture associated with this target | 
 |    description, or NULL if no architecture was specified.  */ | 
 |  | 
 | const struct bfd_arch_info * | 
 | tdesc_architecture (const struct target_desc *target_desc) | 
 | { | 
 |   return target_desc->arch; | 
 | } | 
 |  | 
 | /* See gdbsupport/tdesc.h.  */ | 
 |  | 
 | const char * | 
 | tdesc_architecture_name (const struct target_desc *target_desc) | 
 | { | 
 |   if (target_desc->arch != NULL) | 
 |     return target_desc->arch->printable_name; | 
 |   return NULL; | 
 | } | 
 |  | 
 | /* See gdbsupport/tdesc.h.  */ | 
 |  | 
 | const std::vector<tdesc_compatible_info_up> & | 
 | tdesc_compatible_info_list (const target_desc *target_desc) | 
 | { | 
 |   return target_desc->compatible; | 
 | } | 
 |  | 
 | /* See gdbsupport/tdesc.h.  */ | 
 |  | 
 | const char * | 
 | tdesc_compatible_info_arch_name (const tdesc_compatible_info_up &compatible) | 
 | { | 
 |   return compatible->arch ()->printable_name; | 
 | } | 
 |  | 
 | /* Return the OSABI associated with this target description, or | 
 |    GDB_OSABI_UNKNOWN if no osabi was specified.  */ | 
 |  | 
 | enum gdb_osabi | 
 | tdesc_osabi (const struct target_desc *target_desc) | 
 | { | 
 |   return target_desc->osabi; | 
 | } | 
 |  | 
 | /* See gdbsupport/tdesc.h.  */ | 
 |  | 
 | const char * | 
 | tdesc_osabi_name (const struct target_desc *target_desc) | 
 | { | 
 |   enum gdb_osabi osabi = tdesc_osabi (target_desc); | 
 |   if (osabi > GDB_OSABI_UNKNOWN && osabi < GDB_OSABI_INVALID) | 
 |     return gdbarch_osabi_name (osabi); | 
 |   return nullptr; | 
 | } | 
 |  | 
 | /* Return 1 if this target description includes any registers.  */ | 
 |  | 
 | int | 
 | tdesc_has_registers (const struct target_desc *target_desc) | 
 | { | 
 |   if (target_desc == NULL) | 
 |     return 0; | 
 |  | 
 |   for (const tdesc_feature_up &feature : target_desc->features) | 
 |     if (!feature->registers.empty ()) | 
 |       return 1; | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | /* Return the feature with the given name, if present, or NULL if | 
 |    the named feature is not found.  */ | 
 |  | 
 | const struct tdesc_feature * | 
 | tdesc_find_feature (const struct target_desc *target_desc, | 
 | 		    const char *name) | 
 | { | 
 |   for (const tdesc_feature_up &feature : target_desc->features) | 
 |     if (feature->name == name) | 
 |       return feature.get (); | 
 |  | 
 |   return NULL; | 
 | } | 
 |  | 
 | /* Return the name of FEATURE.  */ | 
 |  | 
 | const char * | 
 | tdesc_feature_name (const struct tdesc_feature *feature) | 
 | { | 
 |   return feature->name.c_str (); | 
 | } | 
 |  | 
 | /* Lookup type associated with ID.  */ | 
 |  | 
 | struct type * | 
 | tdesc_find_type (struct gdbarch *gdbarch, const char *id) | 
 | { | 
 |   tdesc_arch_data *data | 
 |     = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); | 
 |  | 
 |   for (const tdesc_arch_reg ® : data->arch_regs) | 
 |     { | 
 |       if (reg.reg | 
 | 	  && reg.reg->tdesc_type | 
 | 	  && reg.type | 
 | 	  && reg.reg->tdesc_type->name == id) | 
 | 	return reg.type; | 
 |     } | 
 |  | 
 |   return NULL; | 
 | } | 
 |  | 
 | /* Support for registers from target descriptions.  */ | 
 |  | 
 | /* Construct the per-gdbarch data.  */ | 
 |  | 
 | static void * | 
 | tdesc_data_init (struct obstack *obstack) | 
 | { | 
 |   return obstack_new<tdesc_arch_data> (obstack); | 
 | } | 
 |  | 
 | /* Similar, but for the temporary copy used during architecture | 
 |    initialization.  */ | 
 |  | 
 | tdesc_arch_data_up | 
 | tdesc_data_alloc (void) | 
 | { | 
 |   return tdesc_arch_data_up (new tdesc_arch_data ()); | 
 | } | 
 |  | 
 | /* See target-descriptions.h.  */ | 
 |  | 
 | void | 
 | tdesc_arch_data_deleter::operator() (struct tdesc_arch_data *data) const | 
 | { | 
 |   delete data; | 
 | } | 
 |  | 
 | /* Search FEATURE for a register named NAME.  */ | 
 |  | 
 | static struct tdesc_reg * | 
 | tdesc_find_register_early (const struct tdesc_feature *feature, | 
 | 			   const char *name) | 
 | { | 
 |   for (const tdesc_reg_up ® : feature->registers) | 
 |     if (strcasecmp (reg->name.c_str (), name) == 0) | 
 |       return reg.get (); | 
 |  | 
 |   return NULL; | 
 | } | 
 |  | 
 | /* Search FEATURE for a register named NAME.  Assign REGNO to it.  */ | 
 |  | 
 | int | 
 | tdesc_numbered_register (const struct tdesc_feature *feature, | 
 | 			 struct tdesc_arch_data *data, | 
 | 			 int regno, const char *name) | 
 | { | 
 |   struct tdesc_reg *reg = tdesc_find_register_early (feature, name); | 
 |  | 
 |   if (reg == NULL) | 
 |     return 0; | 
 |  | 
 |   /* Make sure the vector includes a REGNO'th element.  */ | 
 |   while (regno >= data->arch_regs.size ()) | 
 |     data->arch_regs.emplace_back (nullptr, nullptr); | 
 |  | 
 |   data->arch_regs[regno] = tdesc_arch_reg (reg, NULL); | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 | /* Search FEATURE for a register named NAME, but do not assign a fixed | 
 |    register number to it.  */ | 
 |  | 
 | int | 
 | tdesc_unnumbered_register (const struct tdesc_feature *feature, | 
 | 			   const char *name) | 
 | { | 
 |   struct tdesc_reg *reg = tdesc_find_register_early (feature, name); | 
 |  | 
 |   if (reg == NULL) | 
 |     return 0; | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 | /* Search FEATURE for a register whose name is in NAMES and assign | 
 |    REGNO to it.  */ | 
 |  | 
 | int | 
 | tdesc_numbered_register_choices (const struct tdesc_feature *feature, | 
 | 				 struct tdesc_arch_data *data, | 
 | 				 int regno, const char *const names[]) | 
 | { | 
 |   int i; | 
 |  | 
 |   for (i = 0; names[i] != NULL; i++) | 
 |     if (tdesc_numbered_register (feature, data, regno, names[i])) | 
 |       return 1; | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | /* Search FEATURE for a register named NAME, and return its size in | 
 |    bits.  The register must exist.  */ | 
 |  | 
 | int | 
 | tdesc_register_bitsize (const struct tdesc_feature *feature, const char *name) | 
 | { | 
 |   struct tdesc_reg *reg = tdesc_find_register_early (feature, name); | 
 |  | 
 |   gdb_assert (reg != NULL); | 
 |   return reg->bitsize; | 
 | } | 
 |  | 
 | /* Look up a register by its GDB internal register number.  */ | 
 |  | 
 | static struct tdesc_arch_reg * | 
 | tdesc_find_arch_register (struct gdbarch *gdbarch, int regno) | 
 | { | 
 |   struct tdesc_arch_data *data; | 
 |  | 
 |   data = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); | 
 |   if (regno < data->arch_regs.size ()) | 
 |     return &data->arch_regs[regno]; | 
 |   else | 
 |     return NULL; | 
 | } | 
 |  | 
 | static struct tdesc_reg * | 
 | tdesc_find_register (struct gdbarch *gdbarch, int regno) | 
 | { | 
 |   struct tdesc_arch_reg *reg = tdesc_find_arch_register (gdbarch, regno); | 
 |  | 
 |   return reg? reg->reg : NULL; | 
 | } | 
 |  | 
 | /* Return the name of register REGNO, from the target description or | 
 |    from an architecture-provided pseudo_register_name method.  */ | 
 |  | 
 | const char * | 
 | tdesc_register_name (struct gdbarch *gdbarch, int regno) | 
 | { | 
 |   struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno); | 
 |   int num_regs = gdbarch_num_regs (gdbarch); | 
 |  | 
 |   if (reg != NULL) | 
 |     return reg->name.c_str (); | 
 |  | 
 |   if (regno >= num_regs && regno < gdbarch_num_cooked_regs (gdbarch)) | 
 |     { | 
 |       struct tdesc_arch_data *data | 
 | 	= (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); | 
 |  | 
 |       gdb_assert (data->pseudo_register_name != NULL); | 
 |       return data->pseudo_register_name (gdbarch, regno); | 
 |     } | 
 |  | 
 |   return ""; | 
 | } | 
 |  | 
 | struct type * | 
 | tdesc_register_type (struct gdbarch *gdbarch, int regno) | 
 | { | 
 |   struct tdesc_arch_reg *arch_reg = tdesc_find_arch_register (gdbarch, regno); | 
 |   struct tdesc_reg *reg = arch_reg? arch_reg->reg : NULL; | 
 |   int num_regs = gdbarch_num_regs (gdbarch); | 
 |   int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch); | 
 |  | 
 |   if (reg == NULL && regno >= num_regs && regno < num_regs + num_pseudo_regs) | 
 |     { | 
 |       struct tdesc_arch_data *data | 
 | 	= (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); | 
 |  | 
 |       gdb_assert (data->pseudo_register_type != NULL); | 
 |       return data->pseudo_register_type (gdbarch, regno); | 
 |     } | 
 |  | 
 |   if (reg == NULL) | 
 |     /* Return "int0_t", since "void" has a misleading size of one.  */ | 
 |     return builtin_type (gdbarch)->builtin_int0; | 
 |  | 
 |   if (arch_reg->type == NULL) | 
 |     { | 
 |       /* First check for a predefined or target defined type.  */ | 
 |       if (reg->tdesc_type) | 
 | 	arch_reg->type = make_gdb_type (gdbarch, reg->tdesc_type); | 
 |  | 
 |       /* Next try size-sensitive type shortcuts.  */ | 
 |       else if (reg->type == "float") | 
 | 	{ | 
 | 	  if (reg->bitsize == gdbarch_float_bit (gdbarch)) | 
 | 	    arch_reg->type = builtin_type (gdbarch)->builtin_float; | 
 | 	  else if (reg->bitsize == gdbarch_double_bit (gdbarch)) | 
 | 	    arch_reg->type = builtin_type (gdbarch)->builtin_double; | 
 | 	  else if (reg->bitsize == gdbarch_long_double_bit (gdbarch)) | 
 | 	    arch_reg->type = builtin_type (gdbarch)->builtin_long_double; | 
 | 	  else | 
 | 	    { | 
 | 	      warning (_("Register \"%s\" has an unsupported size (%d bits)"), | 
 | 		       reg->name.c_str (), reg->bitsize); | 
 | 	      arch_reg->type = builtin_type (gdbarch)->builtin_double; | 
 | 	    } | 
 | 	} | 
 |       else if (reg->type == "int") | 
 | 	{ | 
 | 	  if (reg->bitsize == gdbarch_long_bit (gdbarch)) | 
 | 	    arch_reg->type = builtin_type (gdbarch)->builtin_long; | 
 | 	  else if (reg->bitsize == TARGET_CHAR_BIT) | 
 | 	    arch_reg->type = builtin_type (gdbarch)->builtin_char; | 
 | 	  else if (reg->bitsize == gdbarch_short_bit (gdbarch)) | 
 | 	    arch_reg->type = builtin_type (gdbarch)->builtin_short; | 
 | 	  else if (reg->bitsize == gdbarch_int_bit (gdbarch)) | 
 | 	    arch_reg->type = builtin_type (gdbarch)->builtin_int; | 
 | 	  else if (reg->bitsize == gdbarch_long_long_bit (gdbarch)) | 
 | 	    arch_reg->type = builtin_type (gdbarch)->builtin_long_long; | 
 | 	  else if (reg->bitsize == gdbarch_ptr_bit (gdbarch)) | 
 | 	  /* A bit desperate by this point...  */ | 
 | 	    arch_reg->type = builtin_type (gdbarch)->builtin_data_ptr; | 
 | 	  else | 
 | 	    { | 
 | 	      warning (_("Register \"%s\" has an unsupported size (%d bits)"), | 
 | 		       reg->name.c_str (), reg->bitsize); | 
 | 	      arch_reg->type = builtin_type (gdbarch)->builtin_long; | 
 | 	    } | 
 | 	} | 
 |  | 
 |       if (arch_reg->type == NULL) | 
 | 	internal_error (__FILE__, __LINE__, | 
 | 			"Register \"%s\" has an unknown type \"%s\"", | 
 | 			reg->name.c_str (), reg->type.c_str ()); | 
 |     } | 
 |  | 
 |   return arch_reg->type; | 
 | } | 
 |  | 
 | static int | 
 | tdesc_remote_register_number (struct gdbarch *gdbarch, int regno) | 
 | { | 
 |   struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno); | 
 |  | 
 |   if (reg != NULL) | 
 |     return reg->target_regnum; | 
 |   else | 
 |     return -1; | 
 | } | 
 |  | 
 | /* Check whether REGNUM is a member of REGGROUP.  Registers from the | 
 |    target description may be classified as general, float, vector or other | 
 |    register groups registered with reggroup_add().  Unlike a gdbarch | 
 |    register_reggroup_p method, this function will return -1 if it does not | 
 |    know; the caller should handle registers with no specified group. | 
 |  | 
 |    The names of containing features are not used.  This might be extended | 
 |    to display registers in some more useful groupings. | 
 |  | 
 |    The save-restore flag is also implemented here.  */ | 
 |  | 
 | int | 
 | tdesc_register_in_reggroup_p (struct gdbarch *gdbarch, int regno, | 
 | 			      struct reggroup *reggroup) | 
 | { | 
 |   struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno); | 
 |  | 
 |   if (reg != NULL && !reg->group.empty () | 
 |       && (reg->group == reggroup_name (reggroup))) | 
 | 	return 1; | 
 |  | 
 |   if (reg != NULL | 
 |       && (reggroup == save_reggroup || reggroup == restore_reggroup)) | 
 |     return reg->save_restore; | 
 |  | 
 |   return -1; | 
 | } | 
 |  | 
 | /* Check whether REGNUM is a member of REGGROUP.  Registers with no | 
 |    group specified go to the default reggroup function and are handled | 
 |    by type.  */ | 
 |  | 
 | static int | 
 | tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regno, | 
 | 			   struct reggroup *reggroup) | 
 | { | 
 |   int num_regs = gdbarch_num_regs (gdbarch); | 
 |   int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch); | 
 |   int ret; | 
 |  | 
 |   if (regno >= num_regs && regno < num_regs + num_pseudo_regs) | 
 |     { | 
 |       struct tdesc_arch_data *data | 
 | 	= (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); | 
 |  | 
 |       if (data->pseudo_register_reggroup_p != NULL) | 
 | 	return data->pseudo_register_reggroup_p (gdbarch, regno, reggroup); | 
 |       /* Otherwise fall through to the default reggroup_p.  */ | 
 |     } | 
 |  | 
 |   ret = tdesc_register_in_reggroup_p (gdbarch, regno, reggroup); | 
 |   if (ret != -1) | 
 |     return ret; | 
 |  | 
 |   return default_register_reggroup_p (gdbarch, regno, reggroup); | 
 | } | 
 |  | 
 | /* Record architecture-specific functions to call for pseudo-register | 
 |    support.  */ | 
 |  | 
 | void | 
 | set_tdesc_pseudo_register_name (struct gdbarch *gdbarch, | 
 | 				gdbarch_register_name_ftype *pseudo_name) | 
 | { | 
 |   struct tdesc_arch_data *data | 
 |     = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); | 
 |  | 
 |   data->pseudo_register_name = pseudo_name; | 
 | } | 
 |  | 
 | void | 
 | set_tdesc_pseudo_register_type (struct gdbarch *gdbarch, | 
 | 				gdbarch_register_type_ftype *pseudo_type) | 
 | { | 
 |   struct tdesc_arch_data *data | 
 |     = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); | 
 |  | 
 |   data->pseudo_register_type = pseudo_type; | 
 | } | 
 |  | 
 | void | 
 | set_tdesc_pseudo_register_reggroup_p | 
 |   (struct gdbarch *gdbarch, | 
 |    gdbarch_register_reggroup_p_ftype *pseudo_reggroup_p) | 
 | { | 
 |   struct tdesc_arch_data *data | 
 |     = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); | 
 |  | 
 |   data->pseudo_register_reggroup_p = pseudo_reggroup_p; | 
 | } | 
 |  | 
 | /* Update GDBARCH to use the target description for registers.  */ | 
 |  | 
 | void | 
 | tdesc_use_registers (struct gdbarch *gdbarch, | 
 | 		     const struct target_desc *target_desc, | 
 | 		     tdesc_arch_data_up &&early_data, | 
 | 		     tdesc_unknown_register_ftype unk_reg_cb) | 
 | { | 
 |   int num_regs = gdbarch_num_regs (gdbarch); | 
 |   struct tdesc_arch_data *data; | 
 |  | 
 |   /* We can't use the description for registers if it doesn't describe | 
 |      any.  This function should only be called after validating | 
 |      registers, so the caller should know that registers are | 
 |      included.  */ | 
 |   gdb_assert (tdesc_has_registers (target_desc)); | 
 |  | 
 |   data = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); | 
 |   data->arch_regs = std::move (early_data->arch_regs); | 
 |  | 
 |   /* Build up a set of all registers, so that we can assign register | 
 |      numbers where needed.  The hash table expands as necessary, so | 
 |      the initial size is arbitrary.  */ | 
 |   htab_up reg_hash (htab_create (37, htab_hash_pointer, htab_eq_pointer, | 
 | 				 NULL)); | 
 |   for (const tdesc_feature_up &feature : target_desc->features) | 
 |     for (const tdesc_reg_up ® : feature->registers) | 
 |       { | 
 | 	void **slot = htab_find_slot (reg_hash.get (), reg.get (), INSERT); | 
 |  | 
 | 	*slot = reg.get (); | 
 | 	/* Add reggroup if its new.  */ | 
 | 	if (!reg->group.empty ()) | 
 | 	  if (reggroup_find (gdbarch, reg->group.c_str ()) == NULL) | 
 | 	    reggroup_add (gdbarch, reggroup_gdbarch_new (gdbarch, | 
 | 							 reg->group.c_str (), | 
 | 							 USER_REGGROUP)); | 
 |       } | 
 |  | 
 |   /* Remove any registers which were assigned numbers by the | 
 |      architecture.  */ | 
 |   for (const tdesc_arch_reg &arch_reg : data->arch_regs) | 
 |     if (arch_reg.reg != NULL) | 
 |       htab_remove_elt (reg_hash.get (), arch_reg.reg); | 
 |  | 
 |   /* Assign numbers to the remaining registers and add them to the | 
 |      list of registers.  The new numbers are always above gdbarch_num_regs. | 
 |      Iterate over the features, not the hash table, so that the order | 
 |      matches that in the target description.  */ | 
 |  | 
 |   gdb_assert (data->arch_regs.size () <= num_regs); | 
 |   while (data->arch_regs.size () < num_regs) | 
 |     data->arch_regs.emplace_back (nullptr, nullptr); | 
 |  | 
 |   /* First we give the target a chance to number previously unknown | 
 |      registers.  This allows targets to record the numbers assigned based | 
 |      on which feature the register was from.  */ | 
 |   if (unk_reg_cb != NULL) | 
 |     { | 
 |       for (const tdesc_feature_up &feature : target_desc->features) | 
 | 	for (const tdesc_reg_up ® : feature->registers) | 
 | 	  if (htab_find (reg_hash.get (), reg.get ()) != NULL) | 
 | 	    { | 
 | 	      int regno = unk_reg_cb (gdbarch, feature.get (), | 
 | 				      reg->name.c_str (), num_regs); | 
 | 	      gdb_assert (regno == -1 || regno >= num_regs); | 
 | 	      if (regno != -1) | 
 | 		{ | 
 | 		  while (regno >= data->arch_regs.size ()) | 
 | 		    data->arch_regs.emplace_back (nullptr, nullptr); | 
 | 		  data->arch_regs[regno] = tdesc_arch_reg (reg.get (), NULL); | 
 | 		  num_regs = regno + 1; | 
 | 		  htab_remove_elt (reg_hash.get (), reg.get ()); | 
 | 		} | 
 | 	    } | 
 |     } | 
 |  | 
 |   /* Ensure the array was sized correctly above.  */ | 
 |   gdb_assert (data->arch_regs.size () == num_regs); | 
 |  | 
 |   /* Now in a final pass we assign register numbers to any remaining | 
 |      unnumbered registers.  */ | 
 |   for (const tdesc_feature_up &feature : target_desc->features) | 
 |     for (const tdesc_reg_up ® : feature->registers) | 
 |       if (htab_find (reg_hash.get (), reg.get ()) != NULL) | 
 | 	{ | 
 | 	  data->arch_regs.emplace_back (reg.get (), nullptr); | 
 | 	  num_regs++; | 
 | 	} | 
 |  | 
 |   /* Update the architecture.  */ | 
 |   set_gdbarch_num_regs (gdbarch, num_regs); | 
 |   set_gdbarch_register_name (gdbarch, tdesc_register_name); | 
 |   set_gdbarch_register_type (gdbarch, tdesc_register_type); | 
 |   set_gdbarch_remote_register_number (gdbarch, | 
 | 				      tdesc_remote_register_number); | 
 |   set_gdbarch_register_reggroup_p (gdbarch, tdesc_register_reggroup_p); | 
 | } | 
 |  | 
 | /* See gdbsupport/tdesc.h.  */ | 
 |  | 
 | struct tdesc_feature * | 
 | tdesc_create_feature (struct target_desc *tdesc, const char *name) | 
 | { | 
 |   struct tdesc_feature *new_feature = new tdesc_feature (name); | 
 |  | 
 |   tdesc->features.emplace_back (new_feature); | 
 |  | 
 |   return new_feature; | 
 | } | 
 |  | 
 | /* See gdbsupport/tdesc.h.  */ | 
 |  | 
 | target_desc_up | 
 | allocate_target_description (void) | 
 | { | 
 |   return target_desc_up (new target_desc ()); | 
 | } | 
 |  | 
 | /* See gdbsupport/tdesc.h.  */ | 
 |  | 
 | void | 
 | target_desc_deleter::operator() (struct target_desc *target_desc) const | 
 | { | 
 |   delete target_desc; | 
 | } | 
 |  | 
 | void | 
 | tdesc_add_compatible (struct target_desc *target_desc, | 
 | 		      const struct bfd_arch_info *compatible) | 
 | { | 
 |   /* If this instance of GDB is compiled without BFD support for the | 
 |      compatible architecture, simply ignore it -- we would not be able | 
 |      to handle it anyway.  */ | 
 |   if (compatible == NULL) | 
 |     return; | 
 |  | 
 |   for (const tdesc_compatible_info_up &compat : target_desc->compatible) | 
 |     if (compat->arch () == compatible) | 
 |       internal_error (__FILE__, __LINE__, | 
 | 		      _("Attempted to add duplicate " | 
 | 			"compatible architecture \"%s\""), | 
 | 		      compatible->printable_name); | 
 |  | 
 |   target_desc->compatible.push_back | 
 |     (std::unique_ptr<tdesc_compatible_info> | 
 |      (new tdesc_compatible_info (compatible))); | 
 | } | 
 |  | 
 | void | 
 | set_tdesc_property (struct target_desc *target_desc, | 
 | 		    const char *key, const char *value) | 
 | { | 
 |   gdb_assert (key != NULL && value != NULL); | 
 |  | 
 |   if (tdesc_property (target_desc, key) != NULL) | 
 |     internal_error (__FILE__, __LINE__, | 
 | 		    _("Attempted to add duplicate property \"%s\""), key); | 
 |  | 
 |   target_desc->properties.emplace_back (key, value); | 
 | } | 
 |  | 
 | /* See gdbsupport/tdesc.h.  */ | 
 |  | 
 | void | 
 | set_tdesc_architecture (struct target_desc *target_desc, | 
 | 			const char *name) | 
 | { | 
 |   set_tdesc_architecture (target_desc, bfd_scan_arch (name)); | 
 | } | 
 |  | 
 | void | 
 | set_tdesc_architecture (struct target_desc *target_desc, | 
 | 			const struct bfd_arch_info *arch) | 
 | { | 
 |   target_desc->arch = arch; | 
 | } | 
 |  | 
 | /* See gdbsupport/tdesc.h.  */ | 
 |  | 
 | void | 
 | set_tdesc_osabi (struct target_desc *target_desc, const char *name) | 
 | { | 
 |   set_tdesc_osabi (target_desc, osabi_from_tdesc_string (name)); | 
 | } | 
 |  | 
 | void | 
 | set_tdesc_osabi (struct target_desc *target_desc, enum gdb_osabi osabi) | 
 | { | 
 |   target_desc->osabi = osabi; | 
 | } | 
 |  | 
 |  | 
 | static struct cmd_list_element *tdesc_set_cmdlist, *tdesc_show_cmdlist; | 
 | static struct cmd_list_element *tdesc_unset_cmdlist; | 
 |  | 
 | /* Helper functions for the CLI commands.  */ | 
 |  | 
 | static void | 
 | set_tdesc_filename_cmd (const char *args, int from_tty, | 
 | 			struct cmd_list_element *c) | 
 | { | 
 |   target_desc_info *tdesc_info = get_tdesc_info (current_inferior ()); | 
 |  | 
 |   tdesc_info->filename = tdesc_filename_cmd_string; | 
 |  | 
 |   target_clear_description (); | 
 |   target_find_description (); | 
 | } | 
 |  | 
 | static void | 
 | show_tdesc_filename_cmd (struct ui_file *file, int from_tty, | 
 | 			 struct cmd_list_element *c, | 
 | 			 const char *value) | 
 | { | 
 |   value = get_tdesc_info (current_inferior ())->filename.data (); | 
 |  | 
 |   if (value != NULL && *value != '\0') | 
 |     printf_filtered (_("The target description will be read from \"%s\".\n"), | 
 | 		     value); | 
 |   else | 
 |     printf_filtered (_("The target description will be " | 
 | 		       "read from the target.\n")); | 
 | } | 
 |  | 
 | static void | 
 | unset_tdesc_filename_cmd (const char *args, int from_tty) | 
 | { | 
 |   target_desc_info *tdesc_info = get_tdesc_info (current_inferior ()); | 
 |  | 
 |   tdesc_info->filename.clear (); | 
 |   target_clear_description (); | 
 |   target_find_description (); | 
 | } | 
 |  | 
 | /* Print target description in C.  */ | 
 |  | 
 | class print_c_tdesc : public tdesc_element_visitor | 
 | { | 
 | 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 ()); | 
 |  | 
 |     m_function = (char *) xmalloc (strlen (filename) + 1); | 
 |     for (inp = filename, outp = m_function; *inp != '\0'; inp++) | 
 |       if (*inp == '.') | 
 | 	break; | 
 |       else if (*inp == '-') | 
 | 	*outp++ = '_'; | 
 |       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"); | 
 |   } | 
 |  | 
 |   ~print_c_tdesc () | 
 |   { | 
 |     xfree (m_function); | 
 |   } | 
 |  | 
 |   void visit_pre (const target_desc *e) override | 
 |   { | 
 |     printf_unfiltered ("  Original: %s */\n\n", | 
 | 		       lbasename (m_filename_after_features.c_str ())); | 
 |  | 
 |     printf_unfiltered ("#include \"defs.h\"\n"); | 
 |     printf_unfiltered ("#include \"osabi.h\"\n"); | 
 |     printf_unfiltered ("#include \"target-descriptions.h\"\n"); | 
 |     printf_unfiltered ("\n"); | 
 |  | 
 |     printf_unfiltered ("struct target_desc *tdesc_%s;\n", m_function); | 
 |     printf_unfiltered ("static void\n"); | 
 |     printf_unfiltered ("initialize_tdesc_%s (void)\n", m_function); | 
 |     printf_unfiltered ("{\n"); | 
 |     printf_unfiltered | 
 |       ("  target_desc_up result = allocate_target_description ();\n"); | 
 |  | 
 |     if (tdesc_architecture (e) != NULL) | 
 |       { | 
 | 	printf_unfiltered | 
 | 	  ("  set_tdesc_architecture (result.get (), 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.get (), osabi_from_tdesc_string (\"%s\"));\n", | 
 | 	   gdbarch_osabi_name (tdesc_osabi (e))); | 
 | 	printf_unfiltered ("\n"); | 
 |       } | 
 |  | 
 |     for (const tdesc_compatible_info_up &compatible : e->compatible) | 
 |       printf_unfiltered | 
 | 	("  tdesc_add_compatible (result.get (), bfd_scan_arch (\"%s\"));\n", | 
 | 	 compatible->arch ()->printable_name); | 
 |  | 
 |     if (!e->compatible.empty ()) | 
 |       printf_unfiltered ("\n"); | 
 |  | 
 |     for (const property &prop : e->properties) | 
 |       printf_unfiltered ("  set_tdesc_property (result.get (), \"%s\", \"%s\");\n", | 
 | 			 prop.key.c_str (), prop.value.c_str ()); | 
 |  | 
 |     printf_unfiltered ("  struct tdesc_feature *feature;\n"); | 
 |   } | 
 |  | 
 |   void visit_pre (const tdesc_feature *e) override | 
 |   { | 
 |     printf_unfiltered ("\n  feature = tdesc_create_feature (result.get (), \"%s\");\n", | 
 | 		       e->name.c_str ()); | 
 |   } | 
 |  | 
 |   void visit_post (const tdesc_feature *e) override | 
 |   {} | 
 |  | 
 |   void visit_post (const target_desc *e) override | 
 |   { | 
 |     printf_unfiltered ("\n  tdesc_%s = result.release ();\n", m_function); | 
 |     printf_unfiltered ("}\n"); | 
 |   } | 
 |  | 
 |   void visit (const tdesc_type_builtin *type) override | 
 |   { | 
 |     error (_("C output is not supported type \"%s\"."), type->name.c_str ()); | 
 |   } | 
 |  | 
 |   void visit (const tdesc_type_vector *type) override | 
 |   { | 
 |     if (!m_printed_element_type) | 
 |       { | 
 | 	printf_unfiltered ("  tdesc_type *element_type;\n"); | 
 | 	m_printed_element_type = true; | 
 |       } | 
 |  | 
 |     printf_unfiltered | 
 |       ("  element_type = tdesc_named_type (feature, \"%s\");\n", | 
 |        type->element_type->name.c_str ()); | 
 |     printf_unfiltered | 
 |       ("  tdesc_create_vector (feature, \"%s\", element_type, %d);\n", | 
 |        type->name.c_str (), type->count); | 
 |  | 
 |     printf_unfiltered ("\n"); | 
 |   } | 
 |  | 
 |   void visit (const tdesc_type_with_fields *type) override | 
 |   { | 
 |     if (!m_printed_type_with_fields) | 
 |       { | 
 | 	printf_unfiltered ("  tdesc_type_with_fields *type_with_fields;\n"); | 
 | 	m_printed_type_with_fields = true; | 
 |       } | 
 |  | 
 |     switch (type->kind) | 
 |       { | 
 |       case TDESC_TYPE_STRUCT: | 
 |       case TDESC_TYPE_FLAGS: | 
 | 	if (type->kind == TDESC_TYPE_STRUCT) | 
 | 	  { | 
 | 	    printf_unfiltered | 
 | 	      ("  type_with_fields = tdesc_create_struct (feature, \"%s\");\n", | 
 | 	       type->name.c_str ()); | 
 | 	    if (type->size != 0) | 
 | 	      printf_unfiltered | 
 | 		("  tdesc_set_struct_size (type_with_fields, %d);\n", type->size); | 
 | 	  } | 
 | 	else | 
 | 	  { | 
 | 	    printf_unfiltered | 
 | 	      ("  type_with_fields = tdesc_create_flags (feature, \"%s\", %d);\n", | 
 | 	       type->name.c_str (), type->size); | 
 | 	  } | 
 | 	for (const tdesc_type_field &f : type->fields) | 
 | 	  { | 
 | 	    const char *type_name; | 
 |  | 
 | 	    gdb_assert (f.type != NULL); | 
 | 	    type_name = f.type->name.c_str (); | 
 |  | 
 | 	    /* 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_with_fields, %d, \"%s\");\n", | 
 | 		       f.start, f.name.c_str ()); | 
 | 		  } | 
 | 		else if ((type->size == 4 && f.type->kind == TDESC_TYPE_UINT32) | 
 | 			 || (type->size == 8 | 
 | 			     && f.type->kind == TDESC_TYPE_UINT64)) | 
 | 		  { | 
 | 		    printf_unfiltered | 
 | 		      ("  tdesc_add_bitfield (type_with_fields, \"%s\", %d, %d);\n", | 
 | 		       f.name.c_str (), f.start, f.end); | 
 | 		  } | 
 | 		else | 
 | 		  { | 
 | 		    printf_field_type_assignment | 
 | 		      ("tdesc_named_type (feature, \"%s\");\n", | 
 | 		       type_name); | 
 | 		    printf_unfiltered | 
 | 		      ("  tdesc_add_typed_bitfield (type_with_fields, \"%s\"," | 
 | 		       " %d, %d, field_type);\n", | 
 | 		       f.name.c_str (), f.start, f.end); | 
 | 		  } | 
 | 	      } | 
 | 	    else /* Not a bitfield.  */ | 
 | 	      { | 
 | 		gdb_assert (f.end == -1); | 
 | 		gdb_assert (type->kind == TDESC_TYPE_STRUCT); | 
 | 		printf_field_type_assignment | 
 | 		  ("tdesc_named_type (feature, \"%s\");\n", type_name); | 
 | 		printf_unfiltered | 
 | 		  ("  tdesc_add_field (type_with_fields, \"%s\", field_type);\n", | 
 | 		   f.name.c_str ()); | 
 | 	      } | 
 | 	  } | 
 | 	break; | 
 |       case TDESC_TYPE_UNION: | 
 | 	printf_unfiltered | 
 | 	  ("  type_with_fields = tdesc_create_union (feature, \"%s\");\n", | 
 | 	   type->name.c_str ()); | 
 | 	for (const tdesc_type_field &f : type->fields) | 
 | 	  { | 
 | 	    printf_field_type_assignment | 
 | 	      ("tdesc_named_type (feature, \"%s\");\n", f.type->name.c_str ()); | 
 | 	    printf_unfiltered | 
 | 	      ("  tdesc_add_field (type_with_fields, \"%s\", field_type);\n", | 
 | 	       f.name.c_str ()); | 
 | 	  } | 
 | 	break; | 
 |       case TDESC_TYPE_ENUM: | 
 | 	printf_unfiltered | 
 | 	  ("  type_with_fields = tdesc_create_enum (feature, \"%s\", %d);\n", | 
 | 	   type->name.c_str (), type->size); | 
 | 	for (const tdesc_type_field &f : type->fields) | 
 | 	  printf_unfiltered | 
 | 	    ("  tdesc_add_enum_value (type_with_fields, %d, \"%s\");\n", | 
 | 	     f.start, f.name.c_str ()); | 
 | 	break; | 
 |       default: | 
 | 	error (_("C output is not supported type \"%s\"."), type->name.c_str ()); | 
 |       } | 
 |  | 
 |     printf_unfiltered ("\n"); | 
 |   } | 
 |  | 
 |   void visit (const tdesc_reg *reg) override | 
 |   { | 
 |     printf_unfiltered ("  tdesc_create_reg (feature, \"%s\", %ld, %d, ", | 
 | 		       reg->name.c_str (), reg->target_regnum, | 
 | 		       reg->save_restore); | 
 |     if (!reg->group.empty ()) | 
 |       printf_unfiltered ("\"%s\", ", reg->group.c_str ()); | 
 |     else | 
 |       printf_unfiltered ("NULL, "); | 
 |     printf_unfiltered ("%d, \"%s\");\n", reg->bitsize, reg->type.c_str ()); | 
 |   } | 
 |  | 
 | protected: | 
 |   std::string m_filename_after_features; | 
 |  | 
 | private: | 
 |  | 
 |   /* Print an assignment to the field_type variable.  Print the declaration | 
 |      of field_type if that has not been done yet.  */ | 
 |   ATTRIBUTE_PRINTF (2, 3) | 
 |   void printf_field_type_assignment (const char *fmt, ...) | 
 |   { | 
 |     if (!m_printed_field_type) | 
 |       { | 
 | 	printf_unfiltered ("  tdesc_type *field_type;\n"); | 
 | 	m_printed_field_type = true; | 
 |       } | 
 |  | 
 |     printf_unfiltered ("  field_type = "); | 
 |  | 
 |     va_list args; | 
 |     va_start (args, fmt); | 
 |     vprintf_unfiltered (fmt, args); | 
 |     va_end (args); | 
 |   } | 
 |  | 
 |   char *m_function; | 
 |  | 
 |   /* Did we print "struct tdesc_type *element_type;" yet?  */ | 
 |   bool m_printed_element_type = false; | 
 |  | 
 |   /* Did we print "struct tdesc_type_with_fields *element_type;" yet?  */ | 
 |   bool m_printed_type_with_fields = false; | 
 |  | 
 |   /* Did we print "struct tdesc_type *field_type;" yet?  */ | 
 |   bool m_printed_field_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 \"gdbsupport/tdesc.h\"\n"); | 
 |     printf_unfiltered ("\n"); | 
 |   } | 
 |  | 
 |   void visit_post (const target_desc *e) override | 
 |   {} | 
 |  | 
 |   void visit_pre (const tdesc_feature *e) override | 
 |   { | 
 |     std::string name (m_filename_after_features); | 
 |  | 
 |     auto pos = name.find_first_of ('.'); | 
 |  | 
 |     name = name.substr (0, pos); | 
 |     std::replace (name.begin (), name.end (), '/', '_'); | 
 |     std::replace (name.begin (), name.end (), '-', '_'); | 
 |  | 
 |     printf_unfiltered ("static int\n"); | 
 |     printf_unfiltered ("create_feature_%s ", name.c_str ()); | 
 |     printf_unfiltered ("(struct target_desc *result, long regnum)\n"); | 
 |  | 
 |     printf_unfiltered ("{\n"); | 
 |     printf_unfiltered ("  struct tdesc_feature *feature;\n"); | 
 |  | 
 |     printf_unfiltered | 
 |       ("\n  feature = tdesc_create_feature (result, \"%s\");\n", | 
 |        e->name.c_str ()); | 
 |   } | 
 |  | 
 |   void visit_post (const tdesc_feature *e) override | 
 |   { | 
 |     printf_unfiltered ("  return regnum;\n"); | 
 |     printf_unfiltered ("}\n"); | 
 |   } | 
 |  | 
 |   void visit (const tdesc_reg *reg) override | 
 |   { | 
 |     /* Most "reg" in XML target descriptions don't have "regnum" | 
 |        attribute, so the register number is allocated sequentially. | 
 |        In case that reg has "regnum" attribute, register number | 
 |        should be set by that explicitly.  */ | 
 |  | 
 |     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.c_str (), reg->save_restore); | 
 |     if (!reg->group.empty ()) | 
 |       printf_unfiltered ("\"%s\", ", reg->group.c_str ()); | 
 |     else | 
 |       printf_unfiltered ("NULL, "); | 
 |     printf_unfiltered ("%d, \"%s\");\n", reg->bitsize, reg->type.c_str ()); | 
 |  | 
 |     m_next_regnum++; | 
 |   } | 
 |  | 
 | private: | 
 |   /* The register number to use for the next register we see.  */ | 
 |   int m_next_regnum = 0; | 
 | }; | 
 |  | 
 | /* See gdbsupport/tdesc.h.  */ | 
 |  | 
 | const char * | 
 | tdesc_get_features_xml (const target_desc *tdesc) | 
 | { | 
 |   if (tdesc->xmltarget == nullptr) | 
 |     { | 
 |       std::string buffer ("@"); | 
 |       print_xml_feature v (&buffer); | 
 |       tdesc->accept (v); | 
 |       tdesc->xmltarget = xstrdup (buffer.c_str ()); | 
 |     } | 
 |   return tdesc->xmltarget; | 
 | } | 
 |  | 
 | /* Data structures and functions to setup the option flags for 'maintenance | 
 |    print c-tdesc command.  */ | 
 |  | 
 | struct maint_print_c_tdesc_options | 
 | { | 
 |   /* True when the '-single-feature' flag was passed.  */ | 
 |   bool single_feature = false; | 
 | }; | 
 |  | 
 | using maint_print_c_tdesc_opt_def | 
 |   = gdb::option::flag_option_def<maint_print_c_tdesc_options>; | 
 |  | 
 | static const gdb::option::option_def maint_print_c_tdesc_opt_defs[] = { | 
 |   maint_print_c_tdesc_opt_def { | 
 |     "single-feature", | 
 |     [] (maint_print_c_tdesc_options *opt) { return &opt->single_feature; }, | 
 |     N_("Print C description of just a single feature.") | 
 |   }, | 
 | }; | 
 |  | 
 | static inline gdb::option::option_def_group | 
 | make_maint_print_c_tdesc_options_def_group (maint_print_c_tdesc_options *opts) | 
 | { | 
 |   return {{maint_print_c_tdesc_opt_defs}, opts}; | 
 | } | 
 |  | 
 | /* Implement 'maintenance print c-tdesc' command.  */ | 
 |  | 
 | static void | 
 | maint_print_c_tdesc_cmd (const char *args, int from_tty) | 
 | { | 
 |   const struct target_desc *tdesc; | 
 |   const char *filename; | 
 |  | 
 |   maint_print_c_tdesc_options opts; | 
 |   auto grp = make_maint_print_c_tdesc_options_def_group (&opts); | 
 |   gdb::option::process_options | 
 |     (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp); | 
 |  | 
 |   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.  */ | 
 |       target_desc_info *tdesc_info = get_tdesc_info (current_inferior ()); | 
 |       tdesc = tdesc_info->tdesc; | 
 |       filename = tdesc_info->filename.data (); | 
 |     } | 
 |   else | 
 |     { | 
 |       /* Use the target description from the XML file.  */ | 
 |       filename = args; | 
 |       tdesc = file_read_description_xml (filename); | 
 |     } | 
 |  | 
 |   if (tdesc == NULL) | 
 |     error (_("There is no target description to print.")); | 
 |  | 
 |   if (filename == NULL) | 
 |     filename = "fetched from target"; | 
 |  | 
 |   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 (opts.single_feature) | 
 |     { | 
 |       if (tdesc->features.size () != 1) | 
 | 	error (_("only target descriptions with 1 feature can be used " | 
 | 		 "with -single-feature option")); | 
 |  | 
 |       print_c_feature v (filename_after_features); | 
 |  | 
 |       tdesc->accept (v); | 
 |     } | 
 |   else | 
 |     { | 
 |       print_c_tdesc v (filename_after_features); | 
 |  | 
 |       tdesc->accept (v); | 
 |     } | 
 | } | 
 |  | 
 | /* Completer for the "backtrace" command.  */ | 
 |  | 
 | static void | 
 | maint_print_c_tdesc_cmd_completer (struct cmd_list_element *ignore, | 
 | 				   completion_tracker &tracker, | 
 | 				   const char *text, const char *word) | 
 | { | 
 |   auto grp = make_maint_print_c_tdesc_options_def_group (nullptr); | 
 |   if (gdb::option::complete_options | 
 |       (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp)) | 
 |     return; | 
 |  | 
 |   word = advance_to_filename_complete_word_point (tracker, text); | 
 |   filename_completer (ignore, tracker, text, word); | 
 | } | 
 |  | 
 | /* Implement the maintenance print xml-tdesc command.  */ | 
 |  | 
 | static void | 
 | maint_print_xml_tdesc_cmd (const char *args, int from_tty) | 
 | { | 
 |   const struct target_desc *tdesc; | 
 |  | 
 |   if (args == NULL) | 
 |     { | 
 |       /* Use the global target-supplied description, not the current | 
 | 	 architecture's.  This lets a GDB for one architecture generate XML | 
 | 	 for another architecture's description, even though the gdbarch | 
 | 	 initialization code will reject the new description.  */ | 
 |       tdesc = get_tdesc_info (current_inferior ())->tdesc; | 
 |     } | 
 |   else | 
 |     { | 
 |       /* Use the target description from the XML file.  */ | 
 |       tdesc = file_read_description_xml (args); | 
 |     } | 
 |  | 
 |   if (tdesc == NULL) | 
 |     error (_("There is no target description to print.")); | 
 |  | 
 |   std::string buf; | 
 |   print_xml_feature v (&buf); | 
 |   tdesc->accept (v); | 
 |   puts_unfiltered (buf.c_str ()); | 
 | } | 
 |  | 
 | namespace selftests { | 
 |  | 
 | /* A reference target description, used for testing (see record_xml_tdesc).  */ | 
 |  | 
 | struct xml_test_tdesc | 
 | { | 
 |   xml_test_tdesc (const char *name, std::unique_ptr<const target_desc> &&tdesc) | 
 |     : name (name), tdesc (std::move (tdesc)) | 
 |   {} | 
 |  | 
 |   const char *name; | 
 |   std::unique_ptr<const target_desc> tdesc; | 
 | }; | 
 |  | 
 | static std::vector<xml_test_tdesc> xml_tdesc; | 
 |  | 
 | #if GDB_SELF_TEST | 
 |  | 
 | /* See target-descriptions.h.  */ | 
 |  | 
 | void | 
 | record_xml_tdesc (const char *xml_file, const struct target_desc *tdesc) | 
 | { | 
 |   xml_tdesc.emplace_back (xml_file, std::unique_ptr<const target_desc> (tdesc)); | 
 | } | 
 | #endif | 
 |  | 
 | } | 
 |  | 
 | /* Test the conversion process of a target description to/from xml: Take a target | 
 |    description TDESC, convert to xml, back to a description, and confirm the new | 
 |    tdesc is identical to the original.  */ | 
 | static bool | 
 | maintenance_check_tdesc_xml_convert (const target_desc *tdesc, const char *name) | 
 | { | 
 |   const char *xml = tdesc_get_features_xml (tdesc); | 
 |  | 
 |   if (xml == nullptr || *xml != '@') | 
 |     { | 
 |       printf_filtered (_("Could not convert description for %s to xml.\n"), | 
 | 		       name); | 
 |       return false; | 
 |     } | 
 |  | 
 |   const target_desc *tdesc_trans = string_read_description_xml (xml + 1); | 
 |  | 
 |   if (tdesc_trans == nullptr) | 
 |     { | 
 |       printf_filtered (_("Could not convert description for %s from xml.\n"), | 
 | 		       name); | 
 |       return false; | 
 |     } | 
 |   else if (*tdesc != *tdesc_trans) | 
 |     { | 
 |       printf_filtered (_("Converted description for %s does not match.\n"), | 
 | 		       name); | 
 |       return false; | 
 |     } | 
 |   return true; | 
 | } | 
 |  | 
 |  | 
 | /* Check that the target descriptions created dynamically by | 
 |    architecture-specific code equal the descriptions created from XML files | 
 |    found in the specified directory DIR.  */ | 
 |  | 
 | static void | 
 | maintenance_check_xml_descriptions (const 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.name); | 
 |       const target_desc *tdesc | 
 | 	= file_read_description_xml (tdesc_xml.data ()); | 
 |  | 
 |       if (tdesc == NULL || *tdesc != *e.tdesc) | 
 | 	{ | 
 | 	  printf_filtered ( _("Descriptions for %s do not match.\n"), e.name); | 
 | 	  failed++; | 
 | 	} | 
 |       else if (!maintenance_check_tdesc_xml_convert (tdesc, e.name) | 
 | 	       || !maintenance_check_tdesc_xml_convert (e.tdesc.get (), e.name)) | 
 | 	failed++; | 
 |     } | 
 |   printf_filtered (_("Tested %lu XML files, %d failed\n"), | 
 | 		   (long) selftests::xml_tdesc.size (), failed); | 
 | } | 
 |  | 
 | void _initialize_target_descriptions (); | 
 | void | 
 | _initialize_target_descriptions () | 
 | { | 
 |   cmd_list_element *cmd; | 
 |  | 
 |   tdesc_data = gdbarch_data_register_pre_init (tdesc_data_init); | 
 |  | 
 |   add_basic_prefix_cmd ("tdesc", class_maintenance, _("\ | 
 | Set target description specific variables."), | 
 | 			&tdesc_set_cmdlist, | 
 | 			0 /* allow-unknown */, &setlist); | 
 |   add_show_prefix_cmd ("tdesc", class_maintenance, _("\ | 
 | Show target description specific variables."), | 
 | 		       &tdesc_show_cmdlist, | 
 | 		       0 /* allow-unknown */, &showlist); | 
 |   add_basic_prefix_cmd ("tdesc", class_maintenance, _("\ | 
 | Unset target description specific variables."), | 
 | 			&tdesc_unset_cmdlist, | 
 | 			0 /* allow-unknown */, &unsetlist); | 
 |  | 
 |   add_setshow_filename_cmd ("filename", class_obscure, | 
 | 			    &tdesc_filename_cmd_string, | 
 | 			    _("\ | 
 | Set the file to read for an XML target description."), _("\ | 
 | Show the file to read for an XML target description."), _("\ | 
 | When set, GDB will read the target description from a local\n\ | 
 | file instead of querying the remote target."), | 
 | 			    set_tdesc_filename_cmd, | 
 | 			    show_tdesc_filename_cmd, | 
 | 			    &tdesc_set_cmdlist, &tdesc_show_cmdlist); | 
 |  | 
 |   add_cmd ("filename", class_obscure, unset_tdesc_filename_cmd, _("\ | 
 | Unset the file to read for an XML target description.\n\ | 
 | When unset, GDB will read the description from the target."), | 
 | 	   &tdesc_unset_cmdlist); | 
 |  | 
 |   auto grp = make_maint_print_c_tdesc_options_def_group (nullptr); | 
 |   static std::string help_text | 
 |     = gdb::option::build_help (_("\ | 
 | Print the current target description as a C source file.\n\ | 
 | Usage: maintenance print c-tdesc [OPTION] [FILENAME]\n\ | 
 | \n\ | 
 | Options:\n\ | 
 | %OPTIONS%\n\ | 
 | \n\ | 
 | When FILENAME is not provided then print the current target\n\ | 
 | description, otherwise an XML target description is read from\n\ | 
 | FILENAME and printed as a C function.\n\ | 
 | \n\ | 
 | When '-single-feature' is used then the target description should\n\ | 
 | contain a single feature and the generated C code will only create\n\ | 
 | that feature within an already existing target_desc object."), grp); | 
 |   cmd = add_cmd ("c-tdesc", class_maintenance, maint_print_c_tdesc_cmd, | 
 | 		 help_text.c_str (), &maintenanceprintlist); | 
 |   set_cmd_completer_handle_brkchars (cmd, maint_print_c_tdesc_cmd_completer); | 
 |  | 
 |   cmd = add_cmd ("xml-tdesc", class_maintenance, maint_print_xml_tdesc_cmd, _("\ | 
 | Print the current target description as an XML file."), | 
 | 		 &maintenanceprintlist); | 
 |   set_cmd_completer (cmd, filename_completer); | 
 |  | 
 |   cmd = add_cmd ("xml-descriptions", class_maintenance, | 
 | 		 maintenance_check_xml_descriptions, _("\ | 
 | Check equality of GDB target descriptions and XML created descriptions.\n\ | 
 | 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); | 
 | } |