GNU Binutils with patches for OS216
修訂 | 96ff42812e3d7fc7f2640990331185ffccb4eeb0 (tree) |
---|---|
時間 | 2017-06-20 19:34:12 |
作者 | Yao Qi <yao.qi@lina...> |
Commiter | Yao Qi |
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-06-06 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-06-06 Yao Qi <yao.qi@linaro.org>
* gdb.gdb/unittest.exp: Invoke command
"maintenance check xml-descriptions".
gdb/doc:
2017-06-06 Yao Qi <yao.qi@linaro.org>
* gdb.texinfo (Maintenance Commands): Document command
"maint check xml-descriptions".
@@ -168,6 +168,10 @@ struct cmd_list_element *maintenanceinfolist; | ||
168 | 168 | |
169 | 169 | struct cmd_list_element *maintenanceprintlist; |
170 | 170 | |
171 | +/* Chain containing all defined "maintenance check" subcommands. */ | |
172 | + | |
173 | +struct cmd_list_element *maintenancechecklist; | |
174 | + | |
171 | 175 | struct cmd_list_element *setprintlist; |
172 | 176 | |
173 | 177 | struct cmd_list_element *showprintlist; |
@@ -34698,6 +34698,11 @@ The created source file is built into @value{GDBN} when @value{GDBN} is | ||
34698 | 34698 | built again. This command is used by developers after they add or |
34699 | 34699 | modify XML target descriptions. |
34700 | 34700 | |
34701 | +@kindex maint check xml-descriptions | |
34702 | +@item maint check xml-descriptions @var{dir} | |
34703 | +Check the target descriptions created by @value{GDBN} equal to these | |
34704 | +which are created from XML files in @var{dir}. | |
34705 | + | |
34701 | 34706 | @kindex maint print dummy-frames |
34702 | 34707 | @item maint print dummy-frames |
34703 | 34708 | Prints the contents of @value{GDBN}'s internal dummy-frame stack. |
@@ -95,6 +95,10 @@ extern struct cmd_list_element *maintenanceinfolist; | ||
95 | 95 | |
96 | 96 | extern struct cmd_list_element *maintenanceprintlist; |
97 | 97 | |
98 | +/* Chain containing all defined "maintenance check" subcommands. */ | |
99 | + | |
100 | +extern struct cmd_list_element *maintenancechecklist; | |
101 | + | |
98 | 102 | /* Chain containing all defined "maintenance set" subcommands. */ |
99 | 103 | |
100 | 104 | extern struct cmd_list_element *maintenance_set_cmdlist; |
@@ -1114,4 +1114,24 @@ _initialize_i386_linux_tdep (void) | ||
1114 | 1114 | { |
1115 | 1115 | gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_LINUX, |
1116 | 1116 | i386_linux_init_abi); |
1117 | + | |
1118 | +#if GDB_SELF_TEST | |
1119 | + std::pair<const char *, uint64_t> xml_masks[] = { | |
1120 | + { "i386/i386-linux.xml", X86_XSTATE_SSE_MASK }, | |
1121 | + { "i386/i386-mmx-linux.xml", X86_XSTATE_X87_MASK }, | |
1122 | + { "i386/i386-avx-linux.xml", X86_XSTATE_AVX_MASK }, | |
1123 | + { "i386/i386-mpx-linux.xml", X86_XSTATE_MPX_MASK }, | |
1124 | + { "i386/i386-avx-mpx-linux.xml", X86_XSTATE_AVX_MPX_MASK }, | |
1125 | + { "i386/i386-avx-avx512-linux.xml", X86_XSTATE_AVX_AVX512_MASK }, | |
1126 | + { "i386/i386-avx-mpx-avx512-pku-linux.xml", | |
1127 | + X86_XSTATE_AVX_MPX_AVX512_PKU_MASK }, | |
1128 | + }; | |
1129 | + | |
1130 | + for (auto &a : xml_masks) | |
1131 | + { | |
1132 | + auto tdesc = i386_linux_read_description (a.second); | |
1133 | + | |
1134 | + selftests::record_xml_tdesc (a.first, tdesc); | |
1135 | + } | |
1136 | +#endif /* GDB_SELF_TEST */ | |
1117 | 1137 | } |
@@ -178,6 +178,19 @@ maintenance_info_command (char *arg, int from_tty) | ||
178 | 178 | gdb_stdout); |
179 | 179 | } |
180 | 180 | |
181 | +/* The "maintenance check" command is defined as a prefix, with | |
182 | + allow_unknown 0. Therefore, its own definition is called only for | |
183 | + "maintenance check" with no args. */ | |
184 | + | |
185 | +static void | |
186 | +maintenance_check_command (char *arg, int from_tty) | |
187 | +{ | |
188 | + printf_unfiltered (_("\"maintenance check\" must be followed " | |
189 | + "by the name of a check command.\n")); | |
190 | + help_list (maintenancechecklist, "maintenance check ", all_commands, | |
191 | + gdb_stdout); | |
192 | +} | |
193 | + | |
181 | 194 | /* Mini tokenizing lexer for 'maint info sections' command. */ |
182 | 195 | |
183 | 196 | static int |
@@ -1104,6 +1117,11 @@ Print the internal architecture configuration.\n\ | ||
1104 | 1117 | Takes an optional file parameter."), |
1105 | 1118 | &maintenanceprintlist); |
1106 | 1119 | |
1120 | + add_prefix_cmd ("check", class_maintenance, maintenance_check_command, _("\ | |
1121 | +Commands for checking internal gdb state."), | |
1122 | + &maintenancechecklist, "maintenance check ", 0, | |
1123 | + &maintenancelist); | |
1124 | + | |
1107 | 1125 | add_cmd ("translate-address", class_maintenance, |
1108 | 1126 | maintenance_translate_address, |
1109 | 1127 | _("Translate a section name and address to a symbol."), |
@@ -132,6 +132,20 @@ typedef struct tdesc_reg : tdesc_element | ||
132 | 132 | v.visit (this); |
133 | 133 | } |
134 | 134 | |
135 | + bool operator== (const tdesc_reg &other) const | |
136 | + { | |
137 | + return (streq (name, other.name) | |
138 | + && target_regnum == other.target_regnum | |
139 | + && save_restore == other.save_restore | |
140 | + && bitsize == other.bitsize | |
141 | + && (group == other.group || streq (group, other.group)) | |
142 | + && streq (type, other.type)); | |
143 | + } | |
144 | + | |
145 | + bool operator!= (const tdesc_reg &other) const | |
146 | + { | |
147 | + return !(*this == other); | |
148 | + } | |
135 | 149 | } *tdesc_reg_p; |
136 | 150 | DEF_VEC_P(tdesc_reg_p); |
137 | 151 |
@@ -245,6 +259,15 @@ typedef struct tdesc_type : tdesc_element | ||
245 | 259 | v.visit (this); |
246 | 260 | } |
247 | 261 | |
262 | + bool operator== (const tdesc_type &other) const | |
263 | + { | |
264 | + return (streq (name, other.name) && kind == other.kind); | |
265 | + } | |
266 | + | |
267 | + bool operator!= (const tdesc_type &other) const | |
268 | + { | |
269 | + return !(*this == other); | |
270 | + } | |
248 | 271 | } *tdesc_type_p; |
249 | 272 | DEF_VEC_P(tdesc_type_p); |
250 | 273 |
@@ -312,6 +335,53 @@ typedef struct tdesc_feature : tdesc_element | ||
312 | 335 | |
313 | 336 | v.visit_end (this); |
314 | 337 | } |
338 | + bool operator!= (const tdesc_feature &other) const | |
339 | + { | |
340 | + if (strcmp (name, other.name) != 0) | |
341 | + return true; | |
342 | + | |
343 | + if (VEC_length (tdesc_reg_p, registers) | |
344 | + != VEC_length (tdesc_reg_p, other.registers)) | |
345 | + return true; | |
346 | + | |
347 | + struct tdesc_reg *reg; | |
348 | + | |
349 | + for (int ix = 0; | |
350 | + VEC_iterate (tdesc_reg_p, registers, ix, reg); | |
351 | + ix++) | |
352 | + { | |
353 | + struct tdesc_reg *reg2 | |
354 | + = VEC_index (tdesc_reg_p, other.registers, ix); | |
355 | + | |
356 | + if (reg != reg2 && *reg != *reg2) | |
357 | + return true; | |
358 | + } | |
359 | + | |
360 | + if (VEC_length (tdesc_type_p, types) | |
361 | + != VEC_length (tdesc_type_p, other.types)) | |
362 | + return true; | |
363 | + | |
364 | + struct tdesc_type *type; | |
365 | + | |
366 | + for (int ix = 0; | |
367 | + VEC_iterate (tdesc_type_p, types, ix, type); | |
368 | + ix++) | |
369 | + { | |
370 | + struct tdesc_type *type2 | |
371 | + = VEC_index (tdesc_type_p, other.types, ix); | |
372 | + | |
373 | + if (type != type2 && *type != *type2) | |
374 | + return true; | |
375 | + } | |
376 | + | |
377 | + return false; | |
378 | + } | |
379 | + | |
380 | + bool operator== (const tdesc_feature &other) const | |
381 | + { | |
382 | + return !(*this != other); | |
383 | + } | |
384 | + | |
315 | 385 | } *tdesc_feature_p; |
316 | 386 | DEF_VEC_P(tdesc_feature_p); |
317 | 387 |
@@ -382,6 +452,39 @@ public: | ||
382 | 452 | |
383 | 453 | v.visit_end (this); |
384 | 454 | } |
455 | + | |
456 | + bool operator!= (const target_desc &other) const | |
457 | + { | |
458 | + if (arch != other.arch) | |
459 | + return true; | |
460 | + | |
461 | + if (osabi != other.osabi) | |
462 | + return true; | |
463 | + | |
464 | + if (VEC_length (tdesc_feature_p, features) | |
465 | + != VEC_length (tdesc_feature_p, other.features)) | |
466 | + return true; | |
467 | + | |
468 | + struct tdesc_feature *feature; | |
469 | + | |
470 | + for (int ix = 0; | |
471 | + VEC_iterate (tdesc_feature_p, features, ix, feature); | |
472 | + ix++) | |
473 | + { | |
474 | + struct tdesc_feature *feature2 | |
475 | + = VEC_index (tdesc_feature_p, other.features, ix); | |
476 | + | |
477 | + if (feature != feature2 && *feature != *feature2) | |
478 | + return true; | |
479 | + } | |
480 | + | |
481 | + return false; | |
482 | + } | |
483 | + | |
484 | + bool operator== (const target_desc &other) const | |
485 | + { | |
486 | + return !(*this != other); | |
487 | + } | |
385 | 488 | }; |
386 | 489 | |
387 | 490 | /* Per-architecture data associated with a target description. The |
@@ -2167,6 +2270,45 @@ maint_print_c_tdesc_cmd (char *args, int from_tty) | ||
2167 | 2270 | } |
2168 | 2271 | } |
2169 | 2272 | |
2273 | +namespace selftests { | |
2274 | + | |
2275 | +static std::vector<std::pair<const char*, const target_desc *>> xml_tdesc; | |
2276 | + | |
2277 | +#if GDB_SELF_TEST | |
2278 | +void | |
2279 | +record_xml_tdesc (const char *xml_file, const struct target_desc *tdesc) | |
2280 | +{ | |
2281 | + xml_tdesc.emplace_back (xml_file, tdesc); | |
2282 | +} | |
2283 | +#endif | |
2284 | + | |
2285 | +} | |
2286 | + | |
2287 | +/* Test these GDB builtin target descriptions equal to these which | |
2288 | + are generated by the corresponding xml files. */ | |
2289 | + | |
2290 | +static void | |
2291 | +maintenance_check_xml_descriptions (char *name, int from_tty) | |
2292 | +{ | |
2293 | + if (name == NULL) | |
2294 | + error (_("Missing dir name")); | |
2295 | + | |
2296 | + std::string feature_dir (name); | |
2297 | + unsigned int failed = 0; | |
2298 | + | |
2299 | + for (auto const &e : selftests::xml_tdesc) | |
2300 | + { | |
2301 | + std::string tdesc_xml = (feature_dir + SLASH_STRING + e.first); | |
2302 | + const target_desc *tdesc | |
2303 | + = file_read_description_xml (tdesc_xml.data ()); | |
2304 | + | |
2305 | + if (tdesc == NULL || *tdesc != *e.second) | |
2306 | + failed++; | |
2307 | + } | |
2308 | + printf_filtered (_("%lu XML are tested, %d failed\n"), | |
2309 | + (long) selftests::xml_tdesc.size (), failed); | |
2310 | +} | |
2311 | + | |
2170 | 2312 | /* Provide a prototype to silence -Wmissing-prototypes. */ |
2171 | 2313 | extern initialize_file_ftype _initialize_target_descriptions; |
2172 | 2314 |
@@ -2207,4 +2349,10 @@ GDB will read the description from the target."), | ||
2207 | 2349 | add_cmd ("c-tdesc", class_maintenance, maint_print_c_tdesc_cmd, _("\ |
2208 | 2350 | Print the current target description as a C source file."), |
2209 | 2351 | &maintenanceprintlist); |
2352 | + | |
2353 | + add_cmd ("xml-descriptions", class_maintenance, | |
2354 | + maintenance_check_xml_descriptions, _("\ | |
2355 | +Check the target descriptions.\n\ | |
2356 | +Takes a directory parameter."), | |
2357 | + &maintenancechecklist); | |
2210 | 2358 | } |
@@ -253,4 +253,14 @@ void tdesc_create_reg (struct tdesc_feature *feature, const char *name, | ||
253 | 253 | int regnum, int save_restore, const char *group, |
254 | 254 | int bitsize, const char *type); |
255 | 255 | |
256 | +#if GDB_SELF_TEST | |
257 | +namespace selftests { | |
258 | + | |
259 | +/* Record the target description TDESC generated by XML_FILE. */ | |
260 | + | |
261 | +void record_xml_tdesc (const char *xml_file, | |
262 | + const struct target_desc *tdesc); | |
263 | +} | |
264 | +#endif | |
265 | + | |
256 | 266 | #endif /* TARGET_DESCRIPTIONS_H */ |
@@ -15,3 +15,8 @@ | ||
15 | 15 | |
16 | 16 | gdb_start |
17 | 17 | gdb_test "maintenance selftest" "Ran $decimal unit tests, 0 failed" |
18 | + | |
19 | +if { ![is_remote host] } { | |
20 | + gdb_test "maintenance check xml-descriptions ${srcdir}/../features" \ | |
21 | + "$decimal XML are tested, 0 failed" | |
22 | +} |