Add "maint check xml-descriptions" to test builtin xml target descriptions

Now, GDB is able to dynamically create i386-linux target descriptions
from features, instead of using pre-generated target descriptions.  These
pre-generated target descriptions are no longer used by GDB (note that
they are still used by GDBserver).

This patch add a new maint command "maint check xml-descriptions" to test
dynamically generated tdesc are identical to these generated from xml files.

gdb:

2017-07-26  Yao Qi  <yao.qi@linaro.org>

	* cli/cli-cmds.c (maintenancechecklist): New variable.
	* gdbcmd.h (maintenancechecklist): Declare it.
	* i386-linux-tdep.c (_initialize_i386_linux_tdep) [GDB_SELF_TEST]:
	Call i386_linux_read_description with different masks.
	* maint.c (maintenance_check_command): New function.
	(_initialize_maint_cmds): Call add_prefix_cmd.
	* target-descriptions.c (tdesc_reg): override operator != and ==.
	(tdesc_type): Likewise.
	(tdesc_feature): Likewise.
	(target_desc): Likewise.
	[GDB_SELF_TEST] (selftests::record_xml_tdesc): New function.
	(maintenance_check_xml_descriptions): New function.
	(_initialize_target_descriptions) Add command "xml-descriptions".
	* target-descriptions.h (selftests::record_xml_tdesc): Declare.

gdb/testsuite:

2017-07-26  Yao Qi  <yao.qi@linaro.org>

	* gdb.gdb/unittest.exp: Invoke command
	"maintenance check xml-descriptions".

gdb/doc:

2017-07-26  Yao Qi  <yao.qi@linaro.org>

	* gdb.texinfo (Maintenance Commands): Document command
	"maint check xml-descriptions".
This commit is contained in:
Yao Qi 2017-07-26 14:55:31 +01:00
parent ea03d0d3c3
commit 27d41eac62
11 changed files with 259 additions and 0 deletions

View File

@ -1,3 +1,20 @@
2017-07-26 Yao Qi <yao.qi@linaro.org>
* cli/cli-cmds.c (maintenancechecklist): New variable.
* gdbcmd.h (maintenancechecklist): Declare it.
* i386-linux-tdep.c (_initialize_i386_linux_tdep) [GDB_SELF_TEST]:
Call i386_linux_read_description with different masks.
* maint.c (maintenance_check_command): New function.
(_initialize_maint_cmds): Call add_prefix_cmd.
* target-descriptions.c (tdesc_reg): override operator != and ==.
(tdesc_type): Likewise.
(tdesc_feature): Likewise.
(target_desc): Likewise.
[GDB_SELF_TEST] (selftests::record_xml_tdesc): New function.
(maintenance_check_xml_descriptions): New function.
(_initialize_target_descriptions) Add command "xml-descriptions".
* target-descriptions.h (selftests::record_xml_tdesc): Declare.
2017-07-26 Yao Qi <yao.qi@linaro.org>
* i386-linux-tdep.c: Don't include features/i386/i386-*linux.c.

View File

@ -168,6 +168,10 @@ struct cmd_list_element *maintenanceinfolist;
struct cmd_list_element *maintenanceprintlist;
/* Chain containing all defined "maintenance check" subcommands. */
struct cmd_list_element *maintenancechecklist;
struct cmd_list_element *setprintlist;
struct cmd_list_element *showprintlist;

View File

@ -1,3 +1,8 @@
2017-07-26 Yao Qi <yao.qi@linaro.org>
* gdb.texinfo (Maintenance Commands): Document command
"maint check xml-descriptions".
2017-07-26 Yao Qi <yao.qi@linaro.org>
* gdb.texinfo (Maintenance Commands): Document optional

View File

@ -34698,6 +34698,11 @@ The created source file is built into @value{GDBN} when @value{GDBN} is
built again. This command is used by developers after they add or
modify XML target descriptions.
@kindex maint check xml-descriptions
@item maint check xml-descriptions @var{dir}
Check that the target descriptions dynamically created by @value{GDBN}
equal the descriptions created from XML files found in @var{dir}.
@kindex maint print dummy-frames
@item maint print dummy-frames
Prints the contents of @value{GDBN}'s internal dummy-frame stack.

View File

@ -95,6 +95,10 @@ extern struct cmd_list_element *maintenanceinfolist;
extern struct cmd_list_element *maintenanceprintlist;
/* Chain containing all defined "maintenance check" subcommands. */
extern struct cmd_list_element *maintenancechecklist;
/* Chain containing all defined "maintenance set" subcommands. */
extern struct cmd_list_element *maintenance_set_cmdlist;

View File

@ -1116,4 +1116,28 @@ _initialize_i386_linux_tdep (void)
{
gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_LINUX,
i386_linux_init_abi);
#if GDB_SELF_TEST
struct
{
const char *xml;
uint64_t mask;
} xml_masks[] = {
{ "i386/i386-linux.xml", X86_XSTATE_SSE_MASK },
{ "i386/i386-mmx-linux.xml", X86_XSTATE_X87_MASK },
{ "i386/i386-avx-linux.xml", X86_XSTATE_AVX_MASK },
{ "i386/i386-mpx-linux.xml", X86_XSTATE_MPX_MASK },
{ "i386/i386-avx-mpx-linux.xml", X86_XSTATE_AVX_MPX_MASK },
{ "i386/i386-avx-avx512-linux.xml", X86_XSTATE_AVX_AVX512_MASK },
{ "i386/i386-avx-mpx-avx512-pku-linux.xml",
X86_XSTATE_AVX_MPX_AVX512_PKU_MASK },
};
for (auto &a : xml_masks)
{
auto tdesc = i386_linux_read_description (a.mask);
selftests::record_xml_tdesc (a.xml, tdesc);
}
#endif /* GDB_SELF_TEST */
}

View File

@ -178,6 +178,19 @@ maintenance_info_command (char *arg, int from_tty)
gdb_stdout);
}
/* The "maintenance check" command is defined as a prefix, with
allow_unknown 0. Therefore, its own definition is called only for
"maintenance check" with no args. */
static void
maintenance_check_command (char *arg, int from_tty)
{
printf_unfiltered (_("\"maintenance check\" must be followed "
"by the name of a check command.\n"));
help_list (maintenancechecklist, "maintenance check ", all_commands,
gdb_stdout);
}
/* Mini tokenizing lexer for 'maint info sections' command. */
static int
@ -1104,6 +1117,11 @@ Print the internal architecture configuration.\n\
Takes an optional file parameter."),
&maintenanceprintlist);
add_prefix_cmd ("check", class_maintenance, maintenance_check_command, _("\
Commands for checking internal gdb state."),
&maintenancechecklist, "maintenance check ", 0,
&maintenancelist);
add_cmd ("translate-address", class_maintenance,
maintenance_translate_address,
_("Translate a section name and address to a symbol."),

View File

@ -35,6 +35,8 @@
#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. */
@ -134,6 +136,20 @@ typedef struct tdesc_reg : tdesc_element
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);
@ -248,6 +264,15 @@ typedef struct tdesc_type : tdesc_element
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);
@ -312,6 +337,54 @@ typedef struct tdesc_feature : tdesc_element
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);
@ -382,6 +455,39 @@ struct target_desc : tdesc_element
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
@ -2213,6 +2319,50 @@ maint_print_c_tdesc_cmd (char *args, int from_tty)
}
}
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 (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);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_target_descriptions;
@ -2253,4 +2403,14 @@ GDB will read the description from the target."),
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);
}

View File

@ -253,4 +253,16 @@ void tdesc_create_reg (struct tdesc_feature *feature, const char *name,
int regnum, int save_restore, const char *group,
int bitsize, const char *type);
#if GDB_SELF_TEST
namespace selftests {
/* Record that XML_FILE should generate a target description that equals
TDESC, to be verified by the "maintenance check xml-descriptions"
command. */
void record_xml_tdesc (const char *xml_file,
const struct target_desc *tdesc);
}
#endif
#endif /* TARGET_DESCRIPTIONS_H */

View File

@ -1,3 +1,8 @@
2017-07-26 Yao Qi <yao.qi@linaro.org>
* gdb.gdb/unittest.exp: Invoke command
"maintenance check xml-descriptions".
2017-07-24 Andreas Arnez <arnez@linux.vnet.ibm.com>
* gdb.arch/s390-vregs.exp: Calculate parameters to hex128 in the

View File

@ -15,3 +15,8 @@
gdb_start
gdb_test "maintenance selftest" "Ran $decimal unit tests, 0 failed"
if { ![is_remote host] } {
gdb_test "maintenance check xml-descriptions ${srcdir}/../features" \
"Tested $decimal XML files, 0 failed"
}