diff options
author | Daniel Jacobowitz <dan@debian.org> | 2007-02-08 21:00:36 +0000 |
---|---|---|
committer | Daniel Jacobowitz <dan@debian.org> | 2007-02-08 21:00:36 +0000 |
commit | a0a9363e8b61c8cb09fc1effc2bb67e7cd597053 (patch) | |
tree | 994752af44fc36efd9c7e410b16b18f5ce362b4c /gdb/target-descriptions.c | |
parent | ff36d6a0881de163cba5405f4d7e1003459ce021 (diff) | |
download | gdb-a0a9363e8b61c8cb09fc1effc2bb67e7cd597053.tar.gz |
* Makefile.in (arm-tdep.o, eval.o, target-descriptions.o)
(xml-tdesc.o): Update.
* xml-support.c: Add a comment.
(gdb_xml_enums_boolean): New variable.
(gdb_xml_parse_attr_enum): Use strcasecmp.
* xml-support.h (gdb_xml_enums_boolean): Declare.
* xml-tdesc.c (struct tdesc_parsing_data): Record current_feature,
next_regnum, and current_union.
(tdesc_start_feature, tdesc_start_reg, tdesc_start_union)
(tdesc_end_union, tdesc_start_field, tdesc_start_vector)
(field_attributes, union_children, reg_attributes, union_attributes)
(vector_attributes, feature_attributes, feature_children): New.
(target_children): Make static. Add <feature>.
(tdesc_elements): Make static.
* target-descriptions.c (struct tdesc_reg, tdesc_reg_p, type_p)
(struct tdesc_feature, tdesc_feature_p): New types.
(struct target_desc): Add features member.
(struct tdesc_arch_data, tdesc_data): New.
(target_find_description): Clarify error message. Warn about
ignored register descriptions.
(tdesc_has_registers, tdesc_find_feature, tdesc_feature_name)
(tdesc_named_type, tdesc_data_init, tdesc_data_alloc)
(tdesc_data_cleanup, tdesc_numbered_register)
(tdesc_numbered_register_choices, tdesc_find_register)
(tdesc_register_name, tdesc_register_type)
(tdesc_remote_register_number, tdesc_register_reggroup_p)
(set_tdesc_pseudo_register_name, set_tdesc_pseudo_register_type)
(set_tdesc_pseudo_register_reggroup_p, tdesc_use_registers)
(tdesc_free_reg, tdesc_create_reg, tdesc_free_feature)
(tdesc_create_feature, tdesc_record_type): New.
(free_target_description): Free features.
(_initialize_target_descriptions): Initialize tdesc_data.
* arch-utils.c (default_remote_register_number): New.
* arch-utils.h (default_remote_register_number): New prototype.
* target-descriptions.h (set_tdesc_pseudo_register_name)
(set_tdesc_pseudo_register_type, set_tdesc_pseudo_register_reggroup_p)
(tdesc_use_registers, tdesc_data_alloc, tdesc_data_cleanup)
(tdesc_numbered_register, tdesc_numbered_register_choices)
(tdesc_has_registers, tdesc_find_feature, tdesc_feature_name)
(tdesc_named_type, tdesc_create_feature, tdesc_record_type)
(tdesc_create_reg): Declare.
* gdbarch.sh (remote_register_number): New entry.
* gdbarch.c, gdbarch.h: Regenerate.
* remote.c (init_remote_state): Use gdbarch_remote_register_number.
* features/gdb-target.dtd: Add feature, reg, vector, union, and field.
* arm-tdep.c (arm_register_aliases): New.
(arm_register_name_strings): Rename to...
(arm_register_names): ...this. Make const. Delete the old version.
(current_option, arm_register_byte): Delete.
(set_disassembly_style): Simplify. Do not adjust arm_register_names.
(value_of_arm_user_reg): New.
(arm_gdbarch_init): Verify any described registers. Call
tdesc_use_registers. Don't use arm_register_byte. Create aliases
for standard register names.
(_initialize_arm_tdep): Do not adjust arm_register_names.
* user-regs.c (struct user_reg): Add baton member.
(append_user_reg, user_reg_add_builtin, user_regs_init)
(user_reg_add, value_of_user_reg): Use a baton for user
register functions.
* std-regs.c: Update.
* user-regs.h (user_reg_read_ftype, user_reg_add_builtin)
(user_reg_add): Add baton argument.
* NEWS: Mention target description register support.
* features/arm-core.xml, features/arm-fpa.xml: New.
* eval.c (evaluate_subexp_standard): Allow ptype $register
when the program is not running.
* gdb.texinfo (-target-disconnect): Use @smallexample.
(Requirements): Add anchor for Expat. Update description.
(Target Descriptions): Mention Expat.
(Target Description Format): Document new elements. Use
@smallexample.
(Predefined Target Types, Standard Target Features): New sections.
* doc/gdbint.texinfo (Target Descriptions): New section.
* gdb.xml/single-reg.xml, gdb.xml/tdesc-regs.exp,
gdb.xml/core-only.xml, gdb.xml/extra-regs.xml: New files.
Diffstat (limited to 'gdb/target-descriptions.c')
-rw-r--r-- | gdb/target-descriptions.c | 641 |
1 files changed, 639 insertions, 2 deletions
diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c index 1100f5ebaf3..1f8cf7e17e5 100644 --- a/gdb/target-descriptions.c +++ b/gdb/target-descriptions.c @@ -24,12 +24,17 @@ #include "defs.h" #include "arch-utils.h" #include "gdbcmd.h" +#include "gdbtypes.h" +#include "reggroups.h" #include "target.h" #include "target-descriptions.h" #include "vec.h" +#include "xml-support.h" #include "xml-tdesc.h" #include "gdb_assert.h" +#include "gdb_obstack.h" +#include "hashtab.h" /* Types. */ @@ -40,6 +45,69 @@ typedef struct property } 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 type *gdb_type; +} *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); + +/* A feature from a target description. Each feature is a collection + of other elements, e.g. registers and types. */ + +typedef struct tdesc_feature +{ + /* 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; + + /* The types associated with this feature. */ + VEC(type_p) *types; +} *tdesc_feature_p; +DEF_VEC_P(tdesc_feature_p); + +/* A target description. */ + struct target_desc { /* The architecture reported by the target, if any. */ @@ -47,6 +115,30 @@ struct target_desc /* Any architecture-specific properties specified by the target. */ VEC(property_s) *properties; + + /* The features associated with this target. */ + VEC(tdesc_feature_p) *features; +}; + +/* Per-architecture data associated with a target description. The + target description may be shared by multiple architectures, but + this data is private to one gdbarch. */ + +struct tdesc_arch_data +{ + /* A list of registers, 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; + + /* 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; }; /* Global state. These variables are associated with the current @@ -72,6 +164,11 @@ static const struct target_desc *current_target_desc; static char *target_description_filename; +/* A handle for architecture-specific data associated with the + target description (see struct tdesc_arch_data). */ + +static struct gdbarch_data *tdesc_data; + /* Fetch the current target's description, and switch the current architecture to one which incorporates that description. */ @@ -116,7 +213,17 @@ target_find_description (void) gdbarch_info_init (&info); info.target_desc = current_target_desc; if (!gdbarch_update_p (info)) - warning (_("Could not use target-supplied description")); + warning (_("Architecture rejected target-supplied description")); + else + { + struct tdesc_arch_data *data; + + data = gdbarch_data (current_gdbarch, tdesc_data); + if (tdesc_has_registers (current_target_desc) + && data->registers == NULL) + warning (_("Target-supplied registers are not supported " + "by the current architecture")); + } } /* Now that we know this description is usable, record that we @@ -158,7 +265,7 @@ target_current_description (void) } -/* Direct accessors for feature sets. */ +/* Direct accessors for target descriptions. */ /* Return the string value of a property named KEY, or NULL if the property was not specified. */ @@ -187,8 +294,529 @@ tdesc_architecture (const struct target_desc *target_desc) } +/* 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)) + return 1; + + return 0; +} + +/* Return the feature with the given name, if present, or NULL if + the named feature is not found. */ + +const struct tdesc_feature * +tdesc_find_feature (const struct target_desc *target_desc, + const char *name) +{ + 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; + + return NULL; +} + +/* Return the name of FEATURE. */ + +const char * +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. */ + +struct type * +tdesc_named_type (const struct tdesc_feature *feature, const char *id) +{ + int ix; + struct type *gdb_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; + + /* 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; + + if (strcmp (id, "int16") == 0) + return builtin_type_int16; + + if (strcmp (id, "int32") == 0) + return builtin_type_int32; + + if (strcmp (id, "int64") == 0) + return builtin_type_int64; + + if (strcmp (id, "uint8") == 0) + return builtin_type_uint8; + + if (strcmp (id, "uint16") == 0) + return builtin_type_uint16; + + if (strcmp (id, "uint32") == 0) + return builtin_type_uint32; + + if (strcmp (id, "uint64") == 0) + return builtin_type_uint64; + + if (strcmp (id, "code_ptr") == 0) + return builtin_type_void_func_ptr; + + if (strcmp (id, "data_ptr") == 0) + return builtin_type_void_data_ptr; + + if (strcmp (id, "arm_fpa_ext") == 0) + return builtin_type_arm_ext; + + return NULL; +} + + +/* Support for registers from target descriptions. */ + +/* Construct the per-gdbarch data. */ + +static void * +tdesc_data_init (struct obstack *obstack) +{ + struct tdesc_arch_data *data; + + data = OBSTACK_ZALLOC (obstack, struct tdesc_arch_data); + return data; +} + +/* Similar, but for the temporary copy used during architecture + initialization. */ + +struct tdesc_arch_data * +tdesc_data_alloc (void) +{ + return XZALLOC (struct 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). */ + +void +tdesc_data_cleanup (void *data_untyped) +{ + struct tdesc_arch_data *data = data_untyped; + + VEC_free (tdesc_reg_p, data->registers); + 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) +{ + 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) + { + /* 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 0; +} + +/* Search FEATURE for a register whose name is in NAMES. */ + +int +tdesc_numbered_register_choices (const struct tdesc_feature *feature, + struct tdesc_arch_data *data, + int regno, const char *const names[]) +{ + int i; + + for (i = 0; names[i] != NULL; i++) + if (tdesc_numbered_register (feature, data, regno, names[i])) + return 1; + + return 0; +} + +/* Look up a register by its GDB internal register number. */ + +static struct tdesc_reg * +tdesc_find_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); + else + return NULL; +} + +static const char * +tdesc_register_name (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); + + 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); + gdb_assert (data->pseudo_register_name != NULL); + return data->pseudo_register_name (regno); + } + + return ""; +} + +static struct type * +tdesc_register_type (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 && regno >= num_regs && regno < num_regs + num_pseudo_regs) + { + struct tdesc_arch_data *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; + + /* 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 (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; + } + 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; +} + +static int +tdesc_remote_register_number (struct gdbarch *gdbarch, int regno) +{ + struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno); + + if (reg != NULL) + return reg->target_regnum; + else + return -1; +} + +/* Check whether REGNUM is a member of REGGROUP. Registers from the + target description may be classified as general, float, or vector. + Registers with no group specified go to the default reggroup + function and are handled by type. + + 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. + + The save-restore flag is also implemented here. */ + +static int +tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regno, + struct reggroup *reggroup) +{ + int num_regs = gdbarch_num_regs (gdbarch); + int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch); + struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno); + + if (reg == NULL && 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); + } + + 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 + && (reggroup == save_reggroup || reggroup == restore_reggroup)) + return reg->save_restore; + + return default_register_reggroup_p (gdbarch, regno, reggroup); +} + +/* Record architecture-specific functions to call for pseudo-register + support. */ + +void +set_tdesc_pseudo_register_name (struct gdbarch *gdbarch, + gdbarch_register_name_ftype *pseudo_name) +{ + struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data); + + data->pseudo_register_name = pseudo_name; +} + +void +set_tdesc_pseudo_register_type (struct gdbarch *gdbarch, + gdbarch_register_type_ftype *pseudo_type) +{ + struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data); + + data->pseudo_register_type = pseudo_type; +} + +void +set_tdesc_pseudo_register_reggroup_p + (struct gdbarch *gdbarch, + gdbarch_register_reggroup_p_ftype *pseudo_reggroup_p) +{ + struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data); + + data->pseudo_register_reggroup_p = pseudo_reggroup_p; +} + +/* Update GDBARCH to use the target description for registers. */ + +void +tdesc_use_registers (struct gdbarch *gdbarch, + struct tdesc_arch_data *early_data) +{ + int num_regs = gdbarch_num_regs (gdbarch); + int i, ixf, ixr; + const struct target_desc *target_desc; + struct tdesc_feature *feature; + struct tdesc_reg *reg; + struct tdesc_arch_data *data; + 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; + xfree (early_data); + + /* 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++) + { + void **slot = htab_find_slot (reg_hash, reg, INSERT); + + *slot = reg; + } + + /* 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); + + /* Assign numbers to the remaining registers and add them to the + list of registers. The new numbers are always above 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); + 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) + { + VEC_safe_push (tdesc_reg_p, data->registers, reg); + num_regs++; + } + + htab_delete (reg_hash); + + /* Update the architecture. */ + set_gdbarch_num_regs (gdbarch, num_regs); + set_gdbarch_register_name (gdbarch, tdesc_register_name); + set_gdbarch_register_type (gdbarch, tdesc_register_type); + set_gdbarch_remote_register_number (gdbarch, + tdesc_remote_register_number); + set_gdbarch_register_reggroup_p (gdbarch, tdesc_register_reggroup_p); +} + + /* 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); +} + +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); + + 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) : NULL; + + /* 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); + + VEC_safe_push (tdesc_reg_p, feature->registers, reg); +} + +static void +tdesc_free_feature (struct tdesc_feature *feature) +{ + struct tdesc_reg *reg; + int ix; + + for (ix = 0; VEC_iterate (tdesc_reg_p, feature->registers, ix, reg); ix++) + tdesc_free_reg (reg); + VEC_free (tdesc_reg_p, feature->registers); + + /* 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); + + xfree (feature->name); + xfree (feature); +} + +struct tdesc_feature * +tdesc_create_feature (struct target_desc *tdesc, const char *name) +{ + struct tdesc_feature *new_feature = XZALLOC (struct tdesc_feature); + + new_feature->name = xstrdup (name); + + VEC_safe_push (tdesc_feature_p, tdesc->features, new_feature); + return new_feature; +} + +void +tdesc_record_type (struct tdesc_feature *feature, struct type *type) +{ + /* The type's ID should be used as its TYPE_NAME. */ + gdb_assert (TYPE_NAME (type) != NULL); + + VEC_safe_push (type_p, feature->types, type); +} + struct target_desc * allocate_target_description (void) { @@ -199,10 +827,17 @@ 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++) { @@ -305,6 +940,8 @@ unset_tdesc_filename_cmd (char *args, int from_tty) void _initialize_target_descriptions (void) { + tdesc_data = gdbarch_data_register_pre_init (tdesc_data_init); + add_prefix_cmd ("tdesc", class_maintenance, set_tdesc_cmd, _("\ Set target description specific variables."), &tdesc_set_cmdlist, "set tdesc ", |