Add "maint check xml-descriptions" to test builtin xml target descriptions
authorYao Qi <yao.qi@linaro.org>
Wed, 26 Jul 2017 13:55:31 +0000 (14:55 +0100)
committerYao Qi <yao.qi@linaro.org>
Wed, 26 Jul 2017 13:55:31 +0000 (14:55 +0100)
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".

gdb/ChangeLog
gdb/cli/cli-cmds.c
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/gdbcmd.h
gdb/i386-linux-tdep.c
gdb/maint.c
gdb/target-descriptions.c
gdb/target-descriptions.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.gdb/unittest.exp

index 77c74f20f8baa651cf21f7ae16945071ab2fed5c..45dceb6f31409340b7cb0aea5b7743c519762e30 100644 (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.
index af750d3ec9547bc21bf1467557d9037acee5f733..8f0376e5f03d566588a7693e3dcc9858d137ddc3 100644 (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;
index e3a68d36728059f814a7ec95d3782dbc8b42f1b6..d43ae35c00412fba19895ff9ea401b2ff33ce51e 100644 (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
index 08a7681a4961f7083d7bb4beb4d285982f32768d..17b4c696d95b4bdcc95164703bde16de5bcdd266 100644 (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.
index fbd0cb973d59a1c62924b3c5aa6662b8d7caa29e..14c7f4e541ab5eb503130c4dacdf2a8fd0f62c30 100644 (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;
index 4c0f597a689b60ddb8e5b4197f9660d56b6d5241..708de97a8fbd5ad2b30eb113d4b31448b8018149 100644 (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 */
 }
index d95f6586843f8396d86b34e4a208c0fba14988d1..a0d43ec7c0edd02e2741676a3320437379f99ec5 100644 (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."),
index 333cbd89ab7c1337af35dc611da1f012f94c8931..bee8e004f4b04354383e7c09e71647a44b4acd7c 100644 (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);
 }
index 361ac97a8bd6b3d5deefff84d901225b301f6349..591da1505596591f2715fce704032443ce859306 100644 (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 */
index 1e13687e99cd7d41b24562a3a63fc908c7444ced..2a777a8dab4eb05a1617b3f5a5eebd3f2694c371 100644 (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
index d6fc3de5d5b4eecae89cfafdb54485684842a3f8..c3e36e692379eae37181501f075ef543d0db788c 100644 (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"
+}