#include "hashtab.h"
#include "inferior.h"
#include <algorithm>
+#include "completer.h"
+#include "readline/tilde.h" /* tilde_expand */
/* The interface to visit different elements of target description. */
xfree (group);
}
- /* Disable copying. */
- tdesc_reg (const tdesc_reg &) = delete;
- tdesc_reg &operator= (const tdesc_reg &) = delete;
+ DISABLE_COPY_AND_ASSIGN (tdesc_reg);
/* The name of this register. In standard features, it may be
recognized by the architecture support code, or it may be purely
v.visit (this);
}
+ bool operator== (const tdesc_reg &other) const
+ {
+ return (streq (name, other.name)
+ && target_regnum == other.target_regnum
+ && save_restore == other.save_restore
+ && bitsize == other.bitsize
+ && (group == other.group || streq (group, other.group))
+ && streq (type, other.type));
+ }
+
+ bool operator!= (const tdesc_reg &other) const
+ {
+ return !(*this == other);
+ }
} *tdesc_reg_p;
DEF_VEC_P(tdesc_reg_p);
}
xfree ((char *) name);
}
- /* Disable copying. */
- tdesc_type (const tdesc_type &) = delete;
- tdesc_type &operator= (const tdesc_type &) = delete;
+
+ DISABLE_COPY_AND_ASSIGN (tdesc_type);
/* The name of this type. If this type is a built-in type, this is
a pointer to a constant string. Otherwise, it's a
v.visit (this);
}
+ bool operator== (const tdesc_type &other) const
+ {
+ return (streq (name, other.name) && kind == other.kind);
+ }
+
+ bool operator!= (const tdesc_type &other) const
+ {
+ return !(*this == other);
+ }
} *tdesc_type_p;
DEF_VEC_P(tdesc_type_p);
xfree (name);
}
- /* Disable copying. */
- tdesc_feature (const tdesc_feature &) = delete;
- tdesc_feature &operator= (const tdesc_feature &) = delete;
+ DISABLE_COPY_AND_ASSIGN (tdesc_feature);
/* The name of this feature. It may be recognized by the architecture
support code. */
v.visit_post (this);
}
+
+ bool operator== (const tdesc_feature &other) const
+ {
+ if (strcmp (name, other.name) != 0)
+ return false;
+
+ if (VEC_length (tdesc_reg_p, registers)
+ != VEC_length (tdesc_reg_p, other.registers))
+ return false;
+
+ struct tdesc_reg *reg;
+
+ for (int ix = 0;
+ VEC_iterate (tdesc_reg_p, registers, ix, reg);
+ ix++)
+ {
+ tdesc_reg *reg2
+ = VEC_index (tdesc_reg_p, other.registers, ix);
+
+ if (reg != reg2 && *reg != *reg2)
+ return false;
+ }
+
+ if (VEC_length (tdesc_type_p, types)
+ != VEC_length (tdesc_type_p, other.types))
+ return false;
+
+ tdesc_type *type;
+
+ for (int ix = 0;
+ VEC_iterate (tdesc_type_p, types, ix, type);
+ ix++)
+ {
+ tdesc_type *type2
+ = VEC_index (tdesc_type_p, other.types, ix);
+
+ if (type != type2 && *type != *type2)
+ return false;
+ }
+
+ return true;
+ }
+
+ bool operator!= (const tdesc_feature &other) const
+ {
+ return !(*this == other);
+ }
+
} *tdesc_feature_p;
DEF_VEC_P(tdesc_feature_p);
v.visit_post (this);
}
+
+ bool operator== (const target_desc &other) const
+ {
+ if (arch != other.arch)
+ return false;
+
+ if (osabi != other.osabi)
+ return false;
+
+ if (VEC_length (tdesc_feature_p, features)
+ != VEC_length (tdesc_feature_p, other.features))
+ return false;
+
+ struct tdesc_feature *feature;
+
+ for (int ix = 0;
+ VEC_iterate (tdesc_feature_p, features, ix, feature);
+ ix++)
+ {
+ struct tdesc_feature *feature2
+ = VEC_index (tdesc_feature_p, other.features, ix);
+
+ if (feature != feature2 && *feature != *feature2)
+ return false;
+ }
+
+ return true;
+ }
+
+ bool operator!= (const target_desc &other) const
+ {
+ return !(*this == other);
+ }
};
/* Per-architecture data associated with a target description. The
gdb_assert_not_reached ("bad predefined tdesc type");
}
-/* Return the type associated with ID in the context of FEATURE, or
- NULL if none. */
+/* See arch/tdesc.h. */
struct tdesc_type *
tdesc_named_type (const struct tdesc_feature *feature, const char *id)
int ix;
type = arch_flags_type (gdbarch, tdesc_type->name,
- tdesc_type->u.u.size);
+ tdesc_type->u.u.size * TARGET_CHAR_BIT);
for (ix = 0;
VEC_iterate (tdesc_type_field, tdesc_type->u.u.fields, ix, f);
ix++)
int ix;
type = arch_type (gdbarch, TYPE_CODE_ENUM,
- tdesc_type->u.u.size, tdesc_type->name);
+ tdesc_type->u.u.size * TARGET_CHAR_BIT,
+ tdesc_type->name);
TYPE_UNSIGNED (type) = 1;
for (ix = 0;
VEC_iterate (tdesc_type_field, tdesc_type->u.u.fields, ix, f);
}
\f
+/* See arch/tdesc.h. */
+
void
tdesc_create_reg (struct tdesc_feature *feature, const char *name,
int regnum, int save_restore, const char *group,
VEC_safe_push (tdesc_reg_p, feature->registers, reg);
}
+/* See arch/tdesc.h. */
+
struct tdesc_type *
tdesc_create_vector (struct tdesc_feature *feature, const char *name,
struct tdesc_type *field_type, int count)
return type;
}
+/* See arch/tdesc.h. */
+
struct tdesc_type *
tdesc_create_struct (struct tdesc_feature *feature, const char *name)
{
return type;
}
-/* Set the total length of TYPE. Structs which contain bitfields may
- omit the reserved bits, so the end of the last field may not
- suffice. */
+/* See arch/tdesc.h. */
void
tdesc_set_struct_size (struct tdesc_type *type, int size)
type->u.u.size = size;
}
+/* See arch/tdesc.h. */
+
struct tdesc_type *
tdesc_create_union (struct tdesc_feature *feature, const char *name)
{
return type;
}
+/* See arch/tdesc.h. */
+
struct tdesc_type *
tdesc_create_flags (struct tdesc_feature *feature, const char *name,
int size)
return type;
}
-/* Add a new field to TYPE. */
+/* See arch/tdesc.h. */
void
tdesc_add_field (struct tdesc_type *type, const char *field_name,
VEC_safe_push (tdesc_type_field, type->u.u.fields, &f);
}
-/* Add a new typed bitfield to TYPE. */
-
void
tdesc_add_typed_bitfield (struct tdesc_type *type, const char *field_name,
int start, int end, struct tdesc_type *field_type)
VEC_safe_push (tdesc_type_field, type->u.u.fields, &f);
}
-/* Add a new untyped bitfield to TYPE.
- Untyped bitfields become either uint32 or uint64 depending on the size
- of the underlying type. */
+/* See arch/tdesc.h. */
void
tdesc_add_bitfield (struct tdesc_type *type, const char *field_name,
tdesc_add_typed_bitfield (type, field_name, start, end, field_type);
}
-/* A flag is just a typed(bool) single-bit bitfield.
- This function is kept to minimize changes in generated files. */
+/* See arch/tdesc.h. */
void
tdesc_add_flag (struct tdesc_type *type, int start,
VEC_safe_push (tdesc_type_field, type->u.u.fields, &f);
}
+/* See arch/tdesc.h. */
+
struct tdesc_feature *
-tdesc_create_feature (struct target_desc *tdesc, const char *name)
+tdesc_create_feature (struct target_desc *tdesc, const char *name,
+ const char *xml)
{
struct tdesc_feature *new_feature = new tdesc_feature (name);
VEC_safe_push (property_s, target_desc->properties, &new_prop);
}
+/* See arch/tdesc.h. */
+
+void
+set_tdesc_architecture (struct target_desc *target_desc,
+ const char *name)
+{
+ set_tdesc_architecture (target_desc, bfd_scan_arch (name));
+}
+
void
set_tdesc_architecture (struct target_desc *target_desc,
const struct bfd_arch_info *arch)
target_desc->arch = arch;
}
+/* See arch/tdesc.h. */
+
+void
+set_tdesc_osabi (struct target_desc *target_desc, const char *name)
+{
+ set_tdesc_osabi (target_desc, osabi_from_tdesc_string (name));
+}
+
void
set_tdesc_osabi (struct target_desc *target_desc, enum gdb_osabi osabi)
{
/* Helper functions for the CLI commands. */
static void
-set_tdesc_cmd (char *args, int from_tty)
+set_tdesc_cmd (const char *args, int from_tty)
{
help_list (tdesc_set_cmdlist, "set tdesc ", all_commands, gdb_stdout);
}
static void
-show_tdesc_cmd (char *args, int from_tty)
+show_tdesc_cmd (const char *args, int from_tty)
{
cmd_show_list (tdesc_show_cmdlist, from_tty, "");
}
static void
-unset_tdesc_cmd (char *args, int from_tty)
+unset_tdesc_cmd (const char *args, int from_tty)
{
help_list (tdesc_unset_cmdlist, "unset tdesc ", all_commands, gdb_stdout);
}
}
static void
-unset_tdesc_filename_cmd (char *args, int from_tty)
+unset_tdesc_filename_cmd (const char *args, int from_tty)
{
xfree (target_description_filename);
target_description_filename = NULL;
printf_unfiltered (" Original: %s */\n\n",
lbasename (m_filename_after_features.c_str ()));
- printf_unfiltered ("#include \"target-descriptions.h\"\n");
+ printf_unfiltered ("#include \"arch/tdesc.h\"\n");
printf_unfiltered ("\n");
}
printf_unfiltered ("{\n");
printf_unfiltered (" struct tdesc_feature *feature;\n");
- printf_unfiltered ("\n feature = tdesc_create_feature (result, \"%s\");\n",
- e->name);
+
+ printf_unfiltered
+ ("\n feature = tdesc_create_feature (result, \"%s\", \"%s\");\n",
+ e->name, lbasename (m_filename_after_features.c_str ()));
}
void visit_post (const tdesc_feature *e) override
void visit (const tdesc_reg *reg) override
{
+ /* Most "reg" in XML target descriptions don't have "regnum"
+ attribute, so the register number is allocated sequentially.
+ In case that reg has "regnum" attribute, register number
+ should be set by that explicitly. */
+
+ if (reg->target_regnum < m_next_regnum)
+ {
+ /* The integrity check, it can catch some errors on register
+ number collision, like this,
+
+ <reg name="x0" bitsize="32"/>
+ <reg name="x1" bitsize="32"/>
+ <reg name="x2" bitsize="32"/>
+ <reg name="x3" bitsize="32"/>
+ <reg name="ps" bitsize="32" regnum="3"/>
+
+ but it also has false negatives. The target description
+ below is correct,
+
+ <reg name="x1" bitsize="32" regnum="1"/>
+ <reg name="x3" bitsize="32" regnum="3"/>
+ <reg name="x2" bitsize="32" regnum="2"/>
+ <reg name="x4" bitsize="32" regnum="4"/>
+
+ but it is not a good practice, so still error on this,
+ and also print the message so that it can be saved in the
+ generated c file. */
+
+ printf_unfiltered ("ERROR: \"regnum\" attribute %ld ",
+ reg->target_regnum);
+ printf_unfiltered ("is not the largest number (%d).\n",
+ m_next_regnum);
+ error (_("\"regnum\" attribute %ld is not the largest number (%d)."),
+ reg->target_regnum, m_next_regnum);
+ }
+
+ if (reg->target_regnum > m_next_regnum)
+ {
+ printf_unfiltered (" regnum = %ld;\n", reg->target_regnum);
+ m_next_regnum = reg->target_regnum;
+ }
+
printf_unfiltered (" tdesc_create_reg (feature, \"%s\", regnum++, %d, ",
reg->name, reg->save_restore);
if (reg->group)
else
printf_unfiltered ("NULL, ");
printf_unfiltered ("%d, \"%s\");\n", reg->bitsize, reg->type);
+
+ m_next_regnum++;
}
+private:
+ /* The register number to use for the next register we see. */
+ int m_next_regnum = 0;
};
static void
-maint_print_c_tdesc_cmd (char *args, int from_tty)
+maint_print_c_tdesc_cmd (const char *args, int from_tty)
{
const struct target_desc *tdesc;
const char *filename;
/* Print c files for target features instead of target descriptions,
because c files got from target features are more flexible than the
counterparts. */
- if (startswith (filename_after_features.c_str (), "i386/32bit-"))
+ if (startswith (filename_after_features.c_str (), "i386/32bit-")
+ || startswith (filename_after_features.c_str (), "i386/64bit-")
+ || startswith (filename_after_features.c_str (), "i386/x32-core.xml"))
{
print_c_feature v (filename_after_features);
}
}
-/* Provide a prototype to silence -Wmissing-prototypes. */
-extern initialize_file_ftype _initialize_target_descriptions;
+namespace selftests {
+
+static std::vector<std::pair<const char*, const target_desc *>> xml_tdesc;
+
+#if GDB_SELF_TEST
+
+/* See target-descritpions.h. */
+
+void
+record_xml_tdesc (const char *xml_file, const struct target_desc *tdesc)
+{
+ xml_tdesc.emplace_back (xml_file, tdesc);
+}
+#endif
+
+}
+
+/* Check that the target descriptions created dynamically by
+ architecture-specific code equal the descriptions created from XML files
+ found in the specified directory DIR. */
+
+static void
+maintenance_check_xml_descriptions (const char *dir, int from_tty)
+{
+ if (dir == NULL)
+ error (_("Missing dir name"));
+
+ gdb::unique_xmalloc_ptr<char> dir1 (tilde_expand (dir));
+ std::string feature_dir (dir1.get ());
+ unsigned int failed = 0;
+
+ for (auto const &e : selftests::xml_tdesc)
+ {
+ std::string tdesc_xml = (feature_dir + SLASH_STRING + e.first);
+ const target_desc *tdesc
+ = file_read_description_xml (tdesc_xml.data ());
+
+ if (tdesc == NULL || *tdesc != *e.second)
+ failed++;
+ }
+ printf_filtered (_("Tested %lu XML files, %d failed\n"),
+ (long) selftests::xml_tdesc.size (), failed);
+}
void
_initialize_target_descriptions (void)
add_cmd ("c-tdesc", class_maintenance, maint_print_c_tdesc_cmd, _("\
Print the current target description as a C source file."),
&maintenanceprintlist);
+
+ cmd_list_element *cmd;
+
+ cmd = add_cmd ("xml-descriptions", class_maintenance,
+ maintenance_check_xml_descriptions, _("\
+Check the target descriptions created in GDB equal the descriptions\n\
+created from XML files in the directory.\n\
+The parameter is the directory name."),
+ &maintenancechecklist);
+ set_cmd_completer (cmd, filename_completer);
}