X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Ftarget-descriptions.c;h=6135e0d99eea359bf6ccd2e7c541e58c57baed7b;hb=0abe8a8992948559d225ff120095e42a1a6a36f4;hp=f15340d9e3cdcc00199377841691cdffa815eff5;hpb=c8c122932061ba5c68cc6893262990463162de1c;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c index f15340d9e3..6135e0d99e 100644 --- a/gdb/target-descriptions.c +++ b/gdb/target-descriptions.c @@ -1,6 +1,6 @@ /* Target description support for GDB. - Copyright (C) 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 2006-2017 Free Software Foundation, Inc. Contributed by CodeSourcery. @@ -8,7 +8,7 @@ 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 2 of the License, or + 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, @@ -17,9 +17,7 @@ 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ #include "defs.h" #include "arch-utils.h" @@ -31,10 +29,35 @@ #include "vec.h" #include "xml-support.h" #include "xml-tdesc.h" +#include "osabi.h" -#include "gdb_assert.h" #include "gdb_obstack.h" #include "hashtab.h" +#include "inferior.h" +#include +#include "completer.h" +#include "readline/tilde.h" /* tilde_expand */ + +/* The interface to visit different elements of target description. */ + +class tdesc_element_visitor +{ +public: + virtual void visit_pre (const target_desc *e) = 0; + virtual void visit_post (const target_desc *e) = 0; + + virtual void visit_pre (const tdesc_feature *e) = 0; + virtual void visit_post (const tdesc_feature *e) = 0; + + virtual void visit (const tdesc_type *e) = 0; + virtual void visit (const tdesc_reg *e) = 0; +}; + +class tdesc_element +{ +public: + virtual void accept (tdesc_element_visitor &v) const = 0; +}; /* Types. */ @@ -47,8 +70,33 @@ DEF_VEC_O(property_s); /* An individual register from a target description. */ -typedef struct tdesc_reg +typedef struct tdesc_reg : tdesc_element { + tdesc_reg (struct tdesc_feature *feature, const char *name_, + int regnum, int save_restore_, const char *group_, + int bitsize_, const char *type_) + : name (xstrdup (name_)), target_regnum (regnum), + save_restore (save_restore_), + group (group_ != NULL ? xstrdup (group_) : NULL), + bitsize (bitsize_), + type (type_ != NULL ? xstrdup (type_) : xstrdup ("")) + { + /* If the register's type is target-defined, look it up now. We may not + have easy access to the containing feature when we want it later. */ + tdesc_type = tdesc_named_type (feature, type); + } + + virtual ~tdesc_reg () + { + xfree (name); + xfree (type); + xfree (group); + } + + /* Disable copying. */ + tdesc_reg (const tdesc_reg &) = delete; + tdesc_reg &operator= (const tdesc_reg &) = delete; + /* The name of this register. In standard features, it may be recognized by the architecture support code, or it may be purely for the user. */ @@ -81,58 +129,387 @@ typedef struct tdesc_reg char *type; /* The target-described type corresponding to TYPE, if found. */ - struct type *gdb_type; + struct tdesc_type *tdesc_type; + + void accept (tdesc_element_visitor &v) const override + { + v.visit (this); + } + + bool operator== (const tdesc_reg &other) const + { + return (streq (name, other.name) + && target_regnum == other.target_regnum + && save_restore == other.save_restore + && bitsize == other.bitsize + && (group == other.group || streq (group, other.group)) + && streq (type, other.type)); + } + + bool operator!= (const tdesc_reg &other) const + { + return !(*this == other); + } } *tdesc_reg_p; DEF_VEC_P(tdesc_reg_p); /* A named type from a target description. */ -typedef struct type *type_p; -DEF_VEC_P(type_p); + +typedef struct tdesc_type_field +{ + char *name; + struct tdesc_type *type; + /* For non-enum-values, either both are -1 (non-bitfield), or both are + not -1 (bitfield). For enum values, start is the value (which could be + -1), end is -1. */ + int start, end; +} tdesc_type_field; +DEF_VEC_O(tdesc_type_field); + +enum tdesc_type_kind +{ + /* Predefined types. */ + TDESC_TYPE_BOOL, + 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, + TDESC_TYPE_ENUM +}; + +typedef struct tdesc_type : tdesc_element +{ + tdesc_type (const char *name_, enum tdesc_type_kind kind_) + : name (xstrdup (name_)), kind (kind_) + { + memset (&u, 0, sizeof (u)); + } + + virtual ~tdesc_type () + { + switch (kind) + { + case TDESC_TYPE_STRUCT: + case TDESC_TYPE_UNION: + case TDESC_TYPE_FLAGS: + case TDESC_TYPE_ENUM: + { + struct tdesc_type_field *f; + int ix; + + for (ix = 0; + VEC_iterate (tdesc_type_field, u.u.fields, ix, f); + ix++) + xfree (f->name); + + VEC_free (tdesc_type_field, u.u.fields); + } + break; + + default: + break; + } + xfree ((char *) name); + } + /* Disable copying. */ + tdesc_type (const tdesc_type &) = delete; + tdesc_type &operator= (const tdesc_type &) = delete; + + /* The name of this type. If this type is a built-in type, this is + a pointer to a constant string. Otherwise, it's a + malloc-allocated string (and thus must be freed). */ + const char *name; + + /* Identify the kind of this type. */ + enum tdesc_type_kind kind; + + /* Kind-specific data. */ + union + { + /* Vector type. */ + struct + { + struct tdesc_type *type; + int count; + } v; + + /* Struct, union, flags, or enum type. */ + struct + { + VEC(tdesc_type_field) *fields; + int size; + } u; + } u; + + void accept (tdesc_element_visitor &v) const override + { + v.visit (this); + } + + bool operator== (const tdesc_type &other) const + { + return (streq (name, other.name) && kind == other.kind); + } + + bool operator!= (const tdesc_type &other) const + { + return !(*this == other); + } +} *tdesc_type_p; +DEF_VEC_P(tdesc_type_p); /* A feature from a target description. Each feature is a collection of other elements, e.g. registers and types. */ -typedef struct tdesc_feature +typedef struct tdesc_feature : tdesc_element { + tdesc_feature (const char *name_) + : name (xstrdup (name_)) + {} + + virtual ~tdesc_feature () + { + struct tdesc_reg *reg; + struct tdesc_type *type; + int ix; + + for (ix = 0; VEC_iterate (tdesc_reg_p, registers, ix, reg); ix++) + delete reg; + VEC_free (tdesc_reg_p, registers); + + for (ix = 0; VEC_iterate (tdesc_type_p, types, ix, type); ix++) + delete type; + VEC_free (tdesc_type_p, types); + + xfree (name); + } + + /* Disable copying. */ + tdesc_feature (const tdesc_feature &) = delete; + tdesc_feature &operator= (const tdesc_feature &) = delete; + /* The name of this feature. It may be recognized by the architecture support code. */ char *name; /* The registers associated with this feature. */ - VEC(tdesc_reg_p) *registers; + VEC(tdesc_reg_p) *registers = NULL; /* The types associated with this feature. */ - VEC(type_p) *types; + VEC(tdesc_type_p) *types = NULL; + + void accept (tdesc_element_visitor &v) const override + { + v.visit_pre (this); + + struct tdesc_type *type; + + for (int ix = 0; + VEC_iterate (tdesc_type_p, types, ix, type); + ix++) + type->accept (v); + + struct tdesc_reg *reg; + + for (int ix = 0; + VEC_iterate (tdesc_reg_p, registers, ix, reg); + ix++) + reg->accept (v); + + + v.visit_post (this); + } + + bool operator== (const tdesc_feature &other) const + { + if (strcmp (name, other.name) != 0) + return false; + + if (VEC_length (tdesc_reg_p, registers) + != VEC_length (tdesc_reg_p, other.registers)) + return false; + + struct tdesc_reg *reg; + + for (int ix = 0; + VEC_iterate (tdesc_reg_p, registers, ix, reg); + ix++) + { + tdesc_reg *reg2 + = VEC_index (tdesc_reg_p, other.registers, ix); + + if (reg != reg2 && *reg != *reg2) + return false; + } + + if (VEC_length (tdesc_type_p, types) + != VEC_length (tdesc_type_p, other.types)) + return false; + + tdesc_type *type; + + for (int ix = 0; + VEC_iterate (tdesc_type_p, types, ix, type); + ix++) + { + tdesc_type *type2 + = VEC_index (tdesc_type_p, other.types, ix); + + if (type != type2 && *type != *type2) + return false; + } + + return true; + } + + bool operator!= (const tdesc_feature &other) const + { + return !(*this == other); + } + } *tdesc_feature_p; DEF_VEC_P(tdesc_feature_p); +/* A compatible architecture from a target description. */ +typedef const struct bfd_arch_info *arch_p; +DEF_VEC_P(arch_p); + /* A target description. */ -struct target_desc +struct target_desc : tdesc_element { + target_desc () + {} + + virtual ~target_desc () + { + struct tdesc_feature *feature; + struct property *prop; + int ix; + + for (ix = 0; + VEC_iterate (tdesc_feature_p, features, ix, feature); + ix++) + delete feature; + VEC_free (tdesc_feature_p, features); + + for (ix = 0; + VEC_iterate (property_s, properties, ix, prop); + ix++) + { + xfree (prop->key); + xfree (prop->value); + } + + VEC_free (property_s, properties); + VEC_free (arch_p, compatible); + } + + target_desc (const target_desc &) = delete; + void operator= (const target_desc &) = delete; + /* The architecture reported by the target, if any. */ - const struct bfd_arch_info *arch; + const struct bfd_arch_info *arch = NULL; + + /* The osabi reported by the target, if any; GDB_OSABI_UNKNOWN + otherwise. */ + enum gdb_osabi osabi = GDB_OSABI_UNKNOWN; + + /* The list of compatible architectures reported by the target. */ + VEC(arch_p) *compatible = NULL; /* Any architecture-specific properties specified by the target. */ - VEC(property_s) *properties; + VEC(property_s) *properties = NULL; /* The features associated with this target. */ - VEC(tdesc_feature_p) *features; + VEC(tdesc_feature_p) *features = NULL; + + void accept (tdesc_element_visitor &v) const override + { + v.visit_pre (this); + + struct tdesc_feature *feature; + + for (int ix = 0; + VEC_iterate (tdesc_feature_p, features, ix, feature); + ix++) + feature->accept (v); + + v.visit_post (this); + } + + bool operator== (const target_desc &other) const + { + if (arch != other.arch) + return false; + + if (osabi != other.osabi) + return false; + + if (VEC_length (tdesc_feature_p, features) + != VEC_length (tdesc_feature_p, other.features)) + return false; + + struct tdesc_feature *feature; + + for (int ix = 0; + VEC_iterate (tdesc_feature_p, features, ix, feature); + ix++) + { + struct tdesc_feature *feature2 + = VEC_index (tdesc_feature_p, other.features, ix); + + if (feature != feature2 && *feature != *feature2) + return false; + } + + return true; + } + + bool operator!= (const target_desc &other) const + { + return !(*this == other); + } }; /* Per-architecture data associated with a target description. The target description may be shared by multiple architectures, but this data is private to one gdbarch. */ +typedef struct tdesc_arch_reg +{ + struct tdesc_reg *reg; + struct type *type; +} tdesc_arch_reg; +DEF_VEC_O(tdesc_arch_reg); + struct tdesc_arch_data { - /* A list of registers, indexed by GDB's internal register number. + /* 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). */ - VEC(tdesc_reg_p) *registers; + VEC(tdesc_arch_reg) *arch_regs; /* Functions which report the register name, type, and reggroups for pseudo-registers. */ @@ -141,34 +518,92 @@ struct tdesc_arch_data gdbarch_register_reggroup_p_ftype *pseudo_register_reggroup_p; }; -/* Global state. These variables are associated with the current - target; if GDB adds support for multiple simultaneous targets, then - these variables should become target-specific data. */ +/* Info about an inferior's target description. There's one of these + for each inferior. */ -/* A flag indicating that a description has already been fetched from - the current target, so it should not be queried again. */ +struct target_desc_info +{ + /* A flag indicating that a description has already been fetched + from the target, so it should not be queried again. */ -static int target_desc_fetched; + int fetched; -/* The description fetched from the current target, or NULL if the - current target did not supply any description. Only valid when - target_desc_fetched is set. Only the description initialization - code should access this; normally, the description should be - accessed through the gdbarch object. */ + /* The description fetched from the target, or NULL if the target + did not supply any description. Only valid when + target_desc_fetched is set. Only the description initialization + code should access this; normally, the description should be + accessed through the gdbarch object. */ -static const struct target_desc *current_target_desc; + const struct target_desc *tdesc; -/* Other global variables. */ + /* The filename to read a target description from, as set by "set + tdesc filename ..." */ -/* The filename to read a target description from. */ + char *filename; +}; -static char *target_description_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 = XCNEW (struct 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 != NULL && info->filename != NULL; +} + +/* 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->fetched = src->fetched; + dest->tdesc = src->tdesc; + dest->filename = src->filename != NULL ? xstrdup (src->filename) : NULL; +} + +/* See target-descriptions.h. */ + +void +target_desc_info_free (struct target_desc_info *tdesc_info) +{ + if (tdesc_info != NULL) + { + xfree (tdesc_info->filename); + xfree (tdesc_info); + } +} + +/* Convenience helper macros. */ + +#define target_desc_fetched \ + get_tdesc_info (current_inferior ())->fetched +#define current_target_desc \ + get_tdesc_info (current_inferior ())->tdesc +#define target_description_filename \ + get_tdesc_info (current_inferior ())->filename + +/* 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. */ @@ -185,7 +620,7 @@ target_find_description (void) /* 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 (current_gdbarch) == NULL); + gdb_assert (gdbarch_target_desc (target_gdbarch ()) == NULL); /* First try to fetch an XML description from the user-specified file. */ @@ -218,9 +653,10 @@ target_find_description (void) { struct tdesc_arch_data *data; - data = gdbarch_data (current_gdbarch, tdesc_data); + data = ((struct tdesc_arch_data *) + gdbarch_data (target_gdbarch (), tdesc_data)); if (tdesc_has_registers (current_target_desc) - && data->registers == NULL) + && data->arch_regs == NULL) warning (_("Target-supplied registers are not supported " "by the current architecture")); } @@ -263,6 +699,28 @@ target_current_description (void) 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) +{ + const struct bfd_arch_info *compat; + int ix; + + for (ix = 0; VEC_iterate (arch_p, target_desc->compatible, ix, compat); + ix++) + { + if (compat == arch + || arch->compatible (arch, compat) + || compat->compatible (compat, arch)) + return 1; + } + + return 0; +} /* Direct accessors for target descriptions. */ @@ -292,6 +750,16 @@ tdesc_architecture (const struct target_desc *target_desc) { return target_desc->arch; } + +/* 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; +} + /* Return 1 if this target description includes any registers. */ @@ -341,57 +809,312 @@ tdesc_feature_name (const struct tdesc_feature *feature) return feature->name; } -/* Return the type associated with ID in the context of FEATURE, or - NULL if none. */ +/* Predefined types. */ +static struct tdesc_type tdesc_predefined_types[] = +{ + { "bool", TDESC_TYPE_BOOL }, + { "int8", TDESC_TYPE_INT8 }, + { "int16", TDESC_TYPE_INT16 }, + { "int32", TDESC_TYPE_INT32 }, + { "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 } +}; -struct type * +/* Lookup a predefined type. */ + +static struct tdesc_type * +tdesc_predefined_type (enum tdesc_type_kind kind) +{ + int ix; + struct tdesc_type *type; + + for (ix = 0; ix < ARRAY_SIZE (tdesc_predefined_types); ix++) + if (tdesc_predefined_types[ix].kind == kind) + return &tdesc_predefined_types[ix]; + + gdb_assert_not_reached ("bad predefined tdesc type"); +} + +/* See arch/tdesc.h. */ + +struct tdesc_type * tdesc_named_type (const struct tdesc_feature *feature, const char *id) { int ix; - struct type *gdb_type; + struct tdesc_type *type; /* First try target-defined types. */ - for (ix = 0; VEC_iterate (type_p, feature->types, ix, gdb_type); ix++) - if (strcmp (TYPE_NAME (gdb_type), id) == 0) - return gdb_type; + 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; +} - /* Next try some predefined types. Note that none of these types - depend on the current architecture; some of the builtin_type_foo - variables are swapped based on the architecture. */ - if (strcmp (id, "int8") == 0) - return builtin_type_int8; +/* Lookup type associated with ID. */ - if (strcmp (id, "int16") == 0) - return builtin_type_int16; +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; + + 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++) + { + 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 (strcmp (id, "int32") == 0) - return builtin_type_int32; + return NULL; +} - if (strcmp (id, "int64") == 0) - return builtin_type_int64; +/* Construct, if necessary, and return the GDB type implementing target + type TDESC_TYPE for architecture GDBARCH. */ - if (strcmp (id, "uint8") == 0) - return builtin_type_uint8; +static struct type * +tdesc_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *tdesc_type) +{ + struct type *type; - if (strcmp (id, "uint16") == 0) - return builtin_type_uint16; + switch (tdesc_type->kind) + { + /* Predefined types. */ + case TDESC_TYPE_BOOL: + return builtin_type (gdbarch)->builtin_bool; - if (strcmp (id, "uint32") == 0) - return builtin_type_uint32; + case TDESC_TYPE_INT8: + return builtin_type (gdbarch)->builtin_int8; - if (strcmp (id, "uint64") == 0) - return builtin_type_uint64; + case TDESC_TYPE_INT16: + return builtin_type (gdbarch)->builtin_int16; - if (strcmp (id, "ieee_single") == 0) - return builtin_type_ieee_single; + case TDESC_TYPE_INT32: + return builtin_type (gdbarch)->builtin_int32; - if (strcmp (id, "ieee_double") == 0) - return builtin_type_ieee_double; + case TDESC_TYPE_INT64: + return builtin_type (gdbarch)->builtin_int64; - if (strcmp (id, "arm_fpa_ext") == 0) - return builtin_type_arm_ext; + case TDESC_TYPE_INT128: + return builtin_type (gdbarch)->builtin_int128; - return NULL; + 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->start != -1 && f->end != -1) + { + /* Bitfield. */ + struct field *fld; + struct type *field_type; + int bitsize, total_size; + + /* This invariant should be preserved while creating types. */ + gdb_assert (tdesc_type->u.u.size != 0); + if (f->type != NULL) + field_type = tdesc_gdb_type (gdbarch, f->type); + else if (tdesc_type->u.u.size > 4) + field_type = builtin_type (gdbarch)->builtin_uint64; + else + field_type = builtin_type (gdbarch)->builtin_uint32; + + 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 + { + gdb_assert (f->start == -1 && f->end == -1); + field_type = tdesc_gdb_type (gdbarch, f->type); + append_composite_type_field (type, xstrdup (f->name), + field_type); + } + } + + 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_field *f; + int ix; + + type = arch_flags_type (gdbarch, tdesc_type->name, + tdesc_type->u.u.size); + for (ix = 0; + VEC_iterate (tdesc_type_field, tdesc_type->u.u.fields, ix, f); + ix++) + { + struct type *field_type; + int bitsize = f->end - f->start + 1; + + gdb_assert (f->type != NULL); + field_type = tdesc_gdb_type (gdbarch, f->type); + append_flags_type_field (type, f->start, bitsize, + field_type, f->name); + } + + return type; + } + + case TDESC_TYPE_ENUM: + { + struct tdesc_type_field *f; + int ix; + + type = arch_type (gdbarch, TYPE_CODE_ENUM, + tdesc_type->u.u.size, tdesc_type->name); + TYPE_UNSIGNED (type) = 1; + for (ix = 0; + VEC_iterate (tdesc_type_field, tdesc_type->u.u.fields, ix, f); + ix++) + { + struct field *fld + = append_composite_type_field_raw (type, xstrdup (f->name), + NULL); + + SET_FIELD_BITPOS (fld[0], f->start); + } + + return type; + } + } + + internal_error (__FILE__, __LINE__, + "Type \"%s\" has an unknown kind %d", + tdesc_type->name, tdesc_type->kind); } @@ -414,7 +1137,7 @@ tdesc_data_init (struct obstack *obstack) struct tdesc_arch_data * tdesc_data_alloc (void) { - return XZALLOC (struct tdesc_arch_data); + return XCNEW (struct tdesc_arch_data); } /* Free something allocated by tdesc_data_alloc, if it is not going @@ -424,18 +1147,17 @@ tdesc_data_alloc (void) void tdesc_data_cleanup (void *data_untyped) { - struct tdesc_arch_data *data = data_untyped; + struct tdesc_arch_data *data = (struct tdesc_arch_data *) data_untyped; - VEC_free (tdesc_reg_p, data->registers); + VEC_free (tdesc_arch_reg, data->arch_regs); xfree (data); } /* Search FEATURE for a register named NAME. */ -int -tdesc_numbered_register (const struct tdesc_feature *feature, - struct tdesc_arch_data *data, - int regno, const char *name) +static struct tdesc_reg * +tdesc_find_register_early (const struct tdesc_feature *feature, + const char *name) { int ixr; struct tdesc_reg *reg; @@ -444,18 +1166,50 @@ tdesc_numbered_register (const struct tdesc_feature *feature, VEC_iterate (tdesc_reg_p, feature->registers, ixr, reg); ixr++) if (strcasecmp (reg->name, name) == 0) - { - /* Make sure the vector includes a REGNO'th element. */ - while (regno >= VEC_length (tdesc_reg_p, data->registers)) - VEC_safe_push (tdesc_reg_p, data->registers, NULL); - VEC_replace (tdesc_reg_p, data->registers, regno, reg); - return 1; - } + return reg; - return 0; + 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_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); + + arch_reg.reg = reg; + VEC_replace (tdesc_arch_reg, data->arch_regs, regno, &arch_reg); + return 1; } -/* Search FEATURE for a register whose name is in NAMES. */ +/* 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, @@ -471,105 +1225,139 @@ tdesc_numbered_register_choices (const struct tdesc_feature *feature, return 0; } +/* Search FEATURE for a register named NAME, and return its size in + bits. The register must exist. */ + +int +tdesc_register_size (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_reg * -tdesc_find_register (struct gdbarch *gdbarch, int regno) +static struct tdesc_arch_reg * +tdesc_find_arch_register (struct gdbarch *gdbarch, int regno) { - struct tdesc_reg *reg; struct tdesc_arch_data *data; - data = gdbarch_data (gdbarch, tdesc_data); - if (regno < VEC_length (tdesc_reg_p, data->registers)) - return VEC_index (tdesc_reg_p, data->registers, regno); + 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); 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 (int regno) +tdesc_register_name (struct gdbarch *gdbarch, int regno) { - struct tdesc_reg *reg = tdesc_find_register (current_gdbarch, regno); - int num_regs = gdbarch_num_regs (current_gdbarch); - int num_pseudo_regs = gdbarch_num_pseudo_regs (current_gdbarch); + 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; if (regno >= num_regs && regno < num_regs + num_pseudo_regs) { - struct tdesc_arch_data *data = gdbarch_data (current_gdbarch, - tdesc_data); + 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 (regno); + return data->pseudo_register_name (gdbarch, regno); } return ""; } -static struct type * +struct type * tdesc_register_type (struct gdbarch *gdbarch, int regno) { - struct tdesc_reg *reg = tdesc_find_register (gdbarch, 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 = gdbarch_data (gdbarch, tdesc_data); + 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_int0; - - /* First check for a predefined or target defined type. */ - if (reg->gdb_type) - return reg->gdb_type; + return builtin_type (gdbarch)->builtin_int0; - /* Next try size-sensitive type shortcuts. */ - if (strcmp (reg->type, "float") == 0) - { - if (reg->bitsize == gdbarch_float_bit (gdbarch)) - return builtin_type_float; - else if (reg->bitsize == gdbarch_double_bit (gdbarch)) - return builtin_type_double; - else if (reg->bitsize == gdbarch_long_double_bit (gdbarch)) - return builtin_type_long_double; - } - else if (strcmp (reg->type, "int") == 0) + if (arch_reg->type == NULL) { - if (reg->bitsize == gdbarch_long_bit (gdbarch)) - return builtin_type_long; - else if (reg->bitsize == TARGET_CHAR_BIT) - return builtin_type_char; - else if (reg->bitsize == gdbarch_short_bit (gdbarch)) - return builtin_type_short; - else if (reg->bitsize == gdbarch_int_bit (gdbarch)) - return builtin_type_int; - else if (reg->bitsize == gdbarch_long_long_bit (gdbarch)) - return builtin_type_long_long; - else if (reg->bitsize == gdbarch_ptr_bit (gdbarch)) - /* A bit desperate by this point... */ - return builtin_type_void_data_ptr; + /* First check for a predefined or target defined type. */ + if (reg->tdesc_type) + arch_reg->type = tdesc_gdb_type (gdbarch, reg->tdesc_type); + + /* Next try size-sensitive type shortcuts. */ + else if (strcmp (reg->type, "float") == 0) + { + 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, reg->bitsize); + arch_reg->type = builtin_type (gdbarch)->builtin_double; + } + } + else if (strcmp (reg->type, "int") == 0) + { + 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, 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, reg->type); } - else if (strcmp (reg->type, "code_ptr") == 0) - return builtin_type_void_func_ptr; - else if (strcmp (reg->type, "data_ptr") == 0) - return builtin_type_void_data_ptr; - else - internal_error (__FILE__, __LINE__, - "Register \"%s\" has an unknown type \"%s\"", - reg->name, reg->type); - warning (_("Register \"%s\" has an unsupported size (%d bits)"), - reg->name, reg->bitsize); - return builtin_type_long; + return arch_reg->type; } static int @@ -646,9 +1434,12 @@ tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regno, if (regno >= num_regs && regno < num_regs + num_pseudo_regs) { - struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data); - gdb_assert (data->pseudo_register_reggroup_p != NULL); - return data->pseudo_register_reggroup_p (gdbarch, regno, reggroup); + 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); @@ -665,7 +1456,8 @@ void set_tdesc_pseudo_register_name (struct gdbarch *gdbarch, gdbarch_register_name_ftype *pseudo_name) { - struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data); + struct tdesc_arch_data *data + = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); data->pseudo_register_name = pseudo_name; } @@ -674,7 +1466,8 @@ void set_tdesc_pseudo_register_type (struct gdbarch *gdbarch, gdbarch_register_type_ftype *pseudo_type) { - struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data); + struct tdesc_arch_data *data + = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); data->pseudo_register_type = pseudo_type; } @@ -684,7 +1477,8 @@ set_tdesc_pseudo_register_reggroup_p (struct gdbarch *gdbarch, gdbarch_register_reggroup_p_ftype *pseudo_reggroup_p) { - struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data); + struct tdesc_arch_data *data + = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); data->pseudo_register_reggroup_p = pseudo_reggroup_p; } @@ -693,26 +1487,25 @@ 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) { int num_regs = gdbarch_num_regs (gdbarch); - int i, ixf, ixr; - const struct target_desc *target_desc; + 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; - target_desc = gdbarch_target_desc (gdbarch); - /* 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 = gdbarch_data (gdbarch, tdesc_data); - data->registers = early_data->registers; + data = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); + data->arch_regs = early_data->arch_regs; xfree (early_data); /* Build up a set of all registers, so that we can assign register @@ -733,18 +1526,20 @@ tdesc_use_registers (struct gdbarch *gdbarch, /* Remove any registers which were assigned numbers by the architecture. */ - for (ixr = 0; VEC_iterate (tdesc_reg_p, data->registers, ixr, reg); ixr++) - if (reg) - htab_remove_elt (reg_hash, reg); + 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); /* 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_reg_p, data->registers) <= num_regs); - while (VEC_length (tdesc_reg_p, data->registers) < num_regs) - VEC_safe_push (tdesc_reg_p, data->registers, NULL); + 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++) @@ -753,7 +1548,8 @@ tdesc_use_registers (struct gdbarch *gdbarch, ixr++) if (htab_find (reg_hash, reg) != NULL) { - VEC_safe_push (tdesc_reg_p, data->registers, reg); + new_arch_reg.reg = reg; + VEC_safe_push (tdesc_arch_reg, data->arch_regs, &new_arch_reg); num_regs++; } @@ -769,109 +1565,212 @@ tdesc_use_registers (struct gdbarch *gdbarch, } -/* 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 arch/tdesc.h. */ void tdesc_create_reg (struct tdesc_feature *feature, const char *name, int regnum, int save_restore, const char *group, int bitsize, const char *type) { - struct tdesc_reg *reg = XZALLOC (struct tdesc_reg); + tdesc_reg *reg = new tdesc_reg (feature, name, regnum, save_restore, + group, bitsize, type); - 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 (""); + VEC_safe_push (tdesc_reg_p, feature->registers, reg); +} - /* 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->gdb_type = tdesc_named_type (feature, reg->type); +/* See arch/tdesc.h. */ - VEC_safe_push (tdesc_reg_p, feature->registers, reg); +struct tdesc_type * +tdesc_create_vector (struct tdesc_feature *feature, const char *name, + struct tdesc_type *field_type, int count) +{ + struct tdesc_type *type = new tdesc_type (name, TDESC_TYPE_VECTOR); + + type->u.v.type = field_type; + type->u.v.count = count; + + VEC_safe_push (tdesc_type_p, feature->types, type); + return type; } -static void -tdesc_free_feature (struct tdesc_feature *feature) +/* See arch/tdesc.h. */ + +struct tdesc_type * +tdesc_create_struct (struct tdesc_feature *feature, const char *name) { - struct tdesc_reg *reg; - int ix; + struct tdesc_type *type = new tdesc_type (name, TDESC_TYPE_STRUCT); - for (ix = 0; VEC_iterate (tdesc_reg_p, feature->registers, ix, reg); ix++) - tdesc_free_reg (reg); - VEC_free (tdesc_reg_p, feature->registers); + VEC_safe_push (tdesc_type_p, feature->types, type); + return type; +} - /* There is no easy way to free xmalloc-allocated types, nor is - there a way to allocate types on an obstack not associated with - an objfile. Therefore we never free types. Since we only ever - parse an identical XML document once, this memory leak is mostly - contained. */ - VEC_free (type_p, feature->types); +/* See arch/tdesc.h. */ - xfree (feature->name); - xfree (feature); +void +tdesc_set_struct_size (struct tdesc_type *type, int size) +{ + gdb_assert (type->kind == TDESC_TYPE_STRUCT); + gdb_assert (size > 0); + type->u.u.size = size; } -struct tdesc_feature * -tdesc_create_feature (struct target_desc *tdesc, const char *name) +/* See arch/tdesc.h. */ + +struct tdesc_type * +tdesc_create_union (struct tdesc_feature *feature, const char *name) { - struct tdesc_feature *new_feature = XZALLOC (struct tdesc_feature); + struct tdesc_type *type = new tdesc_type (name, TDESC_TYPE_UNION); - new_feature->name = xstrdup (name); + VEC_safe_push (tdesc_type_p, feature->types, type); + return type; +} - VEC_safe_push (tdesc_feature_p, tdesc->features, new_feature); - return new_feature; +/* See arch/tdesc.h. */ + +struct tdesc_type * +tdesc_create_flags (struct tdesc_feature *feature, const char *name, + int size) +{ + struct tdesc_type *type = new tdesc_type (name, TDESC_TYPE_FLAGS); + + gdb_assert (size > 0); + + type->u.u.size = size; + + VEC_safe_push (tdesc_type_p, feature->types, type); + return type; +} + +struct tdesc_type * +tdesc_create_enum (struct tdesc_feature *feature, const char *name, + int size) +{ + struct tdesc_type *type = new tdesc_type (name, TDESC_TYPE_ENUM); + + gdb_assert (size > 0); + + type->u.u.size = size; + + VEC_safe_push (tdesc_type_p, feature->types, type); + return type; +} + +/* See arch/tdesc.h. */ + +void +tdesc_add_field (struct tdesc_type *type, const char *field_name, + struct tdesc_type *field_type) +{ + struct tdesc_type_field f = { 0 }; + + gdb_assert (type->kind == TDESC_TYPE_UNION + || type->kind == TDESC_TYPE_STRUCT); + + f.name = xstrdup (field_name); + f.type = field_type; + /* Initialize these values so we know this is not a bit-field + when we print-c-tdesc. */ + f.start = -1; + f.end = -1; + + VEC_safe_push (tdesc_type_field, type->u.u.fields, &f); } void -tdesc_record_type (struct tdesc_feature *feature, struct type *type) +tdesc_add_typed_bitfield (struct tdesc_type *type, const char *field_name, + int start, int end, struct tdesc_type *field_type) { - /* The type's ID should be used as its TYPE_NAME. */ - gdb_assert (TYPE_NAME (type) != NULL); + struct tdesc_type_field f = { 0 }; + + gdb_assert (type->kind == TDESC_TYPE_STRUCT + || type->kind == TDESC_TYPE_FLAGS); + gdb_assert (start >= 0 && end >= start); + + f.name = xstrdup (field_name); + f.start = start; + f.end = end; + f.type = field_type; - VEC_safe_push (type_p, feature->types, type); + VEC_safe_push (tdesc_type_field, type->u.u.fields, &f); +} + +/* See arch/tdesc.h. */ + +void +tdesc_add_bitfield (struct tdesc_type *type, const char *field_name, + int start, int end) +{ + struct tdesc_type *field_type; + + gdb_assert (start >= 0 && end >= start); + + if (type->u.u.size > 4) + field_type = tdesc_predefined_type (TDESC_TYPE_UINT64); + else + field_type = tdesc_predefined_type (TDESC_TYPE_UINT32); + + tdesc_add_typed_bitfield (type, field_name, start, end, field_type); +} + +/* See arch/tdesc.h. */ + +void +tdesc_add_flag (struct tdesc_type *type, int start, + const char *flag_name) +{ + struct tdesc_type_field f = { 0 }; + + gdb_assert (type->kind == TDESC_TYPE_FLAGS + || type->kind == TDESC_TYPE_STRUCT); + + f.name = xstrdup (flag_name); + f.start = start; + f.end = start; + f.type = tdesc_predefined_type (TDESC_TYPE_BOOL); + + VEC_safe_push (tdesc_type_field, type->u.u.fields, &f); +} + +void +tdesc_add_enum_value (struct tdesc_type *type, int value, + const char *name) +{ + struct tdesc_type_field f = { 0 }; + + gdb_assert (type->kind == TDESC_TYPE_ENUM); + + f.name = xstrdup (name); + f.start = value; + f.end = -1; + f.type = tdesc_predefined_type (TDESC_TYPE_INT32); + + VEC_safe_push (tdesc_type_field, type->u.u.fields, &f); +} + +/* See arch/tdesc.h. */ + +struct tdesc_feature * +tdesc_create_feature (struct target_desc *tdesc, const char *name, + const char *xml) +{ + struct tdesc_feature *new_feature = new tdesc_feature (name); + + VEC_safe_push (tdesc_feature_p, tdesc->features, new_feature); + return new_feature; } struct target_desc * allocate_target_description (void) { - return XZALLOC (struct target_desc); + return new target_desc (); } static void free_target_description (void *arg) { - struct target_desc *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); + struct target_desc *target_desc = (struct target_desc *) arg; - xfree (target_desc); + delete target_desc; } struct cleanup * @@ -880,6 +1779,30 @@ make_cleanup_free_target_description (struct target_desc *target_desc) return make_cleanup (free_target_description, target_desc); } +void +tdesc_add_compatible (struct target_desc *target_desc, + const struct bfd_arch_info *compatible) +{ + const struct bfd_arch_info *compat; + int ix; + + /* 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 (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); + + VEC_safe_push (arch_p, target_desc->compatible, compatible); +} + void set_tdesc_property (struct target_desc *target_desc, const char *key, const char *value) @@ -906,6 +1829,12 @@ set_tdesc_architecture (struct target_desc *target_desc, { target_desc->arch = arch; } + +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; @@ -916,7 +1845,7 @@ static struct cmd_list_element *tdesc_unset_cmdlist; static void set_tdesc_cmd (char *args, int from_tty) { - help_list (tdesc_set_cmdlist, "set tdesc ", -1, gdb_stdout); + help_list (tdesc_set_cmdlist, "set tdesc ", all_commands, gdb_stdout); } static void @@ -928,13 +1857,16 @@ show_tdesc_cmd (char *args, int from_tty) static void unset_tdesc_cmd (char *args, int from_tty) { - help_list (tdesc_unset_cmdlist, "unset tdesc ", -1, gdb_stdout); + help_list (tdesc_unset_cmdlist, "unset tdesc ", all_commands, gdb_stdout); } static void set_tdesc_filename_cmd (char *args, int from_tty, struct cmd_list_element *c) { + xfree (target_description_filename); + target_description_filename = xstrdup (tdesc_filename_cmd_string); + target_clear_description (); target_find_description (); } @@ -944,13 +1876,14 @@ show_tdesc_filename_cmd (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { + value = target_description_filename; + if (value != NULL && *value != '\0') - printf_filtered (_("\ -The target description will be read from \"%s\".\n"), + 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")); + printf_filtered (_("The target description will be " + "read from the target.\n")); } static void @@ -962,6 +1895,484 @@ unset_tdesc_filename_cmd (char *args, int from_tty) 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 + *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 + (" struct target_desc *result = allocate_target_description ();\n"); + + if (tdesc_architecture (e) != NULL) + { + printf_unfiltered + (" set_tdesc_architecture (result, bfd_scan_arch (\"%s\"));\n", + tdesc_architecture (e)->printable_name); + printf_unfiltered ("\n"); + } + if (tdesc_osabi (e) > GDB_OSABI_UNKNOWN + && tdesc_osabi (e) < GDB_OSABI_INVALID) + { + printf_unfiltered + (" set_tdesc_osabi (result, osabi_from_tdesc_string (\"%s\"));\n", + gdbarch_osabi_name (tdesc_osabi (e))); + printf_unfiltered ("\n"); + } + + int ix; + const struct bfd_arch_info *compatible; + struct property *prop; + + for (ix = 0; VEC_iterate (arch_p, e->compatible, ix, compatible); + ix++) + { + printf_unfiltered + (" tdesc_add_compatible (result, bfd_scan_arch (\"%s\"));\n", + compatible->printable_name); + } + + if (ix) + printf_unfiltered ("\n"); + + for (ix = 0; VEC_iterate (property_s, e->properties, ix, prop); + ix++) + { + printf_unfiltered (" set_tdesc_property (result, \"%s\", \"%s\");\n", + prop->key, prop->value); + } + printf_unfiltered (" struct tdesc_feature *feature;\n"); + } + + void visit_pre (const tdesc_feature *e) override + { + printf_unfiltered ("\n feature = tdesc_create_feature (result, \"%s\");\n", + e->name); + } + + void visit_post (const tdesc_feature *e) override + {} + + void visit_post (const target_desc *e) override + { + printf_unfiltered ("\n tdesc_%s = result;\n", m_function); + printf_unfiltered ("}\n"); + } + + void visit (const tdesc_type *type) override + { + struct tdesc_type_field *f; + + /* Now we do some "filtering" in order to know which variables to + declare. This is needed because otherwise we would declare unused + variables `field_type' and `type'. */ + if (!m_printed_field_type) + { + printf_unfiltered (" struct tdesc_type *field_type;\n"); + m_printed_field_type = true; + } + + if ((type->kind == TDESC_TYPE_UNION + || type->kind == TDESC_TYPE_STRUCT + || type->kind == TDESC_TYPE_FLAGS + || type->kind == TDESC_TYPE_ENUM) + && VEC_length (tdesc_type_field, type->u.u.fields) > 0 + && !m_printed_type) + { + printf_unfiltered (" struct tdesc_type *type;\n"); + m_printed_type = true; + } + + switch (type->kind) + { + case TDESC_TYPE_VECTOR: + printf_unfiltered + (" field_type = tdesc_named_type (feature, \"%s\");\n", + type->u.v.type->name); + printf_unfiltered + (" tdesc_create_vector (feature, \"%s\", field_type, %d);\n", + type->name, type->u.v.count); + break; + case TDESC_TYPE_STRUCT: + case TDESC_TYPE_FLAGS: + if (type->kind == TDESC_TYPE_STRUCT) + { + printf_unfiltered + (" type = tdesc_create_struct (feature, \"%s\");\n", + type->name); + if (type->u.u.size != 0) + printf_unfiltered + (" tdesc_set_struct_size (type, %d);\n", + type->u.u.size); + } + else + { + printf_unfiltered + (" type = tdesc_create_flags (feature, \"%s\", %d);\n", + type->name, type->u.u.size); + } + for (int ix3 = 0; + VEC_iterate (tdesc_type_field, type->u.u.fields, ix3, f); + ix3++) + { + const char *type_name; + + gdb_assert (f->type != NULL); + type_name = f->type->name; + + /* To minimize changes to generated files, don't emit type + info for fields that have defaulted types. */ + if (f->start != -1) + { + gdb_assert (f->end != -1); + if (f->type->kind == TDESC_TYPE_BOOL) + { + gdb_assert (f->start == f->end); + printf_unfiltered + (" tdesc_add_flag (type, %d, \"%s\");\n", + f->start, f->name); + } + else if ((type->u.u.size == 4 + && f->type->kind == TDESC_TYPE_UINT32) + || (type->u.u.size == 8 + && f->type->kind == TDESC_TYPE_UINT64)) + { + printf_unfiltered + (" tdesc_add_bitfield (type, \"%s\", %d, %d);\n", + f->name, f->start, f->end); + } + else + { + printf_unfiltered + (" field_type = tdesc_named_type (feature," + " \"%s\");\n", + type_name); + printf_unfiltered + (" tdesc_add_typed_bitfield (type, \"%s\"," + " %d, %d, field_type);\n", + f->name, f->start, f->end); + } + } + else /* Not a bitfield. */ + { + gdb_assert (f->end == -1); + gdb_assert (type->kind == TDESC_TYPE_STRUCT); + printf_unfiltered + (" field_type = tdesc_named_type (feature," + " \"%s\");\n", + type_name); + printf_unfiltered + (" tdesc_add_field (type, \"%s\", field_type);\n", + f->name); + } + } + break; + case TDESC_TYPE_UNION: + printf_unfiltered + (" type = tdesc_create_union (feature, \"%s\");\n", + type->name); + for (int ix3 = 0; + VEC_iterate (tdesc_type_field, type->u.u.fields, ix3, f); + ix3++) + { + printf_unfiltered + (" field_type = tdesc_named_type (feature, \"%s\");\n", + f->type->name); + printf_unfiltered + (" tdesc_add_field (type, \"%s\", field_type);\n", + f->name); + } + break; + case TDESC_TYPE_ENUM: + printf_unfiltered + (" type = tdesc_create_enum (feature, \"%s\", %d);\n", + type->name, type->u.u.size); + for (int ix3 = 0; + VEC_iterate (tdesc_type_field, type->u.u.fields, ix3, f); + ix3++) + printf_unfiltered + (" tdesc_add_enum_value (type, %d, \"%s\");\n", + f->start, f->name); + break; + default: + error (_("C output is not supported type \"%s\"."), type->name); + } + printf_unfiltered ("\n"); + } + + void visit (const tdesc_reg *reg) override + { + printf_unfiltered (" tdesc_create_reg (feature, \"%s\", %ld, %d, ", + reg->name, reg->target_regnum, reg->save_restore); + if (reg->group) + printf_unfiltered ("\"%s\", ", reg->group); + else + printf_unfiltered ("NULL, "); + printf_unfiltered ("%d, \"%s\");\n", reg->bitsize, reg->type); + } + +protected: + std::string m_filename_after_features; + +private: + char *m_function; + bool m_printed_field_type = false; + bool m_printed_type = false; +}; + +/* Print target description feature in C. */ + +class print_c_feature : public print_c_tdesc +{ +public: + print_c_feature (std::string &file) + : print_c_tdesc (file) + { + /* Trim ".tmp". */ + auto const pos = m_filename_after_features.find_last_of ('.'); + + m_filename_after_features = m_filename_after_features.substr (0, pos); + } + + void visit_pre (const target_desc *e) override + { + printf_unfiltered (" Original: %s */\n\n", + lbasename (m_filename_after_features.c_str ())); + + printf_unfiltered ("#include \"arch/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\", \"%s\");\n", + e->name, lbasename (m_filename_after_features.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, reg->save_restore); + if (reg->group) + printf_unfiltered ("\"%s\", ", reg->group); + else + printf_unfiltered ("NULL, "); + printf_unfiltered ("%d, \"%s\");\n", reg->bitsize, reg->type); + + m_next_regnum++; + } + +private: + /* The register number to use for the next register we see. */ + int m_next_regnum = 0; +}; + +static void +maint_print_c_tdesc_cmd (char *args, int from_tty) +{ + const struct target_desc *tdesc; + const char *filename; + + if (args == NULL) + { + /* Use the global target-supplied description, not the current + architecture's. This lets a GDB for one architecture generate C + for another architecture's description, even though the gdbarch + initialization code will reject the new description. */ + tdesc = current_target_desc; + filename = target_description_filename; + } + else + { + /* Use the target description from the XML file. */ + filename = args; + tdesc = file_read_description_xml (filename); + } + + if (tdesc == NULL) + error (_("There is no target description to print.")); + + if (filename == NULL) + error (_("The current target description did not come from an XML file.")); + + std::string filename_after_features (filename); + auto loc = filename_after_features.rfind ("/features/"); + + if (loc != std::string::npos) + filename_after_features = filename_after_features.substr (loc + 10); + + /* Print c files for target features instead of target descriptions, + because c files got from target features are more flexible than the + counterparts. */ + if (startswith (filename_after_features.c_str (), "i386/32bit-")) + { + print_c_feature v (filename_after_features); + + tdesc->accept (v); + } + else + { + print_c_tdesc v (filename_after_features); + + tdesc->accept (v); + } +} + +namespace selftests { + +static std::vector> xml_tdesc; + +#if GDB_SELF_TEST + +/* See target-descritpions.h. */ + +void +record_xml_tdesc (const char *xml_file, const struct target_desc *tdesc) +{ + xml_tdesc.emplace_back (xml_file, tdesc); +} +#endif + +} + +/* Check that the target descriptions created dynamically by + architecture-specific code equal the descriptions created from XML files + found in the specified directory DIR. */ + +static void +maintenance_check_xml_descriptions (char *dir, int from_tty) +{ + if (dir == NULL) + error (_("Missing dir name")); + + gdb::unique_xmalloc_ptr dir1 (tilde_expand (dir)); + std::string feature_dir (dir1.get ()); + unsigned int failed = 0; + + for (auto const &e : selftests::xml_tdesc) + { + std::string tdesc_xml = (feature_dir + SLASH_STRING + e.first); + const target_desc *tdesc + = file_read_description_xml (tdesc_xml.data ()); + + if (tdesc == NULL || *tdesc != *e.second) + failed++; + } + printf_filtered (_("Tested %lu XML files, %d failed\n"), + (long) selftests::xml_tdesc.size (), failed); +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_target_descriptions; + void _initialize_target_descriptions (void) { @@ -981,7 +2392,7 @@ Unset target description specific variables."), 0 /* allow-unknown */, &unsetlist); add_setshow_filename_cmd ("filename", class_obscure, - &target_description_filename, + &tdesc_filename_cmd_string, _("\ Set the file to read for an XML target description"), _("\ Show the file to read for an XML target description"), _("\ @@ -995,4 +2406,18 @@ file instead of querying the remote target."), Unset the file to read for an XML target description. When unset,\n\ 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); + + cmd_list_element *cmd; + + cmd = add_cmd ("xml-descriptions", class_maintenance, + maintenance_check_xml_descriptions, _("\ +Check the target descriptions created in GDB equal the descriptions\n\ +created from XML files in the directory.\n\ +The parameter is the directory name."), + &maintenancechecklist); + set_cmd_completer (cmd, filename_completer); }