From: Thiago Jung Bauermann Date: Fri, 18 Apr 2025 01:36:21 +0000 (-0300) Subject: Continuation of support for target description parameters X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6b6cc90aee5b6c57e1fae50c4aee3bf2cd9f95e1;p=thirdparty%2Fbinutils-gdb.git Continuation of support for target description parameters With this commit, it's possible to declare parameters in a feature, and generate C and XML feature files. The regcache also supports using parameters for variable-size registers, and they can be "unwound" from the sentinel frame. There's a new gdbarch_fetch_tdesc_parameter hook to request the value of a parameter from the architecture. Maybe a target hook will be needed too, for remote debugging. There's generic support for unwinding parameters from a frame, but for now only the sentinel frame allows it. Remote debugging a target which uses parameters in the target description isn't yet supported. --- diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index be0494fba1e..20469e85017 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -1130,6 +1130,15 @@ default_update_call_site_pc (struct gdbarch *gdbarch, CORE_ADDR pc) return pc; } +static void +default_fetch_tdesc_parameter (struct gdbarch *gdbarch, + readable_regcache *regcache, + unsigned int parameter_id) +{ + error (_("Architecture \"%s\" doesn't support target description parameters"), + gdbarch_bfd_arch_info (get_current_arch ())->printable_name); +} + /* Non-zero if we want to trace architecture code. */ #ifndef GDBARCH_DEBUG diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c index e1a5fdd5b8d..9df9a453240 100644 --- a/gdb/dwarf2/loc.c +++ b/gdb/dwarf2/loc.c @@ -46,6 +46,7 @@ #include "gdbsupport/underlying.h" #include "gdbsupport/byte-vector.h" #include "extract-store-integer.h" +#include "target-descriptions.h" static struct value *dwarf2_evaluate_loc_desc_full (struct type *type, const frame_info_ptr &frame, const gdb_byte *data, @@ -1768,6 +1769,20 @@ dwarf2_evaluate_property (const dynamic_prop *prop, } } break; + + case PROP_TDESC_PARAMETER: + { + gdbarch *gdbarch = get_frame_arch (frame); + auto [feature, param_name, element_length] = prop->tdesc_parameter (); + std::optional param_id = tdesc_parameter_id (gdbarch, + feature, + param_name); + if (!param_id.has_value ()) + return false; + + return read_frame_tdesc_parameter_unsigned (frame, *param_id, value); + } + break; } return false; diff --git a/gdb/features/gdb-target.dtd b/gdb/features/gdb-target.dtd index f619573f241..ae7038d55e2 100644 --- a/gdb/features/gdb-target.dtd +++ b/gdb/features/gdb-target.dtd @@ -20,10 +20,15 @@ + (parameter*, (vector | flags | struct | union )*, reg*)> + + + unwind == NULL) + frame_unwind_find_by_frame (next_frame, &next_frame->prologue_cache); + + /* Ask this frame to unwind its register. */ + value *value + = next_frame->unwind->prev_tdesc_parameter (next_frame, + &next_frame->prologue_cache, + parameter); + if (value == nullptr) + { + auto maybe_param_name = tdesc_parameter_name (gdbarch, parameter); + const char *feature, *param_name; + if (maybe_param_name.has_value ()) + { + feature = maybe_param_name->first; + param_name = maybe_param_name->second; + } + else + { + feature = "unknown"; + param_name = "unknown"; + } + + error (_("Can't unwind value of parameter %d (%s:%s)"), parameter, + feature, param_name); + } + + return value; +} + +value * +get_frame_tdesc_parameter_value (const frame_info_ptr &frame, + unsigned int parameter) +{ + return frame_unwind_tdesc_parameter_value (frame_info_ptr (frame->next), + parameter); +} + +bool +read_frame_tdesc_parameter_unsigned (const frame_info_ptr &frame, + unsigned int parameter, ULONGEST *val) +{ + value *value = get_frame_tdesc_parameter_value (frame, parameter); + + if (!value->entirely_available ()) + return false; + + struct gdbarch *gdbarch = get_frame_arch (frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + + *val = extract_unsigned_integer (value->contents (), byte_order); + return true; +} + /* Create a sentinel frame. See frame_id_build_sentinel for the description of STACK_ADDR and diff --git a/gdb/frame.h b/gdb/frame.h index b240662bd73..3ac3d72125f 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -748,6 +748,19 @@ extern void put_frame_register_bytes (const frame_info_ptr &next_frame, int regnum, CORE_ADDR offset, gdb::array_view buffer); +/* FIXME: Document. */ +extern value *frame_unwind_tdesc_parameter_value + (const frame_info_ptr &next_frame, unsigned int parameter); + +/* FIXME: Document. */ +extern value *get_frame_tdesc_parameter_value (const frame_info_ptr &frame, + unsigned int parameter); + +/* FIXME: Document. */ +extern bool read_frame_tdesc_parameter_unsigned (const frame_info_ptr &frame, + unsigned int parameter, + ULONGEST *val); + /* Unwind the PC. Strictly speaking return the resume address of the calling frame. For GDB, `pc' is the resume address and not a specific register. */ diff --git a/gdb/gdbarch-gen.c b/gdb/gdbarch-gen.c index 32d16598940..e82972a3473 100644 --- a/gdb/gdbarch-gen.c +++ b/gdb/gdbarch-gen.c @@ -262,6 +262,7 @@ struct gdbarch gdbarch_read_core_file_mappings_ftype *read_core_file_mappings = default_read_core_file_mappings; gdbarch_use_target_description_from_corefile_notes_ftype *use_target_description_from_corefile_notes = default_use_target_description_from_corefile_notes; gdbarch_core_parse_exec_context_ftype *core_parse_exec_context = default_core_parse_exec_context; + gdbarch_fetch_tdesc_parameter_ftype *fetch_tdesc_parameter = default_fetch_tdesc_parameter; }; /* Create a new ``struct gdbarch'' based on information provided by @@ -535,6 +536,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of read_core_file_mappings, invalid_p == 0. */ /* Skip verify of use_target_description_from_corefile_notes, invalid_p == 0. */ /* Skip verify of core_parse_exec_context, invalid_p == 0. */ + /* Skip verify of fetch_tdesc_parameter, invalid_p == 0. */ if (!log.empty ()) internal_error (_("verify_gdbarch: the following are invalid ...%s"), log.c_str ()); @@ -1406,6 +1408,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) gdb_printf (file, "gdbarch_dump: core_parse_exec_context = <%s>\n", host_address_to_string (gdbarch->core_parse_exec_context)); + gdb_printf (file, + "gdbarch_dump: fetch_tdesc_parameter = <%s>\n", + host_address_to_string (gdbarch->fetch_tdesc_parameter)); if (gdbarch->dump_tdep != NULL) gdbarch->dump_tdep (gdbarch, file); } @@ -5551,3 +5556,20 @@ set_gdbarch_core_parse_exec_context (struct gdbarch *gdbarch, { gdbarch->core_parse_exec_context = core_parse_exec_context; } + +void +gdbarch_fetch_tdesc_parameter (struct gdbarch *gdbarch, readable_regcache *regcache, unsigned int parameter_id) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->fetch_tdesc_parameter != NULL); + if (gdbarch_debug >= 2) + gdb_printf (gdb_stdlog, "gdbarch_fetch_tdesc_parameter called\n"); + gdbarch->fetch_tdesc_parameter (gdbarch, regcache, parameter_id); +} + +void +set_gdbarch_fetch_tdesc_parameter (struct gdbarch *gdbarch, + gdbarch_fetch_tdesc_parameter_ftype fetch_tdesc_parameter) +{ + gdbarch->fetch_tdesc_parameter = fetch_tdesc_parameter; +} diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h index 313a8f198fd..7371c400e5f 100644 --- a/gdb/gdbarch-gen.h +++ b/gdb/gdbarch-gen.h @@ -1801,3 +1801,9 @@ extern void set_gdbarch_use_target_description_from_corefile_notes (struct gdbar typedef core_file_exec_context (gdbarch_core_parse_exec_context_ftype) (struct gdbarch *gdbarch, bfd *cbfd); extern core_file_exec_context gdbarch_core_parse_exec_context (struct gdbarch *gdbarch, bfd *cbfd); extern void set_gdbarch_core_parse_exec_context (struct gdbarch *gdbarch, gdbarch_core_parse_exec_context_ftype *core_parse_exec_context); + +/* Obtain or calculate target description parameter. */ + +typedef void (gdbarch_fetch_tdesc_parameter_ftype) (struct gdbarch *gdbarch, readable_regcache *regcache, unsigned int parameter_id); +extern void gdbarch_fetch_tdesc_parameter (struct gdbarch *gdbarch, readable_regcache *regcache, unsigned int parameter_id); +extern void set_gdbarch_fetch_tdesc_parameter (struct gdbarch *gdbarch, gdbarch_fetch_tdesc_parameter_ftype *fetch_tdesc_parameter); diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py index ec09d955088..87694eb82b4 100644 --- a/gdb/gdbarch_components.py +++ b/gdb/gdbarch_components.py @@ -2848,3 +2848,17 @@ which all assume current_inferior() is the one to read from. predefault="default_core_parse_exec_context", invalid=False, ) + +Method( + comment=""" +Obtain or calculate target description parameter. +""", + type="void", + name="fetch_tdesc_parameter", + params=[ + ("readable_regcache *", "regcache"), + ("unsigned int", "parameter_id"), + ], + predefault="default_fetch_tdesc_parameter", + invalid=False, +) diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index f2333d97ea7..e6dd6d64e25 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -1039,6 +1039,7 @@ create_static_range_type (type_allocator &alloc, struct type *index_type, static struct type * create_dynamic_range_type (type_allocator &alloc, struct type *index_type, + ULONGEST element_length, const char *parameter_feature, const char *length_parameter) { @@ -1046,12 +1047,12 @@ create_dynamic_range_type (type_allocator &alloc, struct type *index_type, low.set_const_val (0); // FIXME: Leaks memory. - std::pair *parameter - = new std::pair; // FIXME: Is the lifetime of the following strings longer than of this // object? - parameter->first = parameter_feature; - parameter->second = length_parameter; + std::tuple *parameter + = new std::tuple (parameter_feature, + length_parameter, + element_length); high.set_tdesc_parameter (parameter); return create_range_type (alloc, index_type, &low, &high, 0); @@ -1449,7 +1450,8 @@ lookup_array_range_type (struct type *element_type, struct type *index_type, *range_type; index_type = builtin_type (element_type->arch ())->builtin_unsigned_int; - range_type = create_dynamic_range_type (alloc, index_type, parameter_feature, + range_type = create_dynamic_range_type (alloc, index_type, element_type->length (), + parameter_feature, length_parameter); return create_array_type (alloc, element_type, range_type); } @@ -2256,6 +2258,19 @@ resolve_dynamic_range (struct type *dyn_range_type, if (dwarf2_evaluate_property (prop, frame, addr_stack, &value, { (CORE_ADDR) rank })) { + /* In the case of a vector with tdesc parameter in the range, we + should evaluate it to the number of elements in the vector. */ + if (prop->kind () == PROP_TDESC_PARAMETER) + { + ULONGEST element_length = std::get (prop->tdesc_parameter ()); + + if (element_length != ULONGEST_MAX) + value /= element_length; + value -= 1; + + if (low_bound.kind () == PROP_CONST) + value += low_bound.const_val (); + } high_bound.set_const_val (value); if (dyn_range_type->bounds ()->flag_upper_bound_is_count) diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 98732614d36..3132e4478f0 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -299,9 +299,10 @@ union dynamic_prop_data const char *variable_name; - /* The first element is the feature name and the second is the parameter - name. */ - std::pair *tdesc_parameter; + /* The first element is the feature name, the second is the parameter + name and the third is the size of an element in the vector, + or ULONGEST_MAX if it should be ignored. */ + std::tuple *tdesc_parameter; }; /* * Used to store a dynamic property. */ @@ -417,13 +418,13 @@ struct dynamic_prop m_data.variable_name = name; } - std::pair tdesc_parameter () const + std::tuple tdesc_parameter () const { gdb_assert (m_kind == PROP_TDESC_PARAMETER); return *m_data.tdesc_parameter; } - void set_tdesc_parameter (std::pair *parameter) + void set_tdesc_parameter (std::tuple *parameter) { m_kind = PROP_TDESC_PARAMETER; m_data.tdesc_parameter = parameter; diff --git a/gdb/regcache.c b/gdb/regcache.c index 2a65be67382..fb1a0d1597c 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -31,6 +31,7 @@ #include "gdbsupport/unordered_map.h" #include #include "cli/cli-cmds.h" +#include "target-descriptions.h" /* * DATA STRUCTURE @@ -77,6 +78,12 @@ struct regcache_descr /* Cached table containing the type of each register. */ struct type **register_type = nullptr; + + /* Offset of each target description parameter. */ + std::vector tdesc_parameter_offset; + + /* Size of target description parameters buffer. */ + long sizeof_tdesc_parameters = 0; }; static const registry::key @@ -167,6 +174,16 @@ init_regcache_descr (struct gdbarch *gdbarch) descr->sizeof_fixed_size_cooked_registers = offset; } + /* Initialize list of target description parameter offsets. */ + long offset = 0; + descr->tdesc_parameter_offset.resize (tdesc_num_parameters (gdbarch)); + for (i = 0; i < descr->tdesc_parameter_offset.size (); i++) + { + descr->tdesc_parameter_offset[i] = offset; + offset += tdesc_parameter_size (gdbarch, i); + } + descr->sizeof_tdesc_parameters = offset; + return descr; } @@ -311,6 +328,9 @@ reg_buffer::reg_buffer (gdbarch *gdbarch, bool has_pseudo) m_register_status.reset (new register_status[gdbarch_num_regs (gdbarch)] ()); } + + m_tdesc_parameter_status.resize (tdesc_num_parameters (gdbarch), REG_UNKNOWN); + m_tdesc_parameters.resize (m_descr->sizeof_tdesc_parameters, 0); } regcache::regcache (inferior *inf_for_target_calls, gdbarch *gdbarch) @@ -380,6 +400,63 @@ reg_buffer::has_variable_size_registers () return m_descr->has_variable_size_registers; } +/* See regcache.h. */ + +gdb::array_view +reg_buffer::tdesc_parameter_buffer (unsigned int param_id) +{ + gdb_assert (param_id < m_descr->tdesc_parameter_offset.size ()); + gdb_byte *start; + + start = &m_tdesc_parameters[m_descr->tdesc_parameter_offset[param_id]]; + + ULONGEST size = tdesc_parameter_size (m_descr->gdbarch, param_id); + return gdb::array_view (start, size); +} + +/* See regcache.h. */ + +enum register_status +reg_buffer::get_tdesc_parameter_status (unsigned int param_id) const +{ + gdb_assert (param_id < m_tdesc_parameter_status.size ()); + return m_tdesc_parameter_status[param_id]; +} + +/* See regcache.h. */ + +void +reg_buffer::invalidate_tdesc_parameter (unsigned int param_id) +{ + gdb_assert (param_id < m_tdesc_parameter_status.size ()); + m_tdesc_parameter_status[param_id] = REG_UNKNOWN; +} + +/* See regcache.h. */ + +void +reg_buffer::supply_parameter (unsigned int param_id, + gdb::array_view src) +{ + gdb_assert (param_id < m_tdesc_parameter_status.size ()); + + gdb::array_view dst = tdesc_parameter_buffer (param_id); + + if (src.data () != nullptr) + { + copy (src, dst); + m_tdesc_parameter_status[param_id] = REG_VALID; + } + else + { + /* This memset not strictly necessary, but better than garbage + in case the parameter value manages to escape somewhere (due + to a bug, no less). */ + memset (dst.data (), 0, dst.size ()); + m_tdesc_parameter_status[param_id] = REG_UNAVAILABLE; + } +} + /* Helper for reg_buffer::register_buffer. */ template @@ -1292,6 +1369,56 @@ readable_regcache::cooked_read_part (int regnum, int offset, /* See regcache.h. */ +void +readable_regcache::update_tdesc_parameter (unsigned int param_id) +{ + gdb_assert (param_id < m_tdesc_parameter_status.size ()); + + if (get_tdesc_parameter_status (param_id) == REG_UNKNOWN) + { + gdbarch_fetch_tdesc_parameter (m_descr->gdbarch, this, param_id); + + if (m_tdesc_parameter_status[param_id] == REG_UNKNOWN) + m_tdesc_parameter_status[param_id] = REG_UNAVAILABLE; + } +} + +/* See regcache.h. */ + +register_status +readable_regcache::tdesc_parameter_value (unsigned int param_id, + gdb::array_view dst) +{ + gdb_assert (param_id < m_tdesc_parameter_status.size ()); + + ULONGEST size = tdesc_parameter_size (m_descr->gdbarch, param_id); + gdb_assert (dst.size () == size); + + update_tdesc_parameter (param_id); + + if (m_tdesc_parameter_status[param_id] == REG_VALID) + copy (tdesc_parameter_buffer (param_id), dst); + else + memset (dst.data (), 0, dst.size ()); + + return m_tdesc_parameter_status[param_id]; +} + +value * +readable_regcache::tdesc_parameter_value (unsigned int param_id) +{ + value *result = value::allocate (tdesc_parameter_type (m_descr->gdbarch, + param_id)); + + if (tdesc_parameter_value (param_id, + result->contents_raw ()) == REG_UNAVAILABLE) + result->mark_bytes_unavailable (0, result->type ()->length ()); + + return result; +} + +/* See regcache.h. */ + void regcache::cooked_write_part (int regnum, int offset, gdb::array_view src) diff --git a/gdb/regcache.h b/gdb/regcache.h index 1da162f2f74..ce7362b65ef 100644 --- a/gdb/regcache.h +++ b/gdb/regcache.h @@ -271,6 +271,17 @@ public: /* See gdbsupport/common-regcache.h. */ int register_size (int regnum) const override; + /* FIXME: Document. + Assumes SRC contains an integer in target byte order. */ + void supply_parameter (unsigned int param_id, + gdb::array_view src); + + /* FIXME: Document. */ + enum register_status get_tdesc_parameter_status (unsigned int param_id) const; + + /* FIXME: Document. */ + void invalidate_tdesc_parameter (unsigned int param_id); + protected: /* Assert on the range of REGNUM. */ void assert_regnum (int regnum) const; @@ -287,6 +298,9 @@ protected: gdb::array_view register_buffer (int regnum) const; gdb::array_view register_buffer (int regnum); + /* Return a view on target desc parameter PARAM_ID's buffer cache. */ + gdb::array_view tdesc_parameter_buffer (unsigned int param_id_id); + /* Save a register cache. The set of registers saved into the regcache determined by the save_reggroup. COOKED_READ returns zero iff the register's value can't be returned. */ @@ -314,6 +328,12 @@ protected: /* The offset of resolved types for variable-size registers (if any). */ std::vector m_variable_size_register_offset; + /* The target description parameters buffers (if any). */ + std::vector m_tdesc_parameters; + + /* Target description parameter cache status. */ + std::vector m_tdesc_parameter_status; + friend class regcache; friend class detached_regcache; }; @@ -369,6 +389,16 @@ public: will call mark_value_bytes_unavailable as appropriate. */ struct value *cooked_read_value (int regnum); + /* FIXME: Document. */ + void update_tdesc_parameter (unsigned int param_id); + + /* FIXME: Document. */ + register_status tdesc_parameter_value (unsigned int param_id, + gdb::array_view dst); + + /* FIXME: Document. */ + value *tdesc_parameter_value (unsigned int param_id); + protected: /* Perform a partial register transfer using a read, modify, write diff --git a/gdb/sentinel-frame.c b/gdb/sentinel-frame.c index 410a6f496b7..48131cc0a8e 100644 --- a/gdb/sentinel-frame.c +++ b/gdb/sentinel-frame.c @@ -78,6 +78,16 @@ sentinel_frame_prev_arch (const frame_info_ptr &this_frame, return cache->regcache->arch (); } +static value * +sentinel_frame_prev_tdesc_parameter (const frame_info_ptr &this_frame, + void **this_prologue_cache, + unsigned int parameter) +{ + frame_unwind_cache *cache = (frame_unwind_cache *) *this_prologue_cache; + + return cache->regcache->tdesc_parameter_value (parameter); +} + const struct frame_unwind_legacy sentinel_frame_unwind ( "sentinel", SENTINEL_FRAME, @@ -88,5 +98,6 @@ const struct frame_unwind_legacy sentinel_frame_unwind ( NULL, NULL, NULL, - sentinel_frame_prev_arch + sentinel_frame_prev_arch, + sentinel_frame_prev_tdesc_parameter ); diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c index aa0017a252f..d1d55ad8290 100644 --- a/gdb/target-descriptions.c +++ b/gdb/target-descriptions.c @@ -160,13 +160,15 @@ make_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *ttype) return; type *element_gdb_type = make_gdb_type (m_gdbarch, e->element_type); - if (e->bitsize_parameter.length () == 0) + if (e->bitsize_parameter == nullptr) m_type = init_vector_type (element_gdb_type, e->count); else // FIXME: Is the lifetime of feature and tdesc_parameter correct? - // Probably not. e->name is duplicated below. - m_type = init_vector_type (element_gdb_type, e->feature.c_str (), - e->bitsize_parameter.c_str ()); + // Probably not. e->name is duplicated below. OTOH, I think target + // descriptions and their associated objects are never destroyed. + m_type = init_vector_type (element_gdb_type, + e->bitsize_parameter->feature.c_str (), + e->bitsize_parameter->name.c_str ()); m_type->set_name (xstrdup (e->name.c_str ())); return; } @@ -427,6 +429,17 @@ struct tdesc_arch_reg struct type *type; }; +struct tdesc_arch_parameter +{ + tdesc_arch_parameter (const tdesc_parameter *parameter_) + : parameter (parameter_) + {} + + const tdesc_parameter *parameter; + + struct type *type = nullptr; +}; + struct tdesc_arch_data { /* A list of register/type pairs, indexed by GDB's internal register number. @@ -442,6 +455,8 @@ struct tdesc_arch_data 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; + + std::vector parameters; }; /* A handle for architecture-specific data associated with the @@ -687,6 +702,106 @@ tdesc_feature_name (const struct tdesc_feature *feature) return feature->name.c_str (); } +/* See target-descriptions.h. */ + +std::optional +tdesc_parameter_id (gdbarch *gdbarch, const char *feature, + const char *param_name) +{ + struct tdesc_arch_data *data = get_arch_data (gdbarch); + + for (int i = 0; i < data->parameters.size (); i++) + { + const tdesc_arch_parameter &arch_param = data->parameters[i]; + if (arch_param.parameter->feature == feature + && arch_param.parameter->name == param_name) + return i; + } + + return {}; +} + +/* See target-descriptions.h. */ + +const tdesc_parameter * +tdesc_feature_parameter (const tdesc_feature &feature, const char *parameter) +{ + for (int i = 0; i < feature.parameters.size (); i++) + if (feature.parameters[i]->name == parameter) + return feature.parameters[i].get (); + + return nullptr; +} + +/* See target-descriptions.h. */ + +std::optional> +tdesc_parameter_name (gdbarch *gdbarch, unsigned int param_id) +{ + struct tdesc_arch_data *data = get_arch_data (gdbarch); + + if (param_id < data->parameters.size ()) + { + const tdesc_arch_parameter ¶m = data->parameters[param_id]; + return std::pair + { param.parameter->feature.c_str (), param.parameter->name.c_str () }; + } + else + return {}; +} + +/* See target-descriptions.h. */ + +type * +tdesc_parameter_type (gdbarch *gdbarch, unsigned int param_id) +{ + tdesc_arch_data *data = get_arch_data (gdbarch); + + gdb_assert (param_id < data->parameters.size ()); + tdesc_arch_parameter &arch_parameter = data->parameters[param_id]; + const tdesc_parameter *parameter = arch_parameter.parameter; + + if (arch_parameter.type == nullptr) + { + arch_parameter.type = make_gdb_type (gdbarch, parameter->type); + if (arch_parameter.type == nullptr) + internal_error ("Register \"%s\" has an unknown type \"%s\"", + parameter->name.c_str (), + parameter->type->name.c_str ()); + } + + return arch_parameter.type; +} + +/* See target-descriptions.h. */ + +ULONGEST +tdesc_parameter_size (gdbarch *gdbarch, unsigned int param_id) +{ + return tdesc_parameter_type (gdbarch, param_id)->length (); +} + +unsigned int +tdesc_num_parameters (gdbarch *gdbarch) +{ + return get_arch_data (gdbarch)->parameters.size (); +} + +/* See target-descriptions.h. */ + +void +tdesc_setup_parameters (gdbarch *gdbarch, const target_desc *target_desc) +{ + struct tdesc_arch_data *data = get_arch_data (gdbarch); + + /* Ensure this is done only once. */ + gdb_assert (data->parameters.size () == 0); + + for (const tdesc_feature_up &feature : target_desc->features) + for (const tdesc_parameter_up ¶meter: feature->parameters) + data->parameters.emplace_back (parameter.get ()); +} + /* Lookup type associated with ID. */ struct type * @@ -1367,10 +1482,10 @@ public: gdb_printf (" element_type = tdesc_named_type (feature, \"%s\");\n", type->element_type->name.c_str ()); - if (type->bitsize_parameter.length () != 0) + if (type->bitsize_parameter != nullptr) gdb_printf - (" tdesc_create_vector (feature, \"%s\", element_type, \"%s\");\n", - type->name.c_str (), type->bitsize_parameter.c_str ()); + (" tdesc_create_vector (feature, \"%s\", element_type, param_%s);\n", + type->name.c_str (), type->bitsize_parameter->name.c_str ()); else gdb_printf (" tdesc_create_vector (feature, \"%s\", element_type, %d);\n", @@ -1494,11 +1609,26 @@ public: gdb_printf ("\"%s\", ", reg->group.c_str ()); else gdb_printf ("NULL, "); - if (reg->bitsize_parameter.length () != 0) - gdb_printf ("\"%s\", \"%s\");\n", reg->bitsize_parameter.c_str (), - reg->type.c_str ()); + if (reg->bitsize_parameter != nullptr) + gdb_printf ("param_%s, ", reg->bitsize_parameter->name.c_str ()); else - gdb_printf ("%d, \"%s\");\n", reg->bitsize, reg->type.c_str ()); + gdb_printf ("%d, ", reg->bitsize); + gdb_printf ("\"%s\");\n", reg->type.c_str ()); + } + + void visit (const tdesc_parameter *p) override + { + if (!m_printed_param_type) + { + gdb_printf (" tdesc_type *param_type;\n"); + m_printed_param_type = true; + } + + gdb_printf (" param_type = tdesc_named_type (feature, \"%s\");\n", + p->type->name.c_str ()); + gdb_printf + (" const tdesc_parameter ¶m_%s = tdesc_create_parameter (*feature, \"%s\", param_type);\n", + p->name.c_str (), p->name.c_str ()); } protected: @@ -1535,6 +1665,9 @@ private: /* Did we print "struct tdesc_type *field_type;" yet? */ bool m_printed_field_type = false; + + /* Did we print "struct tdesc_type *param_type;" yet? */ + bool m_printed_param_type = false; }; /* Print target description feature in C. */ @@ -1641,11 +1774,11 @@ public: gdb_printf ("\"%s\", ", reg->group.c_str ()); else gdb_printf ("NULL, "); - if (reg->bitsize_parameter.length () != 0) - gdb_printf ("\"%s\", \"%s\");\n", reg->bitsize_parameter.c_str (), - reg->type.c_str ()); + if (reg->bitsize_parameter != nullptr) + gdb_printf ("param_%s, ", reg->bitsize_parameter->name.c_str ()); else - gdb_printf ("%d, \"%s\");\n", reg->bitsize, reg->type.c_str ()); + gdb_printf ("%d, ", reg->bitsize); + gdb_printf ("\"%s\");\n", reg->type.c_str ()); m_next_regnum++; } diff --git a/gdb/target-descriptions.h b/gdb/target-descriptions.h index 7481c87a4e9..494d04ec702 100644 --- a/gdb/target-descriptions.h +++ b/gdb/target-descriptions.h @@ -194,6 +194,39 @@ const struct tdesc_feature *tdesc_find_feature (const struct target_desc *, const char *tdesc_feature_name (const struct tdesc_feature *feature); +/* FIXME: Document. */ + +std::optional tdesc_parameter_id (gdbarch *gdbarch, + const char *feature, + const char *param_name); + +/* FIXME: Document. */ + +const tdesc_parameter *tdesc_feature_parameter (const tdesc_feature &feature, + const char *parameter); + +/* FIXME: Document. */ + +std::optional> tdesc_parameter_name + (gdbarch *gdbarch, unsigned int param_id); + +/* FIXME: Document. */ + +type *tdesc_parameter_type (gdbarch *gdbarch, unsigned int param_id); + +/* FIXME: Document. */ + +ULONGEST tdesc_parameter_size (gdbarch *gdbarch, unsigned int param_id); + +/* FIXME: Document. */ + +unsigned int tdesc_num_parameters (gdbarch *gdbarch); + +/* Update TARGET_DESC to use parameters with GDBARCH. */ + +void tdesc_setup_parameters (struct gdbarch *gdbarch, + const struct target_desc *target_desc); + /* Return the name of register REGNO, from the target description or from an architecture-provided pseudo_register_name method. */ diff --git a/gdb/xml-tdesc.c b/gdb/xml-tdesc.c index 64aef110e7e..9b740649de3 100644 --- a/gdb/xml-tdesc.c +++ b/gdb/xml-tdesc.c @@ -213,9 +213,17 @@ tdesc_start_reg (struct gdb_xml_parser *parser, if (bitsize_attr[0] == '$') { - // FIXME: Check whether the bitsize parameter is valid. + const char *parameter_name = &bitsize_attr[1]; + const tdesc_parameter *parameter + = tdesc_feature_parameter (*data->current_feature, parameter_name); + + if (parameter == nullptr) + gdb_xml_error (parser, + _("Register bitsize references non-existent parameter \"%s\""), + parameter_name); + tdesc_create_reg (data->current_feature, name, regnum, save_restore, - group, &bitsize_attr[1], type); + group, *parameter, type); } else { @@ -508,17 +516,50 @@ tdesc_start_vector (struct gdb_xml_parser *parser, } else if (!strcmp (attributes[2].name, "bitsize")) { - char *bitsize = (char *) attributes[2].value.get (); + const char *bitsize = (const char *) attributes[2].value.get (); if (bitsize[0] != '$') - gdb_xml_error (parser, _ ("Vector bitsize \"%s\" isn't a parameter"), + gdb_xml_error (parser, _("Vector bitsize \"%s\" isn't a parameter"), bitsize); - // FIXME: Check whether the parameter exists. - tdesc_create_vector (data->current_feature, id, field_type, &bitsize[1]); + const char *parameter_name = &bitsize[1]; + const tdesc_parameter *parameter + = tdesc_feature_parameter (*data->current_feature, parameter_name); + + if (parameter == nullptr) + gdb_xml_error (parser, + _("Vector bitsize references non-existent parameter \"%s\""), + parameter_name); + + tdesc_create_vector (data->current_feature, id, field_type, *parameter); } else - gdb_xml_error (parser, _ ("Vector doesn't have count nor size attribute")); + gdb_xml_error (parser, _("Vector doesn't have count nor bitsize attribute")); +} + +/* Handle the start of a element. Initialize the type and + record it with the current feature. */ + +static void +tdesc_start_parameter (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, void *user_data, + std::vector &attributes) +{ + struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data; + + const char *name = (const char *) attributes[0].value.get (); + const char *type_id = (const char *) attributes[1].value.get (); + + tdesc_type *type = tdesc_named_type (data->current_feature, type_id); + if (type == nullptr) + gdb_xml_error (parser, _("Parameter \"%s\" references undefined type \"%s\""), + name, type_id); + + if (data->current_feature->has_parameter (name)) + gdb_xml_error (parser, _("Parameter \"%s\" duplicated in feature \"%s\""), + name, data->current_feature->name.c_str ()); + + tdesc_create_parameter (*data->current_feature, name, type); } /* The elements and attributes of an XML target description. */ @@ -586,6 +627,12 @@ static const struct gdb_xml_attribute vector_attributes[] = { { NULL, GDB_XML_AF_NONE, NULL, NULL } }; +static const struct gdb_xml_attribute parameter_attributes[] = { + { "name", GDB_XML_AF_NONE, NULL, NULL }, + { "type", GDB_XML_AF_NONE, NULL, NULL }, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + static const struct gdb_xml_attribute feature_attributes[] = { { "name", GDB_XML_AF_NONE, NULL, NULL }, { NULL, GDB_XML_AF_NONE, NULL, NULL } @@ -610,6 +657,9 @@ static const struct gdb_xml_element feature_children[] = { { "vector", vector_attributes, NULL, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, tdesc_start_vector, NULL }, + { "parameter", parameter_attributes, NULL, + GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, + tdesc_start_parameter, NULL }, { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } }; diff --git a/gdbsupport/tdesc.cc b/gdbsupport/tdesc.cc index 186354aef85..f332c79be3b 100644 --- a/gdbsupport/tdesc.cc +++ b/gdbsupport/tdesc.cc @@ -35,18 +35,18 @@ tdesc_reg::tdesc_reg (struct tdesc_feature *feature, const std::string &name_, tdesc_reg::tdesc_reg (struct tdesc_feature *feature_, const std::string &name_, int regnum, int save_restore_, const char *group_, - const std::string &bitsize_parameter_, const char *type_) + const tdesc_parameter &bitsize_parameter_, + const char *type_) : name (name_), target_regnum (regnum), save_restore (save_restore_), group (group_ != NULL ? group_ : ""), bitsize (TDESC_REG_VARIABLE_SIZE), - bitsize_parameter (bitsize_parameter_), + bitsize_parameter (&bitsize_parameter_), type (type_ != NULL ? type_ : "") { /* 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.c_str ()); - feature = feature_->name; } /* Predefined types. */ @@ -77,6 +77,9 @@ void tdesc_feature::accept (tdesc_element_visitor &v) const { v.visit_pre (this); + for (const tdesc_parameter_up ¶meter : parameters) + parameter->accept (v); + for (const tdesc_type_up &type : types) type->accept (v); @@ -150,6 +153,32 @@ tdesc_named_type (const struct tdesc_feature *feature, const char *id) /* See gdbsupport/tdesc.h. */ +bool +tdesc_feature::has_parameter (const char *parameter) const +{ + for (int i = 0; i < this->parameters.size (); i++) + if (this->parameters[i]->name == parameter) + return true; + + return false; +} + +/* See gdbsupport/tdesc.h. */ + +const tdesc_parameter & +tdesc_create_parameter (tdesc_feature &feature, const char *parameter, + tdesc_type *type) +{ + gdb_assert (!feature.has_parameter (parameter)); + + feature.parameters.emplace_back (new tdesc_parameter (feature.name, + parameter, type)); + + return *feature.parameters.back ().get (); +} + +/* See gdbsupport/tdesc.h. */ + void tdesc_create_reg (struct tdesc_feature *feature, const char *name, int regnum, int save_restore, const char *group, @@ -166,7 +195,7 @@ tdesc_create_reg (struct tdesc_feature *feature, const char *name, void tdesc_create_reg (struct tdesc_feature *feature, const char *name, int regnum, int save_restore, const char *group, - const char *bitsize_parameter, const char *type) + const tdesc_parameter &bitsize_parameter, const char *type) { tdesc_reg *reg = new tdesc_reg (feature, name, regnum, save_restore, group, bitsize_parameter, type); @@ -191,10 +220,9 @@ tdesc_create_vector (struct tdesc_feature *feature, const char *name, struct tdesc_type * tdesc_create_vector (struct tdesc_feature *feature, const char *name, struct tdesc_type *field_type, - const char *bitsize_parameter) + const tdesc_parameter &bitsize_parameter) { tdesc_type_vector *type = new tdesc_type_vector (name, field_type, - feature->name, bitsize_parameter); feature->types.emplace_back (type); @@ -355,9 +383,9 @@ void print_xml_feature::visit (const tdesc_type_builtin *t) void print_xml_feature::visit (const tdesc_type_vector *t) { - if (t->bitsize_parameter.length () != 0) + if (t->bitsize_parameter != nullptr) add_line ("", t->name.c_str (), - t->element_type->name.c_str (), t->bitsize_parameter.c_str ()); + t->element_type->name.c_str (), t->bitsize_parameter->name.c_str ()); else add_line ("", t->name.c_str (), t->element_type->name.c_str (), t->count); @@ -429,10 +457,10 @@ void print_xml_feature::visit (const tdesc_reg *r) { std::string tmp; - if (r->bitsize_parameter.length () != 0) + if (r->bitsize_parameter != nullptr) string_appendf (tmp, "name.c_str (), r->bitsize_parameter.c_str(), + r->name.c_str (), r->bitsize_parameter->name.c_str(), r->type.c_str (), r->target_regnum); else string_appendf (tmp, @@ -480,6 +508,12 @@ void print_xml_feature::visit_post (const target_desc *e) add_line (""); } +void print_xml_feature::visit (const tdesc_parameter *p) +{ + add_line ("", p->name.c_str (), + p->type->name.c_str ()); +} + /* See gdbsupport/tdesc.h. */ void diff --git a/gdbsupport/tdesc.h b/gdbsupport/tdesc.h index 4ecee683e09..b7b8bca5c10 100644 --- a/gdbsupport/tdesc.h +++ b/gdbsupport/tdesc.h @@ -26,6 +26,7 @@ struct tdesc_type_builtin; struct tdesc_type_vector; struct tdesc_type_with_fields; struct tdesc_reg; +struct tdesc_parameter; struct target_desc; /* The interface to visit different elements of target description. */ @@ -56,6 +57,9 @@ public: virtual void visit (const tdesc_reg *e) {} + + virtual void visit (const tdesc_parameter *e) + {} }; class tdesc_element @@ -79,7 +83,7 @@ struct tdesc_reg : tdesc_element tdesc_reg (struct tdesc_feature *feature, const std::string &name_, int regnum, int save_restore_, const char *group_, - const std::string &bitsize_parameter_, const char *type_); + const tdesc_parameter &bitsize_parameter_, const char *type_); virtual ~tdesc_reg () = default; @@ -109,10 +113,11 @@ struct tdesc_reg : tdesc_element std::string group; /* The size of the register, in bits. - Ignored if BITSIZE_PARAMETER isn't empty. */ + Ignored if BITSIZE_PARAMETER isn't nullptr. */ int bitsize; - std::string feature, bitsize_parameter; + /* FIXME: Document. */ + const tdesc_parameter *bitsize_parameter = nullptr; /* The type of the register. This string corresponds to either a named type from the target description or a predefined @@ -134,6 +139,7 @@ struct tdesc_reg : tdesc_element && save_restore == other.save_restore && bitsize == other.bitsize && group == other.group + && bitsize_parameter == other.bitsize_parameter && type == other.type); } @@ -203,6 +209,9 @@ struct tdesc_type : tdesc_element : name (name_), kind (kind_) {} + tdesc_type (tdesc_type &&other) + { *this = std::move (other); } + virtual ~tdesc_type () = default; DISABLE_COPY_AND_ASSIGN (tdesc_type); @@ -222,10 +231,78 @@ struct tdesc_type : tdesc_element { return !(*this == other); } + + tdesc_type &operator= (tdesc_type &&other) + { + this->name = std::move (other.name); + this->kind = other.kind; + return *this; + } }; typedef std::unique_ptr tdesc_type_up; +/* A parameter from a target description. */ + +struct tdesc_parameter : tdesc_element +{ + tdesc_parameter (const std::string &feature_, const std::string &name_, + tdesc_type *type_) + : feature (feature_), name (name_), type (type_) + {} + + tdesc_parameter (tdesc_parameter &&other) + : type (other.type) + { + *this = std::move (other); + } + + virtual ~tdesc_parameter () = default; + + DISABLE_COPY_AND_ASSIGN (tdesc_parameter); + + /* FIXME: Document. */ + std::string feature; + + /* The name of this parameter. In standard features, it may be + recognized by the architecture support code. */ + std::string name; + + /* The type of the parameter. */ + tdesc_type *type; + + void accept (tdesc_element_visitor &v) const override + { + v.visit (this); + } + + bool operator== (const tdesc_parameter &other) const + { + return (name == other.name + && feature == other.feature + && type == other.type); + } + + bool operator!= (const tdesc_parameter &other) const + { + return !(*this == other); + } + + tdesc_parameter &operator= (tdesc_parameter &&other) + { + if (this != &other) + { + this->feature = std::move (other.feature); + this->name = std::move (other.name); + this->type = other.type; + } + + return *this; + } +}; + +typedef std::unique_ptr tdesc_parameter_up; + struct tdesc_type_builtin : tdesc_type { tdesc_type_builtin (const std::string &name, enum tdesc_type_kind kind) @@ -245,15 +322,13 @@ struct tdesc_type_vector : tdesc_type tdesc_type_vector (const std::string &name, tdesc_type *element_type_, int count_) : tdesc_type (name, TDESC_TYPE_VECTOR), - element_type (element_type_), count (count_) + element_type (element_type_), count (count_), bitsize_parameter (nullptr) {} tdesc_type_vector (const std::string &name, tdesc_type *element_type_, - const std::string &feature_, - const std::string &bitsize_parameter_) + const tdesc_parameter &bitsize_parameter_) : tdesc_type (name, TDESC_TYPE_VECTOR), element_type (element_type_), - count (TDESC_REG_VARIABLE_SIZE), feature (feature_), - bitsize_parameter (bitsize_parameter_) + count (TDESC_REG_VARIABLE_SIZE), bitsize_parameter (&bitsize_parameter_) {} void accept (tdesc_element_visitor &v) const override @@ -263,11 +338,11 @@ struct tdesc_type_vector : tdesc_type struct tdesc_type *element_type; - /* Ignored if BITSIZE_PARAMETER isn't empty. */ + /* Ignored if BITSIZE_PARAMETER isn't nullptr. */ int count; /* Target description parameter providing total vector size. */ - std::string feature, bitsize_parameter; + const tdesc_parameter *bitsize_parameter; }; /* A named type from a target description. */ @@ -328,8 +403,13 @@ struct tdesc_feature : tdesc_element /* The types associated with this feature. */ std::vector types; + /* Paremeters defined in this feature. */ + std::vector parameters; + void accept (tdesc_element_visitor &v) const override; + bool has_parameter (const char *parameter) const; + bool operator== (const tdesc_feature &other) const; bool operator!= (const tdesc_feature &other) const @@ -392,7 +472,7 @@ struct tdesc_type *tdesc_create_vector (struct tdesc_feature *feature, struct tdesc_type *tdesc_create_vector (struct tdesc_feature *feature, const char *name, struct tdesc_type *field_type, - const char *bitsize_parameter); + const tdesc_parameter &bitsize_parameter); /* Return the created struct tdesc_type named NAME in FEATURE. */ tdesc_type_with_fields *tdesc_create_struct (struct tdesc_feature *feature, @@ -453,7 +533,20 @@ void tdesc_create_reg (struct tdesc_feature *feature, const char *name, BITSIZE_PARAMETER. */ void tdesc_create_reg (struct tdesc_feature *feature, const char *name, int regnum, int save_restore, const char *group, - const char *bitsize_parameter, const char *type); + const tdesc_parameter &bitsize_parameter, + const char *type); + +/* Return internal ID of PARAMETER from FEATURE. */ + +std::optional tdesc_parameter_id (const target_desc *target_desc, + const char *feature, + const char *parameter); + +/* Add PARAMETER to FEATURE. */ + +const tdesc_parameter & tdesc_create_parameter (tdesc_feature &feature, + const char *parameter, + tdesc_type *type); /* Return the tdesc in string XML format. */ @@ -477,6 +570,7 @@ public: void visit (const tdesc_type_vector *type) override; void visit (const tdesc_type_with_fields *type) override; void visit (const tdesc_reg *reg) override; + void visit (const tdesc_parameter *p) override; private: