X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=gdb%2Ftarget-descriptions.c;h=248edd51bd13e160bab682612d78d043125874ab;hb=3666a04883754298b03884222206bfe756fbc520;hp=d6a0f9dccf7fcce49be550e9a51f5622eee46845;hpb=618f726fcb851883a0094aa7fa17003889b7189f;p=thirdparty%2Fbinutils-gdb.git diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c index d6a0f9dccf7..248edd51bd1 100644 --- a/gdb/target-descriptions.c +++ b/gdb/target-descriptions.c @@ -1,6 +1,6 @@ /* Target description support for GDB. - Copyright (C) 2006-2016 Free Software Foundation, Inc. + Copyright (C) 2006-2021 Free Software Foundation, Inc. Contributed by CodeSourcery. @@ -26,7 +26,6 @@ #include "reggroups.h" #include "target.h" #include "target-descriptions.h" -#include "vec.h" #include "xml-support.h" #include "xml-tdesc.h" #include "osabi.h" @@ -34,187 +33,393 @@ #include "gdb_obstack.h" #include "hashtab.h" #include "inferior.h" +#include +#include "completer.h" +#include "readline/tilde.h" /* tilde_expand */ /* Types. */ -typedef struct property -{ - char *key; - char *value; -} property_s; -DEF_VEC_O(property_s); - -/* An individual register from a target description. */ - -typedef struct tdesc_reg -{ - /* The name of this register. In standard features, it may be - recognized by the architecture support code, or it may be purely - for the user. */ - char *name; - - /* The register number used by this target to refer to this - register. This is used for remote p/P packets and to determine - the ordering of registers in the remote g/G packets. */ - long target_regnum; - - /* If this flag is set, GDB should save and restore this register - around calls to an inferior function. */ - int save_restore; - - /* The name of the register group containing this register, or NULL - if the group should be automatically determined from the - register's type. If this is "general", "float", or "vector", the - corresponding "info" command should display this register's - value. It can be an arbitrary string, but should be limited to - alphanumeric characters and internal hyphens. Currently other - strings are ignored (treated as NULL). */ - char *group; - - /* The size of the register, in bits. */ - int bitsize; - - /* The type of the register. This string corresponds to either - a named type from the target description or a predefined - type from GDB. */ - char *type; - - /* The target-described type corresponding to TYPE, if found. */ - struct tdesc_type *tdesc_type; -} *tdesc_reg_p; -DEF_VEC_P(tdesc_reg_p); - -/* A named type from a target description. */ - -typedef struct tdesc_type_field -{ - char *name; - struct tdesc_type *type; - int start, end; -} tdesc_type_field; -DEF_VEC_O(tdesc_type_field); - -typedef struct tdesc_type_flag -{ - char *name; - int start; -} tdesc_type_flag; -DEF_VEC_O(tdesc_type_flag); - -enum tdesc_type_kind -{ - /* Predefined types. */ - TDESC_TYPE_INT8, - TDESC_TYPE_INT16, - TDESC_TYPE_INT32, - TDESC_TYPE_INT64, - TDESC_TYPE_INT128, - TDESC_TYPE_UINT8, - TDESC_TYPE_UINT16, - TDESC_TYPE_UINT32, - TDESC_TYPE_UINT64, - TDESC_TYPE_UINT128, - TDESC_TYPE_CODE_PTR, - TDESC_TYPE_DATA_PTR, - TDESC_TYPE_IEEE_SINGLE, - TDESC_TYPE_IEEE_DOUBLE, - TDESC_TYPE_ARM_FPA_EXT, - TDESC_TYPE_I387_EXT, - - /* Types defined by a target feature. */ - TDESC_TYPE_VECTOR, - TDESC_TYPE_STRUCT, - TDESC_TYPE_UNION, - TDESC_TYPE_FLAGS +struct property +{ + property (const std::string &key_, const std::string &value_) + : key (key_), value (value_) + {} + + std::string key; + std::string value; }; -typedef struct tdesc_type +/* Convert a tdesc_type to a gdb type. */ + +static type * +make_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *ttype) { - /* The name of this type. */ - char *name; + class gdb_type_creator : public tdesc_element_visitor + { + public: + gdb_type_creator (struct gdbarch *gdbarch) + : m_gdbarch (gdbarch) + {} - /* Identify the kind of this type. */ - enum tdesc_type_kind kind; + type *get_type () + { + return m_type; + } - /* Kind-specific data. */ - union - { - /* Vector type. */ - struct + void visit (const tdesc_type_builtin *e) override { - struct tdesc_type *type; - int count; - } v; + 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); + } - /* Struct or union type. */ - struct + void visit (const tdesc_type_vector *e) override { - VEC(tdesc_type_field) *fields; - LONGEST size; - } u; + 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; + } - /* Flags type. */ - struct + void visit (const tdesc_type_with_fields *e) override { - VEC(tdesc_type_flag) *flags; - LONGEST size; - } f; - } u; -} *tdesc_type_p; -DEF_VEC_P(tdesc_type_p); + m_type = tdesc_find_type (m_gdbarch, e->name.c_str ()); + if (m_type != NULL) + return; -/* A feature from a target description. Each feature is a collection - of other elements, e.g. registers and types. */ + 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; + } -typedef struct tdesc_feature -{ - /* The name of this feature. It may be recognized by the architecture - support code. */ - char *name; + 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 ()); + } + } - /* The registers associated with this feature. */ - VEC(tdesc_reg_p) *registers; + 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 types associated with this feature. */ - VEC(tdesc_type_p) *types; -} *tdesc_feature_p; -DEF_VEC_P(tdesc_feature_p); + /* The type created. */ + type *m_type; + }; -/* A compatible architecture from a target description. */ -typedef const struct bfd_arch_info *arch_p; -DEF_VEC_P(arch_p); + 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 entity within + a target description. */ + const bfd_arch_info_type *m_arch; +}; /* A target description. */ -struct target_desc +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; + 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; + std::vector compatible; /* Any architecture-specific properties specified by the target. */ - VEC(property_s) *properties; + std::vector properties; /* The features associated with this target. */ - VEC(tdesc_feature_p) *features; + std::vector 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. */ -typedef struct tdesc_arch_reg +struct tdesc_arch_reg { + tdesc_arch_reg (tdesc_reg *reg_, struct type *type_) + : reg (reg_), type (type_) + {} + struct tdesc_reg *reg; struct type *type; -} tdesc_arch_reg; -DEF_VEC_O(tdesc_arch_reg); +}; struct tdesc_arch_data { @@ -224,13 +429,13 @@ struct tdesc_arch_data Registers which are NULL in this array, or off the end, are treated as zero-sized and nameless (i.e. placeholders in the numbering). */ - VEC(tdesc_arch_reg) *arch_regs; + std::vector arch_regs; /* Functions which report the register name, type, and reggroups for pseudo-registers. */ - gdbarch_register_name_ftype *pseudo_register_name; - gdbarch_register_type_ftype *pseudo_register_type; - gdbarch_register_reggroup_p_ftype *pseudo_register_reggroup_p; + 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 @@ -348,11 +553,11 @@ target_find_description (void) /* Next try to read the description from the current target using target objects. */ if (current_target_desc == NULL) - current_target_desc = target_read_description_xml (¤t_target); + current_target_desc = target_read_description_xml (current_top_target ()); /* If that failed try a target-specific hook. */ if (current_target_desc == NULL) - current_target_desc = target_read_description (¤t_target); + current_target_desc = target_read_description (current_top_target ()); /* If a non-NULL description was returned, then update the current architecture. */ @@ -371,7 +576,7 @@ target_find_description (void) data = ((struct tdesc_arch_data *) gdbarch_data (target_gdbarch (), tdesc_data)); if (tdesc_has_registers (current_target_desc) - && data->arch_regs == NULL) + && data->arch_regs.empty ()) warning (_("Target-supplied registers are not supported " "by the current architecture")); } @@ -422,15 +627,11 @@ int tdesc_compatible_p (const struct target_desc *target_desc, const struct bfd_arch_info *arch) { - const struct bfd_arch_info *compat; - int ix; - - for (ix = 0; VEC_iterate (arch_p, target_desc->compatible, ix, compat); - ix++) + for (const tdesc_compatible_info_up &compat : target_desc->compatible) { - if (compat == arch - || arch->compatible (arch, compat) - || compat->compatible (compat, arch)) + if (compat->arch () == arch + || arch->compatible (arch, compat->arch ()) + || compat->arch ()->compatible (compat->arch (), arch)) return 1; } @@ -446,13 +647,9 @@ tdesc_compatible_p (const struct target_desc *target_desc, const char * tdesc_property (const struct target_desc *target_desc, const char *key) { - struct property *prop; - int ix; - - for (ix = 0; VEC_iterate (property_s, target_desc->properties, ix, prop); - ix++) - if (strcmp (prop->key, key) == 0) - return prop->value; + for (const property &prop : target_desc->properties) + if (prop.key == key) + return prop.value.c_str (); return NULL; } @@ -466,6 +663,32 @@ 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_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. */ @@ -475,23 +698,27 @@ 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) { - int ix; - struct tdesc_feature *feature; - if (target_desc == NULL) return 0; - for (ix = 0; - VEC_iterate (tdesc_feature_p, target_desc->features, ix, feature); - ix++) - if (! VEC_empty (tdesc_reg_p, feature->registers)) + for (const tdesc_feature_up &feature : target_desc->features) + if (!feature->registers.empty ()) return 1; return 0; @@ -504,14 +731,9 @@ const struct tdesc_feature * tdesc_find_feature (const struct target_desc *target_desc, const char *name) { - int ix; - struct tdesc_feature *feature; - - for (ix = 0; - VEC_iterate (tdesc_feature_p, target_desc->features, ix, feature); - ix++) - if (strcmp (feature->name, name) == 0) - return feature; + for (const tdesc_feature_up &feature : target_desc->features) + if (feature->name == name) + return feature.get (); return NULL; } @@ -521,50 +743,7 @@ tdesc_find_feature (const struct target_desc *target_desc, const char * tdesc_feature_name (const struct tdesc_feature *feature) { - return feature->name; -} - -/* Predefined types. */ -static struct tdesc_type tdesc_predefined_types[] = -{ - { "int8", TDESC_TYPE_INT8 }, - { "int16", TDESC_TYPE_INT16 }, - { "int32", TDESC_TYPE_INT32 }, - { "int64", TDESC_TYPE_INT64 }, - { "int128", TDESC_TYPE_INT128 }, - { "uint8", TDESC_TYPE_UINT8 }, - { "uint16", TDESC_TYPE_UINT16 }, - { "uint32", TDESC_TYPE_UINT32 }, - { "uint64", TDESC_TYPE_UINT64 }, - { "uint128", TDESC_TYPE_UINT128 }, - { "code_ptr", TDESC_TYPE_CODE_PTR }, - { "data_ptr", TDESC_TYPE_DATA_PTR }, - { "ieee_single", TDESC_TYPE_IEEE_SINGLE }, - { "ieee_double", TDESC_TYPE_IEEE_DOUBLE }, - { "arm_fpa_ext", TDESC_TYPE_ARM_FPA_EXT }, - { "i387_ext", TDESC_TYPE_I387_EXT } -}; - -/* Return the type associated with ID in the context of FEATURE, or - NULL if none. */ - -struct tdesc_type * -tdesc_named_type (const struct tdesc_feature *feature, const char *id) -{ - int ix; - struct tdesc_type *type; - - /* First try target-defined types. */ - for (ix = 0; VEC_iterate (tdesc_type_p, feature->types, ix, type); ix++) - if (strcmp (type->name, id) == 0) - return type; - - /* Next try the predefined types. */ - for (ix = 0; ix < ARRAY_SIZE (tdesc_predefined_types); ix++) - if (strcmp (tdesc_predefined_types[ix].name, id) == 0) - return &tdesc_predefined_types[ix]; - - return NULL; + return feature->name.c_str (); } /* Lookup type associated with ID. */ @@ -572,221 +751,21 @@ tdesc_named_type (const struct tdesc_feature *feature, const char *id) struct type * tdesc_find_type (struct gdbarch *gdbarch, const char *id) { - struct tdesc_arch_reg *reg; - struct tdesc_arch_data *data; - int i, num_regs; + tdesc_arch_data *data + = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); - data = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); - num_regs = VEC_length (tdesc_arch_reg, data->arch_regs); - for (i = 0; i < num_regs; i++) + for (const tdesc_arch_reg ® : data->arch_regs) { - reg = VEC_index (tdesc_arch_reg, data->arch_regs, i); - if (reg->reg - && reg->reg->tdesc_type - && reg->type - && strcmp (id, reg->reg->tdesc_type->name) == 0) - return reg->type; + if (reg.reg + && reg.reg->tdesc_type + && reg.type + && reg.reg->tdesc_type->name == id) + return reg.type; } return NULL; } -/* Construct, if necessary, and return the GDB type implementing target - type TDESC_TYPE for architecture GDBARCH. */ - -static struct type * -tdesc_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *tdesc_type) -{ - struct type *type; - - switch (tdesc_type->kind) - { - /* Predefined types. */ - case TDESC_TYPE_INT8: - return builtin_type (gdbarch)->builtin_int8; - - case TDESC_TYPE_INT16: - return builtin_type (gdbarch)->builtin_int16; - - case TDESC_TYPE_INT32: - return builtin_type (gdbarch)->builtin_int32; - - case TDESC_TYPE_INT64: - return builtin_type (gdbarch)->builtin_int64; - - case TDESC_TYPE_INT128: - return builtin_type (gdbarch)->builtin_int128; - - case TDESC_TYPE_UINT8: - return builtin_type (gdbarch)->builtin_uint8; - - case TDESC_TYPE_UINT16: - return builtin_type (gdbarch)->builtin_uint16; - - case TDESC_TYPE_UINT32: - return builtin_type (gdbarch)->builtin_uint32; - - case TDESC_TYPE_UINT64: - return builtin_type (gdbarch)->builtin_uint64; - - case TDESC_TYPE_UINT128: - return builtin_type (gdbarch)->builtin_uint128; - - case TDESC_TYPE_CODE_PTR: - return builtin_type (gdbarch)->builtin_func_ptr; - - case TDESC_TYPE_DATA_PTR: - return builtin_type (gdbarch)->builtin_data_ptr; - - default: - break; - } - - type = tdesc_find_type (gdbarch, tdesc_type->name); - if (type) - return type; - - switch (tdesc_type->kind) - { - case TDESC_TYPE_IEEE_SINGLE: - return arch_float_type (gdbarch, -1, "builtin_type_ieee_single", - floatformats_ieee_single); - - case TDESC_TYPE_IEEE_DOUBLE: - return arch_float_type (gdbarch, -1, "builtin_type_ieee_double", - floatformats_ieee_double); - - case TDESC_TYPE_ARM_FPA_EXT: - return arch_float_type (gdbarch, -1, "builtin_type_arm_ext", - floatformats_arm_ext); - - case TDESC_TYPE_I387_EXT: - return arch_float_type (gdbarch, -1, "builtin_type_i387_ext", - floatformats_i387_ext); - - /* Types defined by a target feature. */ - case TDESC_TYPE_VECTOR: - { - struct type *type, *field_type; - - field_type = tdesc_gdb_type (gdbarch, tdesc_type->u.v.type); - type = init_vector_type (field_type, tdesc_type->u.v.count); - TYPE_NAME (type) = xstrdup (tdesc_type->name); - - return type; - } - - case TDESC_TYPE_STRUCT: - { - struct type *type, *field_type; - struct tdesc_type_field *f; - int ix; - - type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); - TYPE_NAME (type) = xstrdup (tdesc_type->name); - TYPE_TAG_NAME (type) = TYPE_NAME (type); - - for (ix = 0; - VEC_iterate (tdesc_type_field, tdesc_type->u.u.fields, ix, f); - ix++) - { - if (f->type == NULL) - { - /* Bitfield. */ - struct field *fld; - struct type *field_type; - int bitsize, total_size; - - /* This invariant should be preserved while creating - types. */ - gdb_assert (tdesc_type->u.u.size != 0); - if (tdesc_type->u.u.size > 4) - field_type = builtin_type (gdbarch)->builtin_uint64; - else - field_type = builtin_type (gdbarch)->builtin_uint32; - - fld = append_composite_type_field_raw (type, xstrdup (f->name), - field_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 = tdesc_type->u.u.size * TARGET_CHAR_BIT; - if (gdbarch_bits_big_endian (gdbarch)) - SET_FIELD_BITPOS (fld[0], total_size - f->start - bitsize); - else - SET_FIELD_BITPOS (fld[0], f->start); - FIELD_BITSIZE (fld[0]) = bitsize; - } - else - { - field_type = tdesc_gdb_type (gdbarch, f->type); - append_composite_type_field (type, xstrdup (f->name), - field_type); - } - } - - if (tdesc_type->u.u.size != 0) - TYPE_LENGTH (type) = tdesc_type->u.u.size; - return type; - } - - case TDESC_TYPE_UNION: - { - struct type *type, *field_type; - struct tdesc_type_field *f; - int ix; - - type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION); - TYPE_NAME (type) = xstrdup (tdesc_type->name); - - for (ix = 0; - VEC_iterate (tdesc_type_field, tdesc_type->u.u.fields, ix, f); - ix++) - { - field_type = tdesc_gdb_type (gdbarch, f->type); - append_composite_type_field (type, xstrdup (f->name), field_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 (TYPE_VECTOR (field_type)) - TYPE_VECTOR (type) = 1; - } - return type; - } - - case TDESC_TYPE_FLAGS: - { - struct tdesc_type_flag *f; - int ix; - - type = arch_flags_type (gdbarch, tdesc_type->name, - tdesc_type->u.f.size); - for (ix = 0; - VEC_iterate (tdesc_type_flag, tdesc_type->u.f.flags, ix, f); - ix++) - /* Note that contrary to the function name, this call will - just set the properties of an already-allocated - field. */ - append_flags_type_flag (type, f->start, - *f->name ? f->name : NULL); - - return type; - } - } - - internal_error (__FILE__, __LINE__, - "Type \"%s\" has an unknown kind %d", - tdesc_type->name, tdesc_type->kind); -} - - /* Support for registers from target descriptions. */ /* Construct the per-gdbarch data. */ @@ -794,32 +773,24 @@ tdesc_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *tdesc_type) static void * tdesc_data_init (struct obstack *obstack) { - struct tdesc_arch_data *data; - - data = OBSTACK_ZALLOC (obstack, struct tdesc_arch_data); - return data; + return obstack_new (obstack); } /* Similar, but for the temporary copy used during architecture initialization. */ -struct tdesc_arch_data * +tdesc_arch_data_up tdesc_data_alloc (void) { - return XCNEW (struct tdesc_arch_data); + return tdesc_arch_data_up (new tdesc_arch_data ()); } -/* Free something allocated by tdesc_data_alloc, if it is not going - to be used (for instance if it was unsuitable for the - architecture). */ +/* See target-descriptions.h. */ void -tdesc_data_cleanup (void *data_untyped) +tdesc_arch_data_deleter::operator() (struct tdesc_arch_data *data) const { - struct tdesc_arch_data *data = (struct tdesc_arch_data *) data_untyped; - - VEC_free (tdesc_arch_reg, data->arch_regs); - xfree (data); + delete data; } /* Search FEATURE for a register named NAME. */ @@ -828,14 +799,9 @@ static struct tdesc_reg * tdesc_find_register_early (const struct tdesc_feature *feature, const char *name) { - int ixr; - struct tdesc_reg *reg; - - for (ixr = 0; - VEC_iterate (tdesc_reg_p, feature->registers, ixr, reg); - ixr++) - if (strcasecmp (reg->name, name) == 0) - return reg; + for (const tdesc_reg_up ® : feature->registers) + if (strcasecmp (reg->name.c_str (), name) == 0) + return reg.get (); return NULL; } @@ -847,18 +813,17 @@ tdesc_numbered_register (const struct tdesc_feature *feature, struct tdesc_arch_data *data, int regno, const char *name) { - struct tdesc_arch_reg arch_reg = { 0 }; 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 >= VEC_length (tdesc_arch_reg, data->arch_regs)) - VEC_safe_push (tdesc_arch_reg, data->arch_regs, &arch_reg); + while (regno >= data->arch_regs.size ()) + data->arch_regs.emplace_back (nullptr, nullptr); + + data->arch_regs[regno] = tdesc_arch_reg (reg, NULL); - arch_reg.reg = reg; - VEC_replace (tdesc_arch_reg, data->arch_regs, regno, &arch_reg); return 1; } @@ -898,8 +863,7 @@ tdesc_numbered_register_choices (const struct tdesc_feature *feature, bits. The register must exist. */ int -tdesc_register_size (const struct tdesc_feature *feature, - const char *name) +tdesc_register_bitsize (const struct tdesc_feature *feature, const char *name) { struct tdesc_reg *reg = tdesc_find_register_early (feature, name); @@ -915,8 +879,8 @@ 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 < VEC_length (tdesc_arch_reg, data->arch_regs)) - return VEC_index (tdesc_arch_reg, data->arch_regs, regno); + if (regno < data->arch_regs.size ()) + return &data->arch_regs[regno]; else return NULL; } @@ -937,12 +901,11 @@ tdesc_register_name (struct gdbarch *gdbarch, int regno) { struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno); int num_regs = gdbarch_num_regs (gdbarch); - int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch); if (reg != NULL) - return reg->name; + return reg->name.c_str (); - if (regno >= num_regs && regno < num_regs + num_pseudo_regs) + if (regno >= num_regs && regno < gdbarch_num_cooked_regs (gdbarch)) { struct tdesc_arch_data *data = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); @@ -979,10 +942,10 @@ tdesc_register_type (struct gdbarch *gdbarch, int regno) { /* First check for a predefined or target defined type. */ if (reg->tdesc_type) - arch_reg->type = tdesc_gdb_type (gdbarch, reg->tdesc_type); + arch_reg->type = make_gdb_type (gdbarch, reg->tdesc_type); /* Next try size-sensitive type shortcuts. */ - else if (strcmp (reg->type, "float") == 0) + else if (reg->type == "float") { if (reg->bitsize == gdbarch_float_bit (gdbarch)) arch_reg->type = builtin_type (gdbarch)->builtin_float; @@ -993,11 +956,11 @@ tdesc_register_type (struct gdbarch *gdbarch, int regno) else { warning (_("Register \"%s\" has an unsupported size (%d bits)"), - reg->name, reg->bitsize); + reg->name.c_str (), reg->bitsize); arch_reg->type = builtin_type (gdbarch)->builtin_double; } } - else if (strcmp (reg->type, "int") == 0) + else if (reg->type == "int") { if (reg->bitsize == gdbarch_long_bit (gdbarch)) arch_reg->type = builtin_type (gdbarch)->builtin_long; @@ -1015,7 +978,7 @@ tdesc_register_type (struct gdbarch *gdbarch, int regno) else { warning (_("Register \"%s\" has an unsupported size (%d bits)"), - reg->name, reg->bitsize); + reg->name.c_str (), reg->bitsize); arch_reg->type = builtin_type (gdbarch)->builtin_long; } } @@ -1023,7 +986,7 @@ tdesc_register_type (struct gdbarch *gdbarch, int regno) if (arch_reg->type == NULL) internal_error (__FILE__, __LINE__, "Register \"%s\" has an unknown type \"%s\"", - reg->name, reg->type); + reg->name.c_str (), reg->type.c_str ()); } return arch_reg->type; @@ -1041,17 +1004,13 @@ tdesc_remote_register_number (struct gdbarch *gdbarch, int regno) } /* Check whether REGNUM is a member of REGGROUP. Registers from the - target description may be classified as general, float, or vector. - 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. - - Arbitrary strings (other than "general", "float", and "vector") - from the description are not used; they cause the register to be - displayed in "info all-registers" but excluded from "info - registers" et al. The names of containing features are also not - used. This might be extended to display registers in some more - useful groupings. + 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. */ @@ -1061,26 +1020,9 @@ tdesc_register_in_reggroup_p (struct gdbarch *gdbarch, int regno, { struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno); - if (reg != NULL && reg->group != NULL) - { - int general_p = 0, float_p = 0, vector_p = 0; - - if (strcmp (reg->group, "general") == 0) - general_p = 1; - else if (strcmp (reg->group, "float") == 0) - float_p = 1; - else if (strcmp (reg->group, "vector") == 0) - vector_p = 1; - - if (reggroup == float_reggroup) - return float_p; - - if (reggroup == vector_reggroup) - return vector_p; - - if (reggroup == general_reggroup) - return general_p; - } + if (reg != NULL && !reg->group.empty () + && (reg->group == reggroup_name (reggroup))) + return 1; if (reg != NULL && (reggroup == save_reggroup || reggroup == restore_reggroup)) @@ -1157,15 +1099,11 @@ set_tdesc_pseudo_register_reggroup_p void tdesc_use_registers (struct gdbarch *gdbarch, const struct target_desc *target_desc, - struct tdesc_arch_data *early_data) + tdesc_arch_data_up &&early_data, + tdesc_unknown_register_ftype unk_reg_cb) { int num_regs = gdbarch_num_regs (gdbarch); - int ixf, ixr; - struct tdesc_feature *feature; - struct tdesc_reg *reg; struct tdesc_arch_data *data; - struct tdesc_arch_reg *arch_reg, new_arch_reg = { 0 }; - htab_t reg_hash; /* We can't use the description for registers if it doesn't describe any. This function should only be called after validating @@ -1174,56 +1112,78 @@ tdesc_use_registers (struct gdbarch *gdbarch, gdb_assert (tdesc_has_registers (target_desc)); data = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); - data->arch_regs = early_data->arch_regs; - xfree (early_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. */ - reg_hash = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL); - for (ixf = 0; - VEC_iterate (tdesc_feature_p, target_desc->features, ixf, feature); - ixf++) - for (ixr = 0; - VEC_iterate (tdesc_reg_p, feature->registers, ixr, reg); - ixr++) + 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, reg, INSERT); - - *slot = reg; + 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 (ixr = 0; - VEC_iterate (tdesc_arch_reg, data->arch_regs, ixr, arch_reg); - ixr++) - if (arch_reg->reg) - htab_remove_elt (reg_hash, arch_reg->reg); + 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 (VEC_length (tdesc_arch_reg, data->arch_regs) <= num_regs); - while (VEC_length (tdesc_arch_reg, data->arch_regs) < num_regs) - VEC_safe_push (tdesc_arch_reg, data->arch_regs, &new_arch_reg); - for (ixf = 0; - VEC_iterate (tdesc_feature_p, target_desc->features, ixf, feature); - ixf++) - for (ixr = 0; - VEC_iterate (tdesc_reg_p, feature->registers, ixr, reg); - ixr++) - if (htab_find (reg_hash, reg) != NULL) + 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) { - new_arch_reg.reg = reg; - VEC_safe_push (tdesc_arch_reg, data->arch_regs, &new_arch_reg); + data->arch_regs.emplace_back (reg.get (), nullptr); num_regs++; } - htab_delete (reg_hash); - /* Update the architecture. */ set_gdbarch_num_regs (gdbarch, num_regs); set_gdbarch_register_name (gdbarch, tdesc_register_name); @@ -1232,639 +1192,800 @@ tdesc_use_registers (struct gdbarch *gdbarch, tdesc_remote_register_number); set_gdbarch_register_reggroup_p (gdbarch, tdesc_register_reggroup_p); } - - -/* Methods for constructing a target description. */ -static void -tdesc_free_reg (struct tdesc_reg *reg) -{ - xfree (reg->name); - xfree (reg->type); - xfree (reg->group); - xfree (reg); -} +/* See gdbsupport/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 tdesc_feature * +tdesc_create_feature (struct target_desc *tdesc, const char *name) { - struct tdesc_reg *reg = XCNEW (struct tdesc_reg); + struct tdesc_feature *new_feature = new tdesc_feature (name); - reg->name = xstrdup (name); - reg->target_regnum = regnum; - reg->save_restore = save_restore; - reg->group = group ? xstrdup (group) : NULL; - reg->bitsize = bitsize; - reg->type = type ? xstrdup (type) : xstrdup (""); + tdesc->features.emplace_back (new_feature); - /* If the register's type is target-defined, look it up now. We may not - have easy access to the containing feature when we want it later. */ - reg->tdesc_type = tdesc_named_type (feature, reg->type); - - VEC_safe_push (tdesc_reg_p, feature->registers, reg); + return new_feature; } -static void -tdesc_free_type (struct tdesc_type *type) -{ - switch (type->kind) - { - case TDESC_TYPE_STRUCT: - case TDESC_TYPE_UNION: - { - struct tdesc_type_field *f; - int ix; - - for (ix = 0; - VEC_iterate (tdesc_type_field, type->u.u.fields, ix, f); - ix++) - xfree (f->name); - - VEC_free (tdesc_type_field, type->u.u.fields); - } - break; - - case TDESC_TYPE_FLAGS: - { - struct tdesc_type_flag *f; - int ix; - - for (ix = 0; - VEC_iterate (tdesc_type_flag, type->u.f.flags, ix, f); - ix++) - xfree (f->name); +/* See gdbsupport/tdesc.h. */ - VEC_free (tdesc_type_flag, type->u.f.flags); - } - break; +target_desc_up +allocate_target_description (void) +{ + return target_desc_up (new target_desc ()); +} - default: - break; - } +/* See gdbsupport/tdesc.h. */ - xfree (type->name); - xfree (type); +void +target_desc_deleter::operator() (struct target_desc *target_desc) const +{ + delete target_desc; } -struct tdesc_type * -tdesc_create_vector (struct tdesc_feature *feature, const char *name, - struct tdesc_type *field_type, int count) +void +tdesc_add_compatible (struct target_desc *target_desc, + const struct bfd_arch_info *compatible) { - struct tdesc_type *type = XCNEW (struct tdesc_type); + /* 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; - type->name = xstrdup (name); - type->kind = TDESC_TYPE_VECTOR; - type->u.v.type = field_type; - type->u.v.count = count; + 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); - VEC_safe_push (tdesc_type_p, feature->types, type); - return type; + target_desc->compatible.push_back + (std::unique_ptr + (new tdesc_compatible_info (compatible))); } -struct tdesc_type * -tdesc_create_struct (struct tdesc_feature *feature, const char *name) +void +set_tdesc_property (struct target_desc *target_desc, + const char *key, const char *value) { - struct tdesc_type *type = XCNEW (struct tdesc_type); + gdb_assert (key != NULL && value != NULL); - type->name = xstrdup (name); - type->kind = TDESC_TYPE_STRUCT; + if (tdesc_property (target_desc, key) != NULL) + internal_error (__FILE__, __LINE__, + _("Attempted to add duplicate property \"%s\""), key); - VEC_safe_push (tdesc_type_p, feature->types, type); - return type; + target_desc->properties.emplace_back (key, value); } -/* Set the total length of TYPE. Structs which contain bitfields may - omit the reserved bits, so the end of the last field may not - suffice. */ +/* See gdbsupport/tdesc.h. */ void -tdesc_set_struct_size (struct tdesc_type *type, LONGEST size) +set_tdesc_architecture (struct target_desc *target_desc, + const char *name) { - gdb_assert (type->kind == TDESC_TYPE_STRUCT); - type->u.u.size = size; + set_tdesc_architecture (target_desc, bfd_scan_arch (name)); } -struct tdesc_type * -tdesc_create_union (struct tdesc_feature *feature, const char *name) +void +set_tdesc_architecture (struct target_desc *target_desc, + const struct bfd_arch_info *arch) { - struct tdesc_type *type = XCNEW (struct tdesc_type); + target_desc->arch = arch; +} - type->name = xstrdup (name); - type->kind = TDESC_TYPE_UNION; +/* See gdbsupport/tdesc.h. */ - VEC_safe_push (tdesc_type_p, feature->types, type); - return type; +void +set_tdesc_osabi (struct target_desc *target_desc, const char *name) +{ + set_tdesc_osabi (target_desc, osabi_from_tdesc_string (name)); } -struct tdesc_type * -tdesc_create_flags (struct tdesc_feature *feature, const char *name, - LONGEST size) +void +set_tdesc_osabi (struct target_desc *target_desc, enum gdb_osabi osabi) { - struct tdesc_type *type = XCNEW (struct tdesc_type); - - type->name = xstrdup (name); - type->kind = TDESC_TYPE_FLAGS; - type->u.f.size = size; - - VEC_safe_push (tdesc_type_p, feature->types, type); - return type; + target_desc->osabi = osabi; } + -/* Add a new field. Return a temporary pointer to the field, which - is only valid until the next call to tdesc_add_field (the vector - might be reallocated). */ +static struct cmd_list_element *tdesc_set_cmdlist, *tdesc_show_cmdlist; +static struct cmd_list_element *tdesc_unset_cmdlist; -void -tdesc_add_field (struct tdesc_type *type, const char *field_name, - struct tdesc_type *field_type) +/* Helper functions for the CLI commands. */ + +static void +set_tdesc_filename_cmd (const char *args, int from_tty, + struct cmd_list_element *c) { - struct tdesc_type_field f = { 0 }; + xfree (target_description_filename); + target_description_filename = xstrdup (tdesc_filename_cmd_string); - gdb_assert (type->kind == TDESC_TYPE_UNION - || type->kind == TDESC_TYPE_STRUCT); + target_clear_description (); + target_find_description (); +} - f.name = xstrdup (field_name); - f.type = field_type; +static void +show_tdesc_filename_cmd (struct ui_file *file, int from_tty, + struct cmd_list_element *c, + const char *value) +{ + value = target_description_filename; - VEC_safe_push (tdesc_type_field, type->u.u.fields, &f); + 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")); } -/* Add a new bitfield. */ +static void +unset_tdesc_filename_cmd (const char *args, int from_tty) +{ + xfree (target_description_filename); + target_description_filename = NULL; + target_clear_description (); + target_find_description (); +} -void -tdesc_add_bitfield (struct tdesc_type *type, const char *field_name, - int start, int end) +/* Print target description in C. */ + +class print_c_tdesc : public tdesc_element_visitor { - struct tdesc_type_field f = { 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 ()); - gdb_assert (type->kind == TDESC_TYPE_STRUCT); + 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'; - f.name = xstrdup (field_name); - f.start = start; - f.end = end; + /* Standard boilerplate. */ + printf_unfiltered ("/* THIS FILE IS GENERATED. " + "-*- buffer-read-only: t -*- vi" + ":set ro:\n"); + } - VEC_safe_push (tdesc_type_field, type->u.u.fields, &f); -} + ~print_c_tdesc () + { + xfree (m_function); + } -void -tdesc_add_flag (struct tdesc_type *type, int start, - const char *flag_name) -{ - struct tdesc_type_flag f = { 0 }; + void visit_pre (const target_desc *e) override + { + printf_unfiltered (" Original: %s */\n\n", + lbasename (m_filename_after_features.c_str ())); - gdb_assert (type->kind == TDESC_TYPE_FLAGS); + printf_unfiltered ("#include \"defs.h\"\n"); + printf_unfiltered ("#include \"osabi.h\"\n"); + printf_unfiltered ("#include \"target-descriptions.h\"\n"); + printf_unfiltered ("\n"); - f.name = xstrdup (flag_name); - f.start = start; + 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"); - VEC_safe_push (tdesc_type_flag, type->u.f.flags, &f); -} + 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"); + } -static void -tdesc_free_feature (struct tdesc_feature *feature) -{ - struct tdesc_reg *reg; - struct tdesc_type *type; - int ix; + 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); - for (ix = 0; VEC_iterate (tdesc_reg_p, feature->registers, ix, reg); ix++) - tdesc_free_reg (reg); - VEC_free (tdesc_reg_p, feature->registers); + if (!e->compatible.empty ()) + printf_unfiltered ("\n"); - for (ix = 0; VEC_iterate (tdesc_type_p, feature->types, ix, type); ix++) - tdesc_free_type (type); - VEC_free (tdesc_type_p, feature->types); + for (const property &prop : e->properties) + printf_unfiltered (" set_tdesc_property (result.get (), \"%s\", \"%s\");\n", + prop.key.c_str (), prop.value.c_str ()); - xfree (feature->name); - xfree (feature); -} + printf_unfiltered (" struct tdesc_feature *feature;\n"); + } -struct tdesc_feature * -tdesc_create_feature (struct target_desc *tdesc, const char *name) -{ - struct tdesc_feature *new_feature = XCNEW (struct tdesc_feature); + void visit_pre (const tdesc_feature *e) override + { + printf_unfiltered ("\n feature = tdesc_create_feature (result.get (), \"%s\");\n", + e->name.c_str ()); + } - new_feature->name = xstrdup (name); + void visit_post (const tdesc_feature *e) override + {} - VEC_safe_push (tdesc_feature_p, tdesc->features, new_feature); - return new_feature; -} + void visit_post (const target_desc *e) override + { + printf_unfiltered ("\n tdesc_%s = result.release ();\n", m_function); + printf_unfiltered ("}\n"); + } -struct target_desc * -allocate_target_description (void) -{ - return XCNEW (struct target_desc); -} + void visit (const tdesc_type_builtin *type) override + { + error (_("C output is not supported type \"%s\"."), type->name.c_str ()); + } -static void -free_target_description (void *arg) -{ - struct target_desc *target_desc = (struct target_desc *) arg; - struct tdesc_feature *feature; - struct property *prop; - int ix; - - for (ix = 0; - VEC_iterate (tdesc_feature_p, target_desc->features, ix, feature); - ix++) - tdesc_free_feature (feature); - VEC_free (tdesc_feature_p, target_desc->features); - - for (ix = 0; - VEC_iterate (property_s, target_desc->properties, ix, prop); - ix++) - { - xfree (prop->key); - xfree (prop->value); - } - VEC_free (property_s, target_desc->properties); + 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; + } - VEC_free (arch_p, target_desc->compatible); + 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); - xfree (target_desc); -} + printf_unfiltered ("\n"); + } -struct cleanup * -make_cleanup_free_target_description (struct target_desc *target_desc) -{ - return make_cleanup (free_target_description, target_desc); -} + 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; + } -void -tdesc_add_compatible (struct target_desc *target_desc, - const struct bfd_arch_info *compatible) -{ - const struct bfd_arch_info *compat; - int ix; + 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; - /* 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; + gdb_assert (f.type != NULL); + type_name = f.type->name.c_str (); - for (ix = 0; VEC_iterate (arch_p, target_desc->compatible, ix, compat); - ix++) - if (compat == compatible) - internal_error (__FILE__, __LINE__, - _("Attempted to add duplicate " - "compatible architecture \"%s\""), - compatible->printable_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_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 ()); + } - VEC_safe_push (arch_p, target_desc->compatible, compatible); -} + printf_unfiltered ("\n"); + } -void -set_tdesc_property (struct target_desc *target_desc, - const char *key, const char *value) -{ - struct property *prop, new_prop; - int ix; + 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 ()); + } - gdb_assert (key != NULL && value != NULL); +protected: + std::string m_filename_after_features; - for (ix = 0; VEC_iterate (property_s, target_desc->properties, ix, prop); - ix++) - if (strcmp (prop->key, key) == 0) - internal_error (__FILE__, __LINE__, - _("Attempted to add duplicate property \"%s\""), key); +private: - new_prop.key = xstrdup (key); - new_prop.value = xstrdup (value); - VEC_safe_push (property_s, target_desc->properties, &new_prop); -} + /* 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; + } -void -set_tdesc_architecture (struct target_desc *target_desc, - const struct bfd_arch_info *arch) -{ - target_desc->arch = arch; -} + printf_unfiltered (" field_type = "); -void -set_tdesc_osabi (struct target_desc *target_desc, enum gdb_osabi osabi) + 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 { - target_desc->osabi = osabi; -} - +public: + print_c_feature (std::string &file) + : print_c_tdesc (file) + { + /* Trim ".tmp". */ + auto const pos = m_filename_after_features.find_last_of ('.'); -static struct cmd_list_element *tdesc_set_cmdlist, *tdesc_show_cmdlist; -static struct cmd_list_element *tdesc_unset_cmdlist; + m_filename_after_features = m_filename_after_features.substr (0, pos); + } -/* Helper functions for the CLI commands. */ + void visit_pre (const target_desc *e) override + { + printf_unfiltered (" Original: %s */\n\n", + lbasename (m_filename_after_features.c_str ())); -static void -set_tdesc_cmd (char *args, int from_tty) + 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, + + + + + + + + but it also has false negatives. The target description + below is correct, + + + + + + + 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) { - help_list (tdesc_set_cmdlist, "set tdesc ", all_commands, gdb_stdout); + if (tdesc->xmltarget == nullptr) + { + std::string buffer ("@"); + print_xml_feature v (&buffer); + tdesc->accept (v); + tdesc->xmltarget = xstrdup (buffer.c_str ()); + } + return tdesc->xmltarget; } -static void -show_tdesc_cmd (char *args, int from_tty) +/* Data structures and functions to setup the option flags for 'maintenance + print c-tdesc command. */ + +struct maint_print_c_tdesc_options { - cmd_show_list (tdesc_show_cmdlist, from_tty, ""); -} + /* True when the '-single-feature' flag was passed. */ + bool single_feature = false; +}; -static void -unset_tdesc_cmd (char *args, int from_tty) +using maint_print_c_tdesc_opt_def + = gdb::option::flag_option_def; + +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) { - help_list (tdesc_unset_cmdlist, "unset tdesc ", all_commands, gdb_stdout); + return {{maint_print_c_tdesc_opt_defs}, opts}; } +/* Implement 'maintenance print c-tdesc' command. */ + static void -set_tdesc_filename_cmd (char *args, int from_tty, - struct cmd_list_element *c) +maint_print_c_tdesc_cmd (const char *args, int from_tty) { - xfree (target_description_filename); - target_description_filename = xstrdup (tdesc_filename_cmd_string); + const struct target_desc *tdesc; + const char *filename; - target_clear_description (); - target_find_description (); -} + 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); -static void -show_tdesc_filename_cmd (struct ui_file *file, int from_tty, - struct cmd_list_element *c, - const char *value) -{ - value = target_description_filename; + if (args == NULL) + { + /* Use the global target-supplied description, not the current + architecture's. This lets a GDB for one architecture generate C + for another architecture's description, even though the gdbarch + initialization code will reject the new description. */ + tdesc = current_target_desc; + filename = target_description_filename; + } + else + { + /* Use the target description from the XML file. */ + filename = args; + tdesc = file_read_description_xml (filename); + } - if (value != NULL && *value != '\0') - printf_filtered (_("The target description will be read from \"%s\".\n"), - value); + 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 - printf_filtered (_("The target description will be " - "read from the target.\n")); + { + print_c_tdesc v (filename_after_features); + + tdesc->accept (v); + } } +/* Completer for the "backtrace" command. */ + static void -unset_tdesc_filename_cmd (char *args, int from_tty) +maint_print_c_tdesc_cmd_completer (struct cmd_list_element *ignore, + completion_tracker &tracker, + const char *text, const char *word) { - xfree (target_description_filename); - target_description_filename = NULL; - target_clear_description (); - target_find_description (); + 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_c_tdesc_cmd (char *args, int from_tty) +maint_print_xml_tdesc_cmd (const char *args, int from_tty) { const struct target_desc *tdesc; - const struct bfd_arch_info *compatible; - const char *filename, *inp; - char *function, *outp; - struct property *prop; - struct tdesc_feature *feature; - struct tdesc_reg *reg; - struct tdesc_type *type; - struct tdesc_type_field *f; - struct tdesc_type_flag *flag; - int ix, ix2, ix3; - int printed_field_type = 0; - - /* Use the global target-supplied description, not the current - architecture's. This lets a GDB for one architecture generate C - for another architecture's description, even though the gdbarch - initialization code will reject the new description. */ - tdesc = current_target_desc; + + if (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 = current_target_desc; + } + 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.")); - if (target_description_filename == NULL) - error (_("The current target description did not come from an XML file.")); + std::string buf; + print_xml_feature v (&buf); + tdesc->accept (v); + puts_unfiltered (buf.c_str ()); +} - 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; +namespace selftests { - 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; - } +/* A reference target description, used for testing (see record_xml_tdesc). */ - if ((type->kind == TDESC_TYPE_UNION - || type->kind == TDESC_TYPE_STRUCT) - && VEC_length (tdesc_type_field, type->u.u.fields) > 0) - { - printf_unfiltered (" struct tdesc_type *type;\n"); - printed_desc_type = 1; - break; - } - } +struct xml_test_tdesc +{ + xml_test_tdesc (const char *name, std::unique_ptr &&tdesc) + : name (name), tdesc (std::move (tdesc)) + {} - if (printed_desc_type) - break; - } + const char *name; + std::unique_ptr tdesc; +}; - printf_unfiltered ("\n"); +static std::vector xml_tdesc; - if (tdesc_architecture (tdesc) != NULL) - { - printf_unfiltered - (" set_tdesc_architecture (result, bfd_scan_arch (\"%s\"));\n", - tdesc_architecture (tdesc)->printable_name); - printf_unfiltered ("\n"); - } +#if 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 (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 (tdesc_osabi (tdesc) > GDB_OSABI_UNKNOWN - && tdesc_osabi (tdesc) < GDB_OSABI_INVALID) + if (xml == nullptr || *xml != '@') { - printf_unfiltered - (" set_tdesc_osabi (result, osabi_from_tdesc_string (\"%s\"));\n", - gdbarch_osabi_name (tdesc_osabi (tdesc))); - printf_unfiltered ("\n"); + printf_filtered (_("Could not convert description for %s to xml.\n"), + name); + return false; } - for (ix = 0; VEC_iterate (arch_p, tdesc->compatible, ix, compatible); - ix++) + const target_desc *tdesc_trans = string_read_description_xml (xml + 1); + + if (tdesc_trans == nullptr) { - printf_unfiltered - (" tdesc_add_compatible (result, bfd_scan_arch (\"%s\"));\n", - compatible->printable_name); + printf_filtered (_("Could not convert description for %s from xml.\n"), + name); + return false; } - if (ix) - printf_unfiltered ("\n"); - - for (ix = 0; VEC_iterate (property_s, tdesc->properties, ix, prop); - ix++) + else if (*tdesc != *tdesc_trans) { - printf_unfiltered (" set_tdesc_property (result, \"%s\", \"%s\");\n", - prop->key, prop->value); + printf_filtered (_("Converted description for %s does not match.\n"), + name); + return false; } + return true; +} - for (ix = 0; - VEC_iterate (tdesc_feature_p, tdesc->features, ix, feature); - ix++) - { - printf_unfiltered (" \ -feature = tdesc_create_feature (result, \"%s\");\n", - feature->name); - for (ix2 = 0; - VEC_iterate (tdesc_type_p, feature->types, ix2, type); - ix2++) - { - switch (type->kind) - { - case TDESC_TYPE_VECTOR: - printf_unfiltered - (" field_type = tdesc_named_type (feature, \"%s\");\n", - type->u.v.type->name); - printf_unfiltered - (" tdesc_create_vector (feature, \"%s\", field_type, %d);\n", - type->name, type->u.v.count); - break; - case TDESC_TYPE_STRUCT: - printf_unfiltered - (" type = tdesc_create_struct (feature, \"%s\");\n", - type->name); - if (type->u.u.size != 0) - printf_unfiltered - (" tdesc_set_struct_size (type, %s);\n", - plongest (type->u.u.size)); - for (ix3 = 0; - VEC_iterate (tdesc_type_field, type->u.u.fields, ix3, f); - ix3++) - { - /* Going first for implicitly sized types, else part handles - bitfields. As reported on xml-tdesc.c implicitly sized types - cannot contain a bitfield. */ - if (f->type != NULL) - { - printf_unfiltered - (" field_type = tdesc_named_type (feature, \"%s\");\n", - f->type->name); - printf_unfiltered - (" tdesc_add_field (type, \"%s\", field_type);\n", - f->name); - } - else - printf_unfiltered - (" tdesc_add_bitfield (type, \"%s\", %d, %d);\n", - f->name, f->start, f->end); - } - break; - case TDESC_TYPE_UNION: - printf_unfiltered - (" type = tdesc_create_union (feature, \"%s\");\n", - type->name); - for (ix3 = 0; - VEC_iterate (tdesc_type_field, type->u.u.fields, ix3, f); - ix3++) - { - printf_unfiltered - (" field_type = tdesc_named_type (feature, \"%s\");\n", - f->type->name); - printf_unfiltered - (" tdesc_add_field (type, \"%s\", field_type);\n", - f->name); - } - break; - case TDESC_TYPE_FLAGS: - printf_unfiltered - (" field_type = tdesc_create_flags (feature, \"%s\", %d);\n", - type->name, (int) type->u.f.size); - for (ix3 = 0; - VEC_iterate (tdesc_type_flag, type->u.f.flags, ix3, - flag); - ix3++) - printf_unfiltered - (" tdesc_add_flag (field_type, %d, \"%s\");\n", - flag->start, flag->name); - break; - default: - error (_("C output is not supported type \"%s\"."), type->name); - } - printf_unfiltered ("\n"); - } +/* 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")); - for (ix2 = 0; - VEC_iterate (tdesc_reg_p, feature->registers, ix2, reg); - ix2++) + gdb::unique_xmalloc_ptr 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_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_filtered ( _("Descriptions for %s do not match.\n"), e.name); + failed++; } - - printf_unfiltered ("\n"); + else if (!maintenance_check_tdesc_xml_convert (tdesc, e.name) + || !maintenance_check_tdesc_xml_convert (e.tdesc.get (), e.name)) + failed++; } - - printf_unfiltered (" tdesc_%s = result;\n", function); - printf_unfiltered ("}\n"); + printf_filtered (_("Tested %lu XML files, %d failed\n"), + (long) selftests::xml_tdesc.size (), failed); } -/* Provide a prototype to silence -Wmissing-prototypes. */ -extern initialize_file_ftype _initialize_target_descriptions; - +void _initialize_target_descriptions (); void -_initialize_target_descriptions (void) +_initialize_target_descriptions () { + cmd_list_element *cmd; + tdesc_data = gdbarch_data_register_pre_init (tdesc_data_init); - add_prefix_cmd ("tdesc", class_maintenance, set_tdesc_cmd, _("\ + add_basic_prefix_cmd ("tdesc", class_maintenance, _("\ Set target description specific variables."), - &tdesc_set_cmdlist, "set tdesc ", - 0 /* allow-unknown */, &setlist); - add_prefix_cmd ("tdesc", class_maintenance, show_tdesc_cmd, _("\ + &tdesc_set_cmdlist, "set tdesc ", + 0 /* allow-unknown */, &setlist); + add_show_prefix_cmd ("tdesc", class_maintenance, _("\ Show target description specific variables."), - &tdesc_show_cmdlist, "show tdesc ", - 0 /* allow-unknown */, &showlist); - add_prefix_cmd ("tdesc", class_maintenance, unset_tdesc_cmd, _("\ + &tdesc_show_cmdlist, "show tdesc ", + 0 /* allow-unknown */, &showlist); + add_basic_prefix_cmd ("tdesc", class_maintenance, _("\ Unset target description specific variables."), - &tdesc_unset_cmdlist, "unset tdesc ", - 0 /* allow-unknown */, &unsetlist); + &tdesc_unset_cmdlist, "unset tdesc ", + 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"), _("\ +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, @@ -1872,11 +1993,41 @@ file instead of querying the remote target."), &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. When unset,\n\ -GDB will read the description from the target."), +Unset the file to read for an XML target description.\n\ +When unset, GDB will read the description from the target."), &tdesc_unset_cmdlist); - add_cmd ("c-tdesc", class_maintenance, maint_print_c_tdesc_cmd, _("\ -Print the current target description as a C source file."), - &maintenanceprintlist); + 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); }