@@ -20,7 +20,7 @@
<!ELEMENT compatible (#PCDATA)>
<!ELEMENT feature
- ((vector | flags | struct | union )*, reg*)>
+ (architecture?, (vector | flags | struct | union )*, reg*)>
<!ATTLIST feature
name ID #REQUIRED>
@@ -34,11 +34,22 @@
group CDATA #IMPLIED
>
-<!ELEMENT vector EMPTY>
+<!ELEMENT vector (count?)>
<!ATTLIST vector
id CDATA #REQUIRED
type CDATA #REQUIRED
- count CDATA #REQUIRED>
+ count CDATA #IMPLIED>
+
+<!ELEMENT count (math?)>
+<!ATTLIST count
+ id ID #IMPLIED
+ idref IDREF #IMPLIED>
+<!ELEMENT math (apply | ci | cn)>
+<!ELEMENT apply ((divide | times), (ci | cn)+)>
+<!ELEMENT ci (#PCDATA)>
+<!ELEMENT cn (#PCDATA)>
+<!ELEMENT divide EMPTY>
+<!ELEMENT times EMPTY>
<!ELEMENT flags (field+)>
<!ATTLIST flags
@@ -89,6 +89,7 @@ struct gdbarch
gdbarch_ecoff_reg_to_regnum_ftype *ecoff_reg_to_regnum = no_op_reg_to_regnum;
gdbarch_sdb_reg_to_regnum_ftype *sdb_reg_to_regnum = no_op_reg_to_regnum;
gdbarch_dwarf2_reg_to_regnum_ftype *dwarf2_reg_to_regnum = no_op_reg_to_regnum;
+ gdbarch_regnum_to_dwarf2_reg_ftype *regnum_to_dwarf2_reg = nullptr;
gdbarch_register_name_ftype *register_name = nullptr;
gdbarch_register_type_ftype *register_type = nullptr;
gdbarch_dummy_id_ftype *dummy_id = default_dummy_id;
@@ -347,6 +348,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of ecoff_reg_to_regnum, invalid_p == 0. */
/* Skip verify of sdb_reg_to_regnum, invalid_p == 0. */
/* Skip verify of dwarf2_reg_to_regnum, invalid_p == 0. */
+ /* Skip verify of regnum_to_dwarf2_reg, has predicate. */
if (gdbarch->register_name == 0)
log.puts ("\n\tregister_name");
if (gdbarch->register_type == 0)
@@ -711,6 +713,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
gdb_printf (file,
"gdbarch_dump: dwarf2_reg_to_regnum = <%s>\n",
host_address_to_string (gdbarch->dwarf2_reg_to_regnum));
+ gdb_printf (file,
+ "gdbarch_dump: gdbarch_regnum_to_dwarf2_reg_p() = %d\n",
+ gdbarch_regnum_to_dwarf2_reg_p (gdbarch));
+ gdb_printf (file,
+ "gdbarch_dump: regnum_to_dwarf2_reg = <%s>\n",
+ host_address_to_string (gdbarch->regnum_to_dwarf2_reg));
gdb_printf (file,
"gdbarch_dump: register_name = <%s>\n",
host_address_to_string (gdbarch->register_name));
@@ -2201,6 +2209,30 @@ set_gdbarch_dwarf2_reg_to_regnum (struct gdbarch *gdbarch,
gdbarch->dwarf2_reg_to_regnum = dwarf2_reg_to_regnum;
}
+bool
+gdbarch_regnum_to_dwarf2_reg_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->regnum_to_dwarf2_reg != NULL;
+}
+
+int
+gdbarch_regnum_to_dwarf2_reg (struct gdbarch *gdbarch, int regnum)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->regnum_to_dwarf2_reg != NULL);
+ if (gdbarch_debug >= 2)
+ gdb_printf (gdb_stdlog, "gdbarch_regnum_to_dwarf2_reg called\n");
+ return gdbarch->regnum_to_dwarf2_reg (gdbarch, regnum);
+}
+
+void
+set_gdbarch_regnum_to_dwarf2_reg (struct gdbarch *gdbarch,
+ gdbarch_regnum_to_dwarf2_reg_ftype regnum_to_dwarf2_reg)
+{
+ gdbarch->regnum_to_dwarf2_reg = regnum_to_dwarf2_reg;
+}
+
const char *
gdbarch_register_name (struct gdbarch *gdbarch, int regnr)
{
@@ -308,6 +308,15 @@ typedef int (gdbarch_dwarf2_reg_to_regnum_ftype) (struct gdbarch *gdbarch, int d
extern int gdbarch_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int dwarf2_regnr);
extern void set_gdbarch_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, gdbarch_dwarf2_reg_to_regnum_ftype *dwarf2_reg_to_regnum);
+/* Provide a default mapping from a gdb REGNUM to a DWARF2 register number.
+ Return -1 for bad REGNUM. */
+
+extern bool gdbarch_regnum_to_dwarf2_reg_p (struct gdbarch *gdbarch);
+
+typedef int (gdbarch_regnum_to_dwarf2_reg_ftype) (struct gdbarch *gdbarch, int regnum);
+extern int gdbarch_regnum_to_dwarf2_reg (struct gdbarch *gdbarch, int regnum);
+extern void set_gdbarch_regnum_to_dwarf2_reg (struct gdbarch *gdbarch, gdbarch_regnum_to_dwarf2_reg_ftype *regnum_to_dwarf2_reg);
+
/* Return the name of register REGNR for the specified architecture.
REGNR can be any value greater than, or equal to zero, and less than
'gdbarch_num_cooked_regs (GDBARCH)'. If REGNR is not supported for
@@ -589,6 +589,17 @@ Return -1 for bad REGNUM. Note: Several targets get this wrong.
invalid=False,
)
+Method(
+ comment="""
+Provide a default mapping from a gdb REGNUM to a DWARF2 register number.
+Return -1 for bad REGNUM.
+""",
+ type="int",
+ name="regnum_to_dwarf2_reg",
+ params=[("int", "regnum")],
+ predicate=True,
+)
+
Method(
comment="""
Return the name of register REGNR for the specified architecture.
@@ -1030,6 +1030,40 @@ create_static_range_type (type_allocator &alloc, struct type *index_type,
return result_type;
}
+/* Create a range type using ALLOC.
+
+ Indices will be of type INDEX_TYPE, and will range from 0 to the value
+ LOC_EXPR_ evaluates to, inclusive. */
+
+static struct type *
+create_dynamic_range_type (type_allocator &alloc, struct type *index_type,
+ const gdb::array_view<const gdb_byte> locexpr_)
+{
+ struct dynamic_prop low, high;
+ struct dwarf2_property_baton *baton
+ = GDBARCH_OBSTACK_ZALLOC (alloc.arch (), dwarf2_property_baton);
+ size_t len = locexpr_.size () + 2;
+ gdb_byte *locexpr = GDBARCH_OBSTACK_CALLOC (alloc.arch (), len, gdb_byte);
+
+ memcpy (locexpr, locexpr_.data (), locexpr_.size());
+
+ /* The high bound is inclusive, so decrement the element count by one. */
+ locexpr[len - 2] = DW_OP_lit1;
+ locexpr[len - 1] = DW_OP_minus;
+
+ baton->property_type = builtin_type (alloc.arch ())->builtin_unsigned_int;
+ baton->locexpr.data = locexpr;
+ baton->locexpr.size = len;
+ baton->locexpr.is_reference = false;
+ baton->locexpr.per_objfile = nullptr;
+ baton->locexpr.per_cu = nullptr;
+
+ low.set_const_val (0);
+ high.set_locexpr (baton);
+
+ return create_range_type (alloc, index_type, &low, &high, 0);
+}
+
/* Predicate tests whether BOUNDS are static. Returns 1 if all bounds values
are static, otherwise returns 0. */
@@ -1409,6 +1443,21 @@ lookup_array_range_type (struct type *element_type,
return create_array_type (alloc, element_type, range_type);
}
+/* Create type for array ranges where the low bound is 0 and the high
+ bound is given by the provided DWARF LOCEXPR_. */
+
+static struct type *
+lookup_array_range_type (struct type *element_type,
+ const gdb::array_view<const gdb_byte> locexpr_)
+{
+ type_allocator alloc (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, locexpr_);
+ return create_array_type (alloc, element_type, range_type);
+}
+
/* See gdbtypes.h. */
struct type *
@@ -1497,6 +1546,18 @@ init_vector_type (struct type *elt_type, int n)
return array_type;
}
+/* Create vector type of elements of type ELT_TYPE, where the number of
+ elements is given by the provided DWARF LOCEXPR. */
+
+struct type *
+init_vector_type (struct type *elt_type,
+ const gdb::array_view<const gdb_byte> locexpr)
+{
+ struct type *array_type = lookup_array_range_type (elt_type, locexpr);
+ make_vector_type (array_type);
+ return array_type;
+}
+
/* Internal routine called by TYPE_SELF_TYPE to return the type that TYPE
belongs to. In c++ this is the class of "this", but TYPE_THIS_TYPE is too
confusing. "self" is a common enough replacement for "this".
@@ -2427,6 +2427,8 @@ extern void append_flags_type_flag (struct type *type, int bitpos,
extern void make_vector_type (struct type *array_type);
extern struct type *init_vector_type (struct type *elt_type, int n);
+extern struct type *init_vector_type (struct type *elt_type,
+ const gdb::array_view<const gdb_byte> locexpr);
extern struct type *lookup_reference_type (struct type *, enum type_code);
extern struct type *lookup_lvalue_reference_type (struct type *);
@@ -159,7 +159,10 @@ make_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *ttype)
return;
type *element_gdb_type = make_gdb_type (m_gdbarch, e->element_type);
- m_type = init_vector_type (element_gdb_type, e->count);
+ if (e->locexpr.size() > 0)
+ m_type = init_vector_type (element_gdb_type, e->locexpr);
+ else
+ m_type = init_vector_type (element_gdb_type, e->count);
m_type->set_name (xstrdup (e->name.c_str ()));
return;
}
@@ -364,6 +367,10 @@ struct target_desc : tdesc_element
/* The features associated with this target. */
std::vector<tdesc_feature_up> features;
+ /* Location expressions for variable-size vector registers may use constants
+ defined in the DWARF header. */
+ bool include_dwarf_header = false;
+
/* Used to cache the generated xml version of the target description. */
mutable char *xmltarget = nullptr;
@@ -452,6 +459,23 @@ get_arch_data (struct gdbarch *gdbarch)
return result;
}
+/* See gdbsupport/tdesc.h. */
+
+int
+tdesc_dwarf_reg_to_regnum (const char *arch, int dwarf_reg)
+{
+ struct gdbarch_info info;
+ info.bfd_arch_info = bfd_scan_arch (arch);
+ if (info.bfd_arch_info == nullptr)
+ return -1;
+
+ gdbarch *gdbarch = gdbarch_find_by_info (info);
+ if (gdbarch == nullptr)
+ return -1;
+
+ return gdbarch_dwarf2_reg_to_regnum (gdbarch, dwarf_reg);
+}
+
/* The string manipulated by the "set tdesc filename ..." command. */
static std::string tdesc_filename_cmd_string;
@@ -1214,6 +1238,14 @@ set_tdesc_osabi (struct target_desc *target_desc, enum gdb_osabi osabi)
{
target_desc->osabi = osabi;
}
+
+/* See gdb/target-descriptions.h. */
+
+void
+set_tdesc_include_dwarf_header (struct target_desc *target_desc, bool include)
+{
+ target_desc->include_dwarf_header = include;
+}
static struct cmd_list_element *tdesc_set_cmdlist, *tdesc_show_cmdlist;
@@ -1372,9 +1404,45 @@ class print_c_tdesc : public tdesc_element_visitor
gdb_printf
(" element_type = tdesc_named_type (feature, \"%s\");\n",
type->element_type->name.c_str ());
- gdb_printf
- (" tdesc_create_vector (feature, \"%s\", element_type, %d);\n",
- type->name.c_str (), type->count);
+
+ if (type->count == TDESC_REG_VARIABLE_SIZE)
+ {
+ const std::string *prefix;
+
+ if (type->locexpr_id.has_value ())
+ prefix = &*type->locexpr_id;
+ else if (type->locexpr_idref.has_value ())
+ prefix = &*type->locexpr_idref;
+ else
+ prefix = &type->name;
+
+ if (!type->locexpr_idref.has_value ())
+ {
+ gdb_printf (" gdb_byte %s_locexpr[%zu];\n", prefix->c_str (),
+ type->locexpr.size ());
+ for (unsigned int i = 0; i < type->locexpr.size (); i++)
+ {
+ const char *op_name;
+
+ if (type->locexpr_str.has_value ())
+ op_name = type->locexpr_str->at (i);
+ else
+ op_name = nullptr;
+
+ if (op_name == nullptr)
+ gdb_printf (" %s_locexpr[%u] = %u;\n", prefix->c_str (), i,
+ type->locexpr[i]);
+ else
+ gdb_printf (" %s_locexpr[%u] = %s;\n", prefix->c_str (), i,
+ op_name);
+ }
+ }
+ gdb_printf (" tdesc_create_vector (feature, \"%s\", element_type, %s_locexpr);\n",
+ type->name.c_str (), prefix->c_str ());
+ }
+ else
+ gdb_printf (" tdesc_create_vector (feature, \"%s\", element_type, %d);\n",
+ type->name.c_str (), type->count);
gdb_printf ("\n");
}
@@ -1494,7 +1562,13 @@ class print_c_tdesc : public tdesc_element_visitor
gdb_printf ("\"%s\", ", reg->group.c_str ());
else
gdb_printf ("NULL, ");
- gdb_printf ("%d, \"%s\"", reg->bitsize, reg->type.c_str ());
+
+ if (reg->bitsize == TDESC_REG_VARIABLE_SIZE)
+ gdb_printf ("TDESC_REG_VARIABLE_SIZE, ");
+ else
+ gdb_printf ("%d, ", reg->bitsize);
+
+ gdb_printf ("\"%s\"", reg->type.c_str ());
if (reg->load_early)
gdb_printf (", true");
@@ -1558,6 +1632,8 @@ class print_c_feature : public print_c_tdesc
lbasename (m_filename_after_features.c_str ()));
gdb_printf ("#include \"gdbsupport/tdesc.h\"\n");
+ if (e->include_dwarf_header)
+ gdb_printf ("#include \"dwarf2.h\"\n");
gdb_printf ("\n");
}
@@ -1642,7 +1718,13 @@ class print_c_feature : public print_c_tdesc
gdb_printf ("\"%s\", ", reg->group.c_str ());
else
gdb_printf ("NULL, ");
- gdb_printf ("%d, \"%s\"", reg->bitsize, reg->type.c_str ());
+
+ if (reg->bitsize == TDESC_REG_VARIABLE_SIZE)
+ gdb_printf ("TDESC_REG_VARIABLE_SIZE, ");
+ else
+ gdb_printf ("%d, ", reg->bitsize);
+
+ gdb_printf ("\"%s\"", reg->type.c_str ());
if (reg->load_early)
gdb_printf (", true");
@@ -229,6 +229,12 @@ void set_tdesc_property (struct target_desc *,
void tdesc_add_compatible (struct target_desc *,
const struct bfd_arch_info *);
+/* Set whether the C version of the target description should include
+ dwarf2.h. */
+
+void set_tdesc_include_dwarf_header (struct target_desc *target_desc,
+ bool include);
+
#if GDB_SELF_TEST
namespace selftests {
@@ -71,21 +71,62 @@ static std::unordered_map<std::string, target_desc_up> xml_cache;
struct tdesc_parsing_data
{
/* The target description we are building. */
- struct target_desc *tdesc;
+ struct target_desc *tdesc = nullptr;
/* The target feature we are currently parsing, or last parsed. */
- struct tdesc_feature *current_feature;
+ struct tdesc_feature *current_feature = nullptr;
/* The register number to use for the next register we see, if
it does not have its own. This starts at zero. */
- int next_regnum;
+ int next_regnum = 0;
/* The struct or union we are currently parsing, or last parsed. */
- tdesc_type_with_fields *current_type;
+ tdesc_type_with_fields *current_type = nullptr;
/* The byte size of the current struct/flags type, if specified. Zero
if not specified. Flags values must specify a size. */
- int current_type_size;
+ int current_type_size = 0;
+
+ /* Map used to implement id/idref attribute support for the <count>
+ element in a vector type. The fist member is the count id, and the
+ second is the DWARF expression it corresponds to. */
+ std::unordered_map<std::string, gdb::byte_vector> vector_count_locexprs;
+
+ /* Information needed to parse <vector> element. */
+ struct {
+ /* id attribute for the <vector> element being processed. */
+ std::string id;
+
+ /* Type of field in <vector> element being processed. */
+ struct tdesc_type *field_type = nullptr;
+
+ /* Holds number of elements, if <vector> has "count" attribute. */
+ std::optional<int> count;
+
+ /* Holds DWARF expression, if <vector> has a <math> child. */
+ gdb::byte_vector locexpr;
+
+ /* Holds string representation of opcodes in locexpr. Used to provide
+ more readable code when converting to C. Needs to have the same
+ number of elements as locexpr. */
+ std::optional<std::vector<const char *>> locexpr_str;
+
+ /* id attribute for the <count> element being processed. */
+ std::string count_id;
+
+ std::string count_idref;
+
+ std::optional<gdb_byte> apply_operator;
+
+ std::optional<const char *> apply_operator_str;
+ } current_vector;
+
+ /* gdbarch that roughly corresponds to the XML target description being
+ parsed. Used to gather basic facts about the architecture such as the
+ DWARF register numbering. */
+ gdbarch *preliminary_gdbarch = nullptr;
+
+ std::set<int> load_early_regnums;
};
/* Handle the end of an <architecture> element and its value. */
@@ -166,6 +207,36 @@ tdesc_start_feature (struct gdb_xml_parser *parser,
data->current_feature = tdesc_create_feature (data->tdesc, name);
}
+/* Handle the end of a <feature> element. */
+
+static void
+tdesc_end_feature (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element, void *user_data,
+ const char *body_text)
+{
+ struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data;
+
+ for (int regnum : data->load_early_regnums)
+ {
+ std::vector<tdesc_reg_up> ®isters = data->current_feature->registers;
+ auto reg = std::find_if (registers.begin (), registers.end (),
+ [=] (tdesc_reg_up &i) {
+ if (i->target_regnum == regnum)
+ return true;
+ else
+ return false;
+ });
+ if (reg == registers.end ())
+ gdb_xml_error (parser,
+ _("Register number %d used in expression but not found in feature."),
+ regnum);
+
+ (*reg)->load_early = true;
+ }
+
+ data->load_early_regnums.clear ();
+}
+
/* Handle the start of a <reg> element. Fill in the optional
attributes and attach it to the containing feature. */
@@ -474,27 +545,287 @@ tdesc_start_vector (struct gdb_xml_parser *parser,
void *user_data, std::vector<gdb_xml_value> &attributes)
{
struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data;
- struct tdesc_type *field_type;
- char *id, *field_type_id;
- ULONGEST count;
+ char *field_type_id;
- id = (char *) attributes[0].value.get ();
+ data->current_vector.id = (char *) attributes[0].value.get ();
field_type_id = (char *) attributes[1].value.get ();
- count = * (ULONGEST *) attributes[2].value.get ();
- if (count > MAX_VECTOR_SIZE)
+ if (attributes.size () >= 3)
{
- gdb_xml_error (parser,
- _("Vector size %s is larger than maximum (%d)"),
- pulongest (count), MAX_VECTOR_SIZE);
+ ULONGEST count = *(ULONGEST *)attributes[2].value.get ();
+
+ if (count > MAX_VECTOR_SIZE)
+ gdb_xml_error (parser,
+ _ ("Vector \"%s\": size %s is larger than maximum (%d)"),
+ data->current_vector.id.c_str (), pulongest (count),
+ MAX_VECTOR_SIZE);
+
+ data->current_vector.count = (int) count;
}
- field_type = tdesc_named_type (data->current_feature, field_type_id);
- if (field_type == NULL)
+ data->current_vector.field_type = tdesc_named_type (data->current_feature,
+ field_type_id);
+ if (data->current_vector.field_type == nullptr)
gdb_xml_error (parser, _("Vector \"%s\" references undefined type \"%s\""),
- id, field_type_id);
+ data->current_vector.id.c_str (), field_type_id);
+}
+
+/* Handle the end of a <vector> element. */
+
+static void
+tdesc_end_vector (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element, void *user_data,
+ const char *body_text)
+{
+ struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data;
+
+ if (data->current_vector.count.has_value ()
+ && !data->current_vector.locexpr.empty ())
+ gdb_xml_error (parser,
+ _ ("Vector \"%s\" has both a count attribute and a count expression"),
+ data->current_vector.id.c_str ());
+ else if (!data->current_vector.count.has_value ()
+ && data->current_vector.locexpr.empty ())
+ gdb_xml_error (parser,
+ _ ("Vector \"%s\" has neither a count attribute nor a count expression"),
+ data->current_vector.id.c_str ());
+
+ if (data->current_vector.count.has_value ())
+ tdesc_create_vector (data->current_feature,
+ data->current_vector.id.c_str (),
+ data->current_vector.field_type,
+ *data->current_vector.count);
+ else
+ {
+ tdesc_type *type = tdesc_create_vector (data->current_feature,
+ data->current_vector.id.c_str (),
+ data->current_vector.field_type,
+ data->current_vector.locexpr,
+ data->current_vector.locexpr_str);
+ tdesc_type_vector *type_vector = static_cast<tdesc_type_vector *> (type);
+
+ if (!data->current_vector.count_id.empty ())
+ type_vector->locexpr_id = data->current_vector.count_id;
+ else if (!data->current_vector.count_idref.empty ())
+ type_vector->locexpr_idref = data->current_vector.count_idref;
+
+ set_tdesc_include_dwarf_header (data->tdesc, true);
+ }
+
+ data->current_vector = {};
+}
+
+/* Handle the start of a <count> element. Store any given count ID and process
+ IDREFs. */
+
+static void
+tdesc_start_count (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data, std::vector<gdb_xml_value> &attributes)
+{
+ struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data;
+ const char *id = nullptr, *idref = nullptr;
+
+ for (gdb_xml_value &attr : attributes)
+ {
+ if (!strcmp (attr.name, "id"))
+ id = (const char *) attr.value.get ();
+ else if (!strcmp (attr.name, "idref"))
+ idref = (const char *) attr.value.get ();
+ }
+
+ if (id != nullptr && idref != nullptr)
+ gdb_xml_error (parser,
+ _ ("Vector \"%s\": count expression has both an id and an idref"),
+ data->current_vector.id.c_str ());
+
+ if (id != nullptr)
+ {
+ std::string current_count_id = id;
+
+ if (data->vector_count_locexprs.find (current_count_id)
+ != data->vector_count_locexprs.end ())
+ gdb_xml_error (parser,
+ _ ("Vector \"%s\": count expression has duplicate id \"%s\""),
+ data->current_vector.id.c_str (), id);
+
+ data->current_vector.count_id = std::move (current_count_id);
+ }
+ else if (idref != nullptr)
+ {
+ std::string current_count_idref = idref;
+
+ if (data->vector_count_locexprs.find (current_count_idref)
+ == data->vector_count_locexprs.end ())
+ gdb_xml_error (parser,
+ _ ("Vector \"%s\": count expression references unknown id \"%s\""),
+ data->current_vector.id.c_str (), idref);
- tdesc_create_vector (data->current_feature, id, field_type, count);
+ data->current_vector.count_idref = idref;
+ }
+}
+
+/* Handle the end of a <count> element. If the element has an id attribute, store the
+ location expression in the map. If it has an idref attribute, fetch the location
+ expression from the map. */
+
+static void
+tdesc_end_count (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element, void *user_data,
+ const char *body_text)
+{
+ struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data;
+
+ if (!data->current_vector.count_id.empty ())
+ {
+ bool inserted
+ = data->vector_count_locexprs
+ .insert ({ data->current_vector.count_id,
+ data->current_vector.locexpr })
+ .second;
+
+ /* Insertion isn't supposed to fail: we already checked in the start
+ handler that this id isn't present in the map. */
+ gdb_assert (inserted);
+ }
+ else if (!data->current_vector.count_idref.empty ())
+ data->current_vector.locexpr
+ = data->vector_count_locexprs.at (data->current_vector.count_idref);
+}
+
+/* Handle the start of a <math> element. It just has to check whether it's inside
+ a <count> element with an idref and initialize data->current_vector.locexpr_str. */
+
+static void
+tdesc_start_math (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element, void *user_data,
+ std::vector<gdb_xml_value> &attributes)
+{
+ struct tdesc_parsing_data *data = (struct tdesc_parsing_data *)user_data;
+
+ if (!data->current_vector.count_idref.empty ())
+ gdb_xml_error (parser,
+ _ ("Vector \"%s\": count element with an idref isn't empty."),
+ data->current_vector.id.c_str ());
+
+ data->current_vector.locexpr_str.emplace ();
+}
+
+/* Handle the end of an <apply> element. We just need to store the expression
+ operator at the end of the location expression. */
+
+static void
+tdesc_end_apply (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element, void *user_data,
+ const char *body_text)
+{
+ struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data;
+
+ if (!data->current_vector.apply_operator.has_value ())
+ gdb_xml_error (parser,
+ _ ("Vector \"%s\": apply element doesn't have an operator."),
+ data->current_vector.id.c_str ());
+
+ data->current_vector.locexpr.push_back (*data->current_vector.apply_operator);
+ data->current_vector.locexpr_str->push_back (*data->current_vector.apply_operator_str);
+}
+
+/* Handle the end of a <ci> element and its value. */
+
+static void
+tdesc_end_ci (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element, void *user_data,
+ const char *body_text)
+{
+ struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data;
+
+ if (data->preliminary_gdbarch == nullptr) {
+ gdbarch_info arch_info;
+ arch_info.bfd_arch_info = tdesc_architecture (data->tdesc);
+ arch_info.osabi = tdesc_osabi (data->tdesc);
+ data->preliminary_gdbarch = gdbarch_find_by_info (arch_info);
+
+ if (data->preliminary_gdbarch == nullptr)
+ gdb_xml_error (parser,
+ _("Vector \"%s\": couldn't find basic architecture information."),
+ data->current_vector.id.c_str ());
+
+ if (!gdbarch_regnum_to_dwarf2_reg_p (data->preliminary_gdbarch))
+ gdb_xml_error (parser,
+ _("Vector \"%s\": architecture %s doesn't support vector count based on another register."),
+ data->current_vector.id.c_str (),
+ gdbarch_bfd_arch_info (data->preliminary_gdbarch)->printable_name);
+ }
+
+ ULONGEST regnum = gdb_xml_parse_ulongest (parser, body_text);
+ if (regnum > INT_MAX)
+ gdb_xml_error (parser,
+ _("Vector \"%s\": count expression uses register number %s out of range."),
+ data->current_vector.id.c_str (), pulongest (regnum));
+
+ int dwarf_reg = gdbarch_regnum_to_dwarf2_reg (data->preliminary_gdbarch,
+ regnum);
+ if (dwarf_reg < 0 || dwarf_reg > 255)
+ gdb_xml_error (parser,
+ _("Vector \"%s\": count expression uses register number %s out of range."),
+ data->current_vector.id.c_str (), pulongest (dwarf_reg));
+
+ data->current_vector.locexpr.push_back (DW_OP_bregx);
+ data->current_vector.locexpr.push_back ((gdb_byte) dwarf_reg);
+ data->current_vector.locexpr.push_back (0);
+
+ data->current_vector.locexpr_str->push_back ("DW_OP_bregx");
+ data->current_vector.locexpr_str->push_back (nullptr);
+ data->current_vector.locexpr_str->push_back (nullptr);
+
+ data->load_early_regnums.insert (regnum);
+}
+
+/* Handle the end of a <cn> element and its value. */
+
+static void
+tdesc_end_cn (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element, void *user_data,
+ const char *body_text)
+{
+ struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data;
+ ULONGEST number = gdb_xml_parse_ulongest (parser, body_text);
+
+ /* We only support DW_OP_lit0 to DW_OP_lit31. */
+ if (number > 31)
+ gdb_xml_error (parser,
+ _ ("Vector \"%s\": count expression uses value %s larger than maximum of 31."),
+ data->current_vector.id.c_str (), pulongest (number));
+
+ gdb_byte value = DW_OP_lit0 + number;
+ data->current_vector.locexpr.push_back (value);
+ data->current_vector.locexpr_str->push_back (get_DW_OP_name (value));
+}
+
+/* Handle the end of a <divide> element. */
+
+static void
+tdesc_end_divide (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element, void *user_data,
+ const char *body_text)
+{
+ struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data;
+
+ data->current_vector.apply_operator = DW_OP_div;
+ data->current_vector.apply_operator_str = "DW_OP_div";
+}
+
+/* Handle the end of a <times> element. */
+
+static void
+tdesc_end_times (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element, void *user_data,
+ const char *body_text)
+{
+ struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data;
+
+ data->current_vector.apply_operator = DW_OP_mul;
+ data->current_vector.apply_operator_str = "DW_OP_mul";
}
/* The elements and attributes of an XML target description. */
@@ -525,6 +856,43 @@ static const struct gdb_xml_element enum_children[] = {
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
};
+/* MathML allows recursing <apply> elements, but we don't have a need for it
+ yet, so for simplicity we don't. */
+static const struct gdb_xml_element apply_children[] = {
+ { "ci", nullptr, nullptr, GDB_XML_EF_NONE, nullptr, tdesc_end_ci },
+ { "cn", nullptr, nullptr, GDB_XML_EF_OPTIONAL, nullptr, tdesc_end_cn },
+ { "divide", nullptr, nullptr, GDB_XML_EF_OPTIONAL, nullptr,
+ tdesc_end_divide },
+ { "times", nullptr, nullptr, GDB_XML_EF_OPTIONAL, nullptr, tdesc_end_times },
+ { nullptr, nullptr, nullptr, GDB_XML_EF_NONE, nullptr, nullptr }
+};
+
+static const struct gdb_xml_element math_children[] = {
+ { "apply", nullptr, apply_children, GDB_XML_EF_OPTIONAL, nullptr,
+ tdesc_end_apply },
+ { "ci", nullptr, nullptr, GDB_XML_EF_OPTIONAL, nullptr, tdesc_end_ci },
+ { "cn", nullptr, nullptr, GDB_XML_EF_OPTIONAL, nullptr, tdesc_end_cn },
+ { nullptr, nullptr, nullptr, GDB_XML_EF_NONE, nullptr, nullptr }
+};
+
+static const struct gdb_xml_element count_children[] = {
+ { "math", nullptr, math_children, GDB_XML_EF_OPTIONAL, tdesc_start_math,
+ nullptr },
+ { nullptr, nullptr, nullptr, GDB_XML_EF_NONE, nullptr, nullptr }
+};
+
+static const struct gdb_xml_attribute count_attributes[] = {
+ { "id", GDB_XML_AF_OPTIONAL, nullptr, nullptr },
+ { "idref", GDB_XML_AF_OPTIONAL, nullptr, nullptr },
+ { nullptr, GDB_XML_AF_NONE, nullptr, nullptr }
+};
+
+static const struct gdb_xml_element vector_children[] = {
+ { "count", count_attributes, count_children, GDB_XML_EF_OPTIONAL,
+ tdesc_start_count, tdesc_end_count },
+ { nullptr, nullptr, nullptr, GDB_XML_EF_NONE, nullptr, nullptr }
+};
+
static const struct gdb_xml_attribute reg_attributes[] = {
{ "name", GDB_XML_AF_NONE, NULL, NULL },
{ "bitsize", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
@@ -557,7 +925,7 @@ static const struct gdb_xml_attribute enum_attributes[] = {
static const struct gdb_xml_attribute vector_attributes[] = {
{ "id", GDB_XML_AF_NONE, NULL, NULL },
{ "type", GDB_XML_AF_NONE, NULL, NULL },
- { "count", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { "count", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
};
@@ -582,9 +950,10 @@ static const struct gdb_xml_element feature_children[] = {
{ "enum", enum_attributes, enum_children,
GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
tdesc_start_enum, NULL },
- { "vector", vector_attributes, NULL,
- GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
- tdesc_start_vector, NULL },
+ { "vector", vector_attributes, vector_children,
+ GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, tdesc_start_vector,
+ tdesc_end_vector },
+ { "architecture", NULL, NULL, GDB_XML_EF_OPTIONAL, NULL, tdesc_end_arch },
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
};
@@ -602,7 +971,7 @@ static const struct gdb_xml_element target_children[] = {
NULL, tdesc_end_compatible },
{ "feature", feature_attributes, feature_children,
GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
- tdesc_start_feature, NULL },
+ tdesc_start_feature, tdesc_end_feature },
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
};
@@ -636,7 +1005,6 @@ tdesc_parse_xml (const char *document, xml_fetch_another fetcher)
if (it != xml_cache.end ())
return it->second.get ();
- memset (&data, 0, sizeof (struct tdesc_parsing_data));
target_desc_up description = allocate_target_description ();
data.tdesc = description.get ();
@@ -208,6 +208,7 @@ SFILES = \
$(srcdir)/linux-sparc-low.cc \
$(srcdir)/linux-x86-low.cc \
$(srcdir)/linux-xtensa-low.cc \
+ $(srcdir)/locexpr.cc \
$(srcdir)/mem-break.cc \
$(srcdir)/netbsd-aarch64-low.cc \
$(srcdir)/netbsd-amd64-low.cc \
@@ -262,6 +263,7 @@ OBS = \
dll.o \
hostio.o \
inferiors.o \
+ locexpr.o \
mem-break.o \
notif.o \
regcache.o \
@@ -104,6 +104,9 @@
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
+/* Define if the target provides DWARF register to regnum mapping. */
+#undef HAVE_DWARF_REG_TO_REGNUM
+
/* Define to 1 if the system has the type `Elf32_auxv_t'. */
#undef HAVE_ELF32_AUXV_T
@@ -14743,6 +14743,12 @@ if $want_ipa ; then
fi
fi
+if test "${srv_dwarf_reg_to_regnum}" = "yes"; then
+
+$as_echo "#define HAVE_DWARF_REG_TO_REGNUM 1" >>confdefs.h
+
+fi
+
@@ -441,6 +441,11 @@ if $want_ipa ; then
fi
fi
+if test "${srv_dwarf_reg_to_regnum}" = "yes"; then
+ AC_DEFINE(HAVE_DWARF_REG_TO_REGNUM, 1,
+ [Define if the target provides DWARF register to regnum mapping.])
+fi
+
AC_SUBST(GDBSERVER_DEPFILES)
AC_SUBST(GDBSERVER_LIBS)
AC_SUBST(srv_xmlbuiltin)
new file mode 100644
@@ -0,0 +1,107 @@
+/* Simplified DWARF location expression evaluator for gdbserver.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "server.h"
+#include "leb128.h"
+#include "locexpr.h"
+#include "regcache.h"
+#include "arch/aarch64.h"
+
+#define DW_OP_lit0 0x30
+#define DW_OP_lit2 0x32
+#define DW_OP_lit4 0x34
+#define DW_OP_lit8 0x38
+#define DW_OP_bregx 0x92
+#define DW_OP_div 0x1b
+#define DW_OP_mul 0x1e
+
+/* See gdbserver/locexpr.h. */
+
+long
+evaluate_locexpr (const gdb::array_view<const gdb_byte> locexpr,
+ const struct regcache *regcache)
+{
+ std::vector<long> stack;
+
+ for (auto it = locexpr.begin (); it != locexpr.end ();)
+ {
+ gdb_byte op = *it;
+ long result;
+
+ it++;
+ switch (op)
+ {
+ case DW_OP_div:
+ {
+ long divisor = stack.back ();
+ stack.pop_back ();
+ long dividend = stack.back ();
+ stack.pop_back ();
+ result = dividend / divisor;
+ break;
+ }
+ case DW_OP_mul:
+ {
+ long multiplicand = stack.back ();
+ stack.pop_back ();
+ long multiplier = stack.back ();
+ stack.pop_back ();
+ result = multiplier * multiplicand;
+ break;
+ }
+ case DW_OP_lit0:
+ case DW_OP_lit2:
+ case DW_OP_lit4:
+ case DW_OP_lit8:
+ result = op - DW_OP_lit0;
+ break;
+ case DW_OP_bregx:
+ {
+ uint64_t reg;
+ int read = read_uleb128_to_uint64 (it, locexpr.end (), ®);
+ gdb_assert (read != 0);
+
+ it += read;
+
+ int64_t offset;
+ read = read_sleb128_to_int64 (it, locexpr.end (), &offset);
+ gdb_assert (read != 0);
+
+ it += read;
+
+ const char *arch = tdesc_architecture_name (regcache->tdesc);
+ reg = tdesc_dwarf_reg_to_regnum (arch, reg);
+ gdb_assert (reg != -1);
+
+ register_status reg_status = regcache->get_register_status (reg);
+ gdb_assert (reg_status == REG_VALID);
+ regcache->raw_collect (reg,
+ gdb::make_array_view ((gdb_byte *) &result,
+ sizeof (result)));
+ result += offset;
+ break;
+ }
+ default:
+ gdb_assert_not_reached ("Unsupported locexpr operation: %c\n", op);
+ }
+
+ stack.push_back (result);
+ }
+
+ return stack.back ();
+}
new file mode 100644
@@ -0,0 +1,31 @@
+/* Simplified DWARF location expression evaluator for gdbserver.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef GDBSERVER_LOCEXPR_H
+#define GDBSERVER_LOCEXPR_H
+
+#include "gdbsupport/array-view.h"
+#include "gdbsupport/common-types.h"
+#include "regcache.h"
+
+/* Evaluate the given DWARF LOCEXPR, using REGCACHE to get register values. */
+
+long evaluate_locexpr (const gdb::array_view<const gdb_byte> locexpr,
+ const struct regcache *regcache);
+
+#endif /* GDBSERVER_LOCEXPR_H */
@@ -129,6 +129,9 @@ copy_target_description (struct target_desc *dest,
dest->expedite_regs = src->expedite_regs;
dest->registers_size = src->registers_size;
dest->xmltarget = src->xmltarget;
+
+ if (src->arch)
+ set_tdesc_architecture (dest, src->arch.get ());
}
const struct target_desc *
@@ -242,3 +245,18 @@ tdesc_contains_feature (const target_desc *tdesc, const std::string &feature)
return false;
}
+
+#ifndef HAVE_DWARF_REG_TO_REGNUM
+
+/* See gdbsupport/tdesc.h.
+
+ This is a dummy implementation. It's not used if the target description
+ doesn't have variable-length registers. */
+
+int
+tdesc_dwarf_reg_to_regnum (const char *arch, int dwarf_reg)
+{
+ return -1;
+}
+
+#endif /* HAVE_DWARF_REG_TO_REGNUM */
@@ -18,6 +18,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "gdbsupport/tdesc.h"
+#include "dwarf2.h"
tdesc_reg::tdesc_reg (struct tdesc_feature *feature, const std::string &name_,
int regnum, int save_restore_, const char *group_,
@@ -160,6 +161,21 @@ tdesc_create_vector (struct tdesc_feature *feature, const char *name,
/* See gdbsupport/tdesc.h. */
+struct tdesc_type *
+tdesc_create_vector (struct tdesc_feature *feature, const char *name,
+ struct tdesc_type *field_type,
+ const gdb::array_view<const gdb_byte> locexpr,
+ std::optional<std::vector<const char *>> locexpr_str)
+{
+ tdesc_type_vector *type = new tdesc_type_vector (name, field_type, locexpr,
+ locexpr_str);
+ feature->types.emplace_back (type);
+
+ return type;
+}
+
+/* See gdbsupport/tdesc.h. */
+
tdesc_type_with_fields *
tdesc_create_struct (struct tdesc_feature *feature, const char *name)
{
@@ -312,8 +328,113 @@ void print_xml_feature::visit (const tdesc_type_builtin *t)
void print_xml_feature::visit (const tdesc_type_vector *t)
{
- add_line ("<vector id=\"%s\" type=\"%s\" count=\"%d\"/>",
- t->name.c_str (), t->element_type->name.c_str (), t->count);
+ if (t->locexpr.empty ())
+ add_line ("<vector id=\"%s\" type=\"%s\" count=\"%d\"/>",
+ t->name.c_str (), t->element_type->name.c_str (), t->count);
+ else
+ {
+ add_line ("<vector id=\"%s\" type=\"%s\">",
+ t->name.c_str (), t->element_type->name.c_str ());
+
+ if (t->locexpr_idref.has_value ())
+ add_line (" <count idref=\"%s\"/>", t->locexpr_idref->c_str ());
+ else
+ {
+ if (t->locexpr_id.has_value ())
+ add_line (" <count id=\"%s\">", t->locexpr_id->c_str ());
+ else
+ add_line (" <count>");
+
+ add_line (" <math>");
+
+ std::vector<std::string> stack;
+
+ /* Convert DWARF location expression to MathML. */
+ for (int i = 0; i < t->locexpr.size (); i++)
+ {
+ switch (t->locexpr[i])
+ {
+ case DW_OP_bregx:
+ {
+ gdb_byte arg1 = t->locexpr[i + 1];
+ gdb_byte arg2 = t->locexpr[i + 2];
+ gdb_byte dwarf_reg;
+
+ if (arg1 == 0)
+ dwarf_reg = arg2;
+ else if (arg2 == 0)
+ dwarf_reg = arg1;
+ else
+ error (_("In a vector count locexpr one of the "
+ "operands of DW_OP_bregx must be 0."));
+
+ if (m_arch == nullptr)
+ error (_("Feature references a register in locexpr but "
+ "the architecture is unknown."));
+
+ int regnum = tdesc_dwarf_reg_to_regnum (m_arch, dwarf_reg);
+ if (regnum == -1)
+ error (_("Unknown DWARF register %d."), dwarf_reg);
+
+ stack.push_back (string_printf ("<ci>%d</ci>", regnum));
+
+ i += 2;
+ }
+ break;
+ case DW_OP_div:
+ {
+ std::string divisor = stack.back ();
+ stack.pop_back ();
+ std::string dividend = stack.back ();
+ stack.pop_back ();
+
+ stack.push_back ("</apply>");
+ stack.push_back (" " + divisor);
+ stack.push_back (" " + dividend);
+ stack.push_back (" <divide/>");
+ stack.push_back ("<apply>");
+ }
+ break;
+ case DW_OP_mul:
+ {
+ std::string multiplicand = stack.back ();
+ stack.pop_back ();
+ std::string multiplier = stack.back ();
+ stack.pop_back ();
+
+ stack.push_back ("</apply>");
+ stack.push_back (" " + multiplicand);
+ stack.push_back (" " + multiplier);
+ stack.push_back (" <times/>");
+ stack.push_back ("<apply>");
+ }
+ break;
+ default:
+ {
+ gdb_byte val = t->locexpr[i];
+
+ if (val > DW_OP_lit0 && val <= DW_OP_lit31)
+ stack.push_back (string_printf ("<cn>%d</cn>",
+ val - DW_OP_lit0));
+ else
+ error (_ ("Unsupported DWARF operator %d."), val);
+ }
+ break;
+ }
+ }
+
+ while (!stack.empty ())
+ {
+ add_line (" " + stack.back ());
+ stack.pop_back ();
+ }
+
+ add_line (" </math>");
+ add_line (" </count>");
+ }
+
+ add_line ("</vector>");
+ }
}
void print_xml_feature::visit (const tdesc_type_with_fields *t)
@@ -405,9 +526,12 @@ void print_xml_feature::visit_pre (const target_desc *e)
add_line ("<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
add_line ("<target>");
indent (1);
- if (tdesc_architecture_name (e))
- add_line ("<architecture>%s</architecture>",
- tdesc_architecture_name (e));
+ const char *arch = tdesc_architecture_name (e);
+ if (arch != nullptr)
+ {
+ add_line ("<architecture>%s</architecture>", arch);
+ m_arch = arch;
+ }
const char *osabi = tdesc_osabi_name (e);
if (osabi != nullptr)
@@ -64,6 +64,11 @@ class tdesc_element
virtual void accept (tdesc_element_visitor &v) const = 0;
};
+/* Used in vector type element count or register bitsize to indicate that
+ the corresponding value is given by a DWARF expression. */
+
+#define TDESC_REG_VARIABLE_SIZE -1
+
/* An individual register from a target description. */
struct tdesc_reg : tdesc_element
@@ -242,13 +247,40 @@ struct tdesc_type_vector : tdesc_type
element_type (element_type_), count (count_)
{}
+ tdesc_type_vector (const std::string &name, tdesc_type *element_type_,
+ const gdb::array_view<const gdb_byte> locexpr_,
+ std::optional<std::vector<const char *>> locexpr_str_)
+ : tdesc_type (name, TDESC_TYPE_VECTOR), element_type (element_type_),
+ count (TDESC_REG_VARIABLE_SIZE), locexpr (locexpr_.begin (),
+ locexpr_.end()),
+ locexpr_str (locexpr_str_)
+ {
+ if (locexpr_str.has_value () && locexpr.size () != locexpr_str->size ())
+ error (_ ("Vector locexpr and its string representation must have the same size."));
+ }
+
void accept (tdesc_element_visitor &v) const override
{
v.visit (this);
}
struct tdesc_type *element_type;
+
+ /* Ignored if LOCEXPR isn't empty. */
int count;
+
+ /* DWARF location expression providing number of elements. */
+ gdb::byte_vector locexpr;
+
+ /* Vector with strings to use instead of the corresponding raw bytecode
+ in C code that creates the vector type. */
+ std::optional<std::vector<const char *>> locexpr_str;
+
+ /* XML id used to reference this location expression. */
+ std::optional<std::string> locexpr_id;
+
+ /* XML id of location expression to be used for number of elements. */
+ std::optional<std::string> locexpr_idref;
};
/* A named type from a target description. */
@@ -368,6 +400,14 @@ struct tdesc_type *tdesc_create_vector (struct tdesc_feature *feature,
struct tdesc_type *field_type,
int count);
+/* Return the created vector tdesc_type named NAME in FEATURE,
+ with number of elements given by DWARF LOCEXPR. */
+struct tdesc_type * tdesc_create_vector (struct tdesc_feature *feature,
+ const char *name,
+ struct tdesc_type *field_type,
+ const gdb::array_view<const gdb_byte> locexpr,
+ std::optional<std::vector<const char *>> locexpr_str = {});
+
/* Return the created struct tdesc_type named NAME in FEATURE. */
tdesc_type_with_fields *tdesc_create_struct (struct tdesc_feature *feature,
const char *name);
@@ -469,6 +509,13 @@ class print_xml_feature : public tdesc_element_visitor
/* The current indentation depth. */
int m_depth;
+
+ /* The current feature's architecture, if any. */
+ const char *m_arch = nullptr;
};
+/* Convert ARCH's DWARF register number DWARF_REG to GDB's register number.
+ Returns -1 if ARCH or DWARF_REG are unknown. */
+int tdesc_dwarf_reg_to_regnum (const char *arch, int dwarf_reg);
+
#endif /* COMMON_TDESC_H */