OLD | NEW |
| (Empty) |
1 #!/usr/bin/python | |
2 # | |
3 # Copyright (c) 2012 The Native Client Authors. All rights reserved. | |
4 # Use of this source code is governed by a BSD-style license that can be | |
5 # found in the LICENSE file. | |
6 # | |
7 | |
8 """ | |
9 Responsible for generating the testing decoders based on | |
10 parsed table representations. | |
11 """ | |
12 | |
13 # This file generates testing code for our class decoder. The decoder | |
14 # tables are specifically written to minimize the number of decoder | |
15 # classes needed to parse valid ARM instructions. For testing, this is | |
16 # a problem. We can't (easily) tell if the intended instruction rules | |
17 # of ARM are being met, since there is not a one-to-one mapping from | |
18 # class decoders to rules. | |
19 # | |
20 # For example, consider the following two rows (from armv7.table): | |
21 # | |
22 # | 0011x - = Binary4RegisterShiftedOp | |
23 # Rsb_Rule_144_A1_P288 | |
24 # cccc0000011snnnnddddssss0tt1mmmm | |
25 # RegsNotPc | |
26 # | 0100x - = Binary4RegisterShiftedOp | |
27 # Add_Rule_7_A1_P26 | |
28 # cccc0000100snnnnddddssss0tt1mmmm | |
29 # RegsNotPc | |
30 # | |
31 # Both rows state to return a Binary4RegisterShiftedOp class decoder. | |
32 # The sequence of four symbols correspond to (in order presented): | |
33 # | |
34 # name - The name of the class decoder to use in sel_ldr | |
35 # rule - A unique name identifying the rule from the manual that | |
36 # defines what the selected class decoder is to decode. | |
37 # pattern - The sequence of bits defines by the rule (above) | |
38 # constraints - Any additional constraints assumed by the rule. | |
39 # | |
40 # All but the name is optional. The remaining fields provide | |
41 # additional documentation and information for testing (which is | |
42 # used by this file). | |
43 # | |
44 # If these two rows had a mergable bit pattern (which they do not), | |
45 # these rows would still not mergable since the actions are | |
46 # different. However, for sel_ldr, they both state to use a | |
47 # Binary4RegisterShiftedOp. The remaining identifiers are added data | |
48 # for testing only. | |
49 # | |
50 # We fix this by defining a notion of "action_filter" where one can | |
51 # choose to keep only those fields that are applicable. For sel_ldr, | |
52 # it's only 'name'. For testing, it will include other fields, | |
53 # depending on the context. | |
54 # | |
55 # Note: The current ARM instruction table has both new and old | |
56 # actions. Old actions only define the 'InstClass' entry. If the | |
57 # remaining fields are omitted, the corresponding testing for those | |
58 # entries are omitted. | |
59 # | |
60 # Note: See dgen_decoder_output.py for more details on how we build a | |
61 # decoder for sel_ldr. | |
62 # | |
63 # For testing, we would like to know the specific instruction rule | |
64 # that was being tested. Further, we would like to know what | |
65 # instruction rule was chosen for each decoder class selection made by | |
66 # the parse tables. To do this, we do two levels of wrapping. | |
67 # | |
68 # This file generates a set of wrapper classes, each a subclass of | |
69 # NamedClassDecoder. One is generated for each InstClass needed by | |
70 # sel_ldr (i.e. only the 'name' field). These named classes correspond | |
71 # to what sel_ldr will select. | |
72 # | |
73 # The named version of each named InstClass is: | |
74 # | |
75 # class NamedInstClass : public NamedClassDecoder { | |
76 # public: | |
77 # inline NamedInstClass() | |
78 # : NamedClassDecoder(decoder_, "InstClass") | |
79 # {} | |
80 # virtual ~NamedInstClass() {} | |
81 # protected: | |
82 # explicit inline NamedInstClass(const char* name) | |
83 # : NamedClassDecoder(decoder_, name) {} | |
84 # private: | |
85 # Binary3RegisterShiftedTest decoder_; | |
86 #}; | |
87 # | |
88 # This makes sure that each decoder class can be identified using a | |
89 # separate class decoder. The public constructor is for table rows | |
90 # that don't have rule names. The protected constructor is for table | |
91 # rows that have a rule name, and will be a subclass of this class. | |
92 # The class defined for rows with a Rule name is: | |
93 # | |
94 # class NamedRuleInstClass : public NamedInstClass { | |
95 # public: | |
96 # inline NamedRuleInstClass() | |
97 # : NamedInstClass("RuleInstClass") | |
98 # {} | |
99 # virtual ~NamedRuleInstClass() {} | |
100 #}; | |
101 # | |
102 # The base class for NamedClassDecoder is specified in | |
103 # "named_class_decoder.h". This file defines a class that takes a | |
104 # ClassDecoder (reference) C and a print name NAME, and builds a | |
105 # corresponding ClassDecoder that acts like C, but will print out | |
106 # NAME. The behaviour of C is maintained by dispatching each virtual | |
107 # on the NamedClassDecoder to the corresponding virtual on C. | |
108 # | |
109 # We then define the class decoder Decoder, by defining a derived | |
110 # instance of DecoderState as follows: | |
111 # | |
112 # class NamedDecoder : DecoderState { | |
113 # public: | |
114 # explicit NamedDecoder(); | |
115 # virtual ~NamedDecoder(); | |
116 # const NamedClassDecoder& decode_named(const Instruction) const; | |
117 # virtual const ClassDecoder& decode(const Instruction) const; | |
118 # ... | |
119 # }; | |
120 # | |
121 # The method decode is the expected API for the NamedDecoder, which is | |
122 # an instance of DecoderState (defined in decode.h). The method | |
123 # decode_named is the same, but returns NamedClassDecoder's so that | |
124 # good error messages can be generated by the test harnesses for | |
125 # ClassDecoder's (see decoder_tester.h for more details on | |
126 # ClassDecoder test harnesses). | |
127 # | |
128 # To the NamedDecoder, we add a constant field NamedClassDecoder for | |
129 # each possible class decoder method decode_named could return, or | |
130 # that we could use in automatically generated tests. These fields | |
131 # allow us to only create the corresponding decoder classes once | |
132 # (during constructor initialization). | |
133 # | |
134 # Finally, we add a method corresponding to each defined decoder | |
135 # table. The forms of these decoders is: | |
136 # | |
137 # inline const NamedClassDecoder& decode_TABLE( | |
138 # const nacl_arm_dec::Instruction insn) const; | |
139 # | |
140 # Each of these methods are defined as inline methods so that they can | |
141 # be optimized away in the corresponding top level methods (i.e. | |
142 # decode_named and decode). | |
143 # | |
144 # For testing, there are three files generated: | |
145 # | |
146 # decoder_named_classes.h | |
147 # decoder_named_decoder.h | |
148 # decoder_named.cc | |
149 # decoder_tests.cc | |
150 # | |
151 # File decoder_named_classes.h defines the class declarations for the | |
152 # generated Rule classes, and named class decoder classes. File | |
153 # decoder_named_decoder.h defines the decoder class NamedDecoder | |
154 # (discussed above). decoder_named.cc contains the corresponding | |
155 # implementations of the constructors and methods of these classes. | |
156 # | |
157 # decoder_tests.cc generates an automatic test harness executable, | |
158 # that will test each instruction Rule. Each test generates all | |
159 # possible matches the the corresponding Pattern of the table rule, | |
160 # and calls the corresponding tester associated with the class decoder | |
161 # of that row. By default, the tester is presumed to be named. | |
162 # | |
163 # InstClassTester | |
164 # | |
165 # If the row defines a Constraints identifier, then the tester | |
166 # | |
167 # InstClassTesterConstraints | |
168 # | |
169 # is used instead. | |
170 | |
171 import dgen_opt | |
172 import dgen_output | |
173 | |
174 # Defines the header for decoder_named_classes.h | |
175 NAMED_CLASSES_H_HEADER=""" | |
176 %(FILE_HEADER)s | |
177 %(NOT_TCB_MESSAGE)s | |
178 | |
179 #ifndef %(IFDEF_NAME)s | |
180 #define %(IFDEF_NAME)s | |
181 | |
182 #include "native_client/src/trusted/validator_arm/named_class_decoder.h" | |
183 | |
184 """ | |
185 | |
186 RULE_CLASSES_HEADER=""" | |
187 /* | |
188 * Define rule decoder classes. | |
189 */ | |
190 namespace nacl_arm_dec { | |
191 """ | |
192 | |
193 RULE_CLASS=""" | |
194 class %(rule)s%(decoder)s | |
195 : public %(decoder)s { | |
196 public: | |
197 virtual ~%(rule)s%(decoder)s() {} | |
198 }; | |
199 | |
200 """ | |
201 | |
202 RULE_CLASSES_FOOTER=""" | |
203 } // nacl_arm_dec | |
204 """ | |
205 | |
206 NAMED_H_NAMESPACE=""" | |
207 namespace nacl_arm_test { | |
208 """ | |
209 | |
210 NAMED_DECODERS_HEADER=""" | |
211 /* | |
212 * Define named class decoders for each class decoder. | |
213 * The main purpose of these classes is to introduce | |
214 * instances that are named specifically to the class decoder | |
215 * and/or rule that was used to parse them. This makes testing | |
216 * much easier in that error messages use these named classes | |
217 * to clarify what row in the corresponding table was used | |
218 * to select this decoder. Without these names, debugging the | |
219 * output of the test code would be nearly impossible | |
220 */ | |
221 | |
222 """ | |
223 | |
224 NAMED_DECODER_DECLARE=""" | |
225 class Named%(decoder)s : public NamedClassDecoder { | |
226 public: | |
227 inline Named%(decoder)s() | |
228 : NamedClassDecoder(decoder_, "%(decoder)s") | |
229 {} | |
230 virtual ~Named%(decoder)s() {} | |
231 protected: | |
232 explicit inline Named%(decoder)s(const char* name) | |
233 : NamedClassDecoder(decoder_, name) {} | |
234 private: | |
235 nacl_arm_dec::%(decoder)s decoder_; | |
236 }; | |
237 | |
238 """ | |
239 | |
240 NAMED_RULE_DECLARE=""" | |
241 class Named%(rule)s%(decoder)s | |
242 : public Named%(decoder)s { | |
243 public: | |
244 inline Named%(rule)s%(decoder)s() | |
245 : Named%(decoder)s("%(rule)s%(decoder)s") | |
246 {} | |
247 virtual ~Named%(rule)s%(decoder)s() {} | |
248 }; | |
249 | |
250 """ | |
251 | |
252 NAMED_CLASSES_H_FOOTER=""" | |
253 } // namespace nacl_arm_test | |
254 #endif // %(IFDEF_NAME)s | |
255 """ | |
256 | |
257 def generate_named_classes_h(decoder, decoder_name, filename, out): | |
258 """Defines named classes needed for decoder testing. | |
259 | |
260 Args: | |
261 tables: list of Table objects to process. | |
262 decoder_name: The name of the decoder state to build. | |
263 filename: The (localized) name for the .h file. | |
264 out: a COutput object to write to. | |
265 """ | |
266 if not decoder.primary: raise Exception('No tables provided.') | |
267 | |
268 values = { | |
269 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, | |
270 'NOT_TCB_MESSAGE' : dgen_output.NOT_TCB_BOILERPLATE, | |
271 'IFDEF_NAME' : dgen_output.ifdef_name(filename), | |
272 'decoder_name': decoder_name, | |
273 } | |
274 out.write(NAMED_CLASSES_H_HEADER % values) | |
275 _generate_rule_classes(decoder, values, out) | |
276 out.write(NAMED_H_NAMESPACE) | |
277 _generate_named_decoder_classes(decoder, values, out) | |
278 out.write(NAMED_CLASSES_H_FOOTER % values) | |
279 | |
280 def _generate_named_decoder_classes(decoder, values, out): | |
281 out.write(NAMED_DECODERS_HEADER) | |
282 # Generate one for each type of decoder in the decoder. | |
283 for d in decoder.action_filter(['name']).decoders(): | |
284 values['decoder'] = d.name | |
285 values['rule'] = '' | |
286 out.write(NAMED_DECODER_DECLARE % values) | |
287 # Now generate one for each decoder that has a rule associated with it. | |
288 for d in decoder.action_filter(['name', 'rule']).rules(): | |
289 values['decoder'] = d.name | |
290 values['rule'] = d.rule | |
291 out.write(NAMED_RULE_DECLARE % values) | |
292 | |
293 def _generate_rule_classes(decoder, values, out): | |
294 # Note: we generate these classes in nacl_arm_dec, so that | |
295 # all decoder classes generated by the pareser are in the | |
296 # same namesapce. | |
297 out.write(RULE_CLASSES_HEADER) | |
298 for action in decoder.action_filter(['name', 'rule']).rules(): | |
299 values['decoder'] = action.name | |
300 values['rule'] = action.rule | |
301 out.write(RULE_CLASS % values) | |
302 out.write(RULE_CLASSES_FOOTER) | |
303 | |
304 NAMED_DECODER_H_HEADER=""" | |
305 %(FILE_HEADER)s | |
306 %(NOT_TCB_MESSAGE)s | |
307 | |
308 #ifndef %(IFDEF_NAME)s | |
309 #define %(IFDEF_NAME)s | |
310 | |
311 #include "native_client/src/trusted/validator_arm/decode.h" | |
312 #include "%(FILENAME_BASE)s_classes.h" | |
313 #include "native_client/src/trusted/validator_arm/named_class_decoder.h" | |
314 | |
315 namespace nacl_arm_test { | |
316 """ | |
317 | |
318 DECODER_STATE_HEADER=""" | |
319 // Defines a (named) decoder class selector for instructions | |
320 class Named%(decoder_name)s : nacl_arm_dec::DecoderState { | |
321 public: | |
322 explicit Named%(decoder_name)s(); | |
323 virtual ~Named%(decoder_name)s(); | |
324 | |
325 // Parses the given instruction, returning the named class | |
326 // decoder to use. | |
327 const NamedClassDecoder& decode_named( | |
328 const nacl_arm_dec::Instruction) const; | |
329 | |
330 // Parses the given instruction, returning the class decoder | |
331 // to use. | |
332 virtual const nacl_arm_dec::ClassDecoder& decode( | |
333 const nacl_arm_dec::Instruction) const; | |
334 """ | |
335 | |
336 DECODER_STATE_FIELD_COMMENTS=""" | |
337 // The following fields define the set of class decoders | |
338 // that can be returned by the API function "decode_named". They | |
339 // are created once as instance fields, and then returned | |
340 // by the table methods above. This speeds up the code since | |
341 // the class decoders need to only be bulit once (and reused | |
342 // for each call to "decode_named"). | |
343 """ | |
344 | |
345 DECODER_STATE_FIELD=""" | |
346 const Named%(rule)s%(decoder)s %(rule)s%(decoder)s_instance_; | |
347 """ | |
348 | |
349 DECODER_STATE_PRIVATE=""" | |
350 private: | |
351 """ | |
352 | |
353 DECODER_STATE_DECODER_COMMENTS=""" | |
354 // The following list of methods correspond to each decoder table, | |
355 // and implements the pattern matching of the corresponding bit | |
356 // patterns. After matching the corresponding bit patterns, they | |
357 // either call other methods in this list (corresponding to another | |
358 // decoder table), or they return the instance field that implements | |
359 // the class decoder that should be used to decode the particular | |
360 // instruction. | |
361 """ | |
362 | |
363 DECODER_STATE_DECODER=""" | |
364 inline const NamedClassDecoder& decode_%(table)s( | |
365 const nacl_arm_dec::Instruction insn) const; | |
366 """ | |
367 | |
368 DECODER_STATE_FOOTER=""" | |
369 }; | |
370 """ | |
371 | |
372 NAMED_DECODER_H_FOOTER=""" | |
373 } // namespace nacl_arm_test | |
374 #endif // %(IFDEF_NAME)s | |
375 """ | |
376 | |
377 def generate_named_decoder_h(decoder, decoder_name, filename, out): | |
378 """Generates the named decoder for testing. | |
379 | |
380 Args: | |
381 tables: list of Table objects to process. | |
382 decoder_name: The name of the decoder state to build. | |
383 filename: The (localized) name for the .h file. | |
384 out: a COutput object to write to. | |
385 """ | |
386 if not decoder.primary: raise Exception('No tables provided.') | |
387 assert filename.endswith('_decoder.h') | |
388 | |
389 values = { | |
390 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, | |
391 'NOT_TCB_MESSAGE' : dgen_output.NOT_TCB_BOILERPLATE, | |
392 'IFDEF_NAME' : dgen_output.ifdef_name(filename), | |
393 'FILENAME_BASE': filename[:-len('_decoder.h')], | |
394 'decoder_name': decoder_name, | |
395 } | |
396 out.write(NAMED_DECODER_H_HEADER % values) | |
397 _generate_decoder_state_class(decoder, values, out) | |
398 out.write(NAMED_DECODER_H_FOOTER % values) | |
399 | |
400 def _generate_decoder_state_class(decoder, values, out): | |
401 # Generate a field for each type of decoder in the decoder. | |
402 out.write(DECODER_STATE_HEADER % values) | |
403 out.write(DECODER_STATE_FIELD_COMMENTS); | |
404 for d in decoder.action_filter(['name']).decoders(): | |
405 values['decoder'] = d.name | |
406 values['rule'] = '' | |
407 out.write(DECODER_STATE_FIELD % values) | |
408 # Now generate one for each decoder that has a rule associated with it. | |
409 for d in decoder.action_filter(['name', 'rule']).rules(): | |
410 values['decoder'] = d.name | |
411 values['rule'] = d.rule | |
412 out.write(DECODER_STATE_FIELD % values) | |
413 out.write(DECODER_STATE_PRIVATE); | |
414 out.write(DECODER_STATE_DECODER_COMMENTS) | |
415 for table in decoder.tables(): | |
416 values['table'] = table.name | |
417 out.write(DECODER_STATE_DECODER % values) | |
418 out.write(DECODER_STATE_FOOTER % values) | |
419 | |
420 # Defines the source for DECODER_named.cc | |
421 NAMED_CC_HEADER=""" | |
422 %(FILE_HEADER)s | |
423 %(NOT_TCB_MESSAGE)s | |
424 #include "%(FILENAME_BASE)s_decoder.h" | |
425 | |
426 #include <stdio.h> | |
427 | |
428 using nacl_arm_dec::ClassDecoder; | |
429 using nacl_arm_dec::Instruction; | |
430 | |
431 namespace nacl_arm_test { | |
432 """ | |
433 | |
434 PARSE_CONSTRUCT_HEADER=""" | |
435 Named%(decoder_name)s::Named%(decoder_name)s() | |
436 : nacl_arm_dec::DecoderState() | |
437 """ | |
438 | |
439 PARSE_CONSTRUCT_FIELDS=""" | |
440 , %(rule)s%(decoder)s_instance_() | |
441 """ | |
442 | |
443 PARSE_CONSTRUCT_FOOTER=""" | |
444 {} | |
445 | |
446 Named%(decoder_name)s::~Named%(decoder_name)s() {} | |
447 """ | |
448 | |
449 PARSE_TABLE_METHOD_HEADER=""" | |
450 /* | |
451 * Implementation of table %(table_name)s. | |
452 * Specified by: %(citation)s | |
453 */ | |
454 const NamedClassDecoder& Named%(decoder_name)s::decode_%(table_name)s( | |
455 const nacl_arm_dec::Instruction insn) const { | |
456 """ | |
457 | |
458 PARSE_TABLE_METHOD_ROW=""" | |
459 if (%(tests)s) { | |
460 return %(action)s; | |
461 } | |
462 """ | |
463 | |
464 PARSE_TABLE_METHOD_FOOTER=""" | |
465 // Catch any attempt to fall through... | |
466 fprintf(stderr, "TABLE IS INCOMPLETE: %(table_name)s could not parse %%08X", | |
467 insn.bits(31,0)); | |
468 return Forbidden_instance_; | |
469 } | |
470 | |
471 """ | |
472 | |
473 NAMED_CC_FOOTER=""" | |
474 const NamedClassDecoder& Named%(decoder_name)s:: | |
475 decode_named(const nacl_arm_dec::Instruction insn) const { | |
476 return decode_%(entry_table_name)s(insn); | |
477 } | |
478 | |
479 const nacl_arm_dec::ClassDecoder& Named%(decoder_name)s:: | |
480 decode(const nacl_arm_dec::Instruction insn) const { | |
481 return decode_named(insn).named_decoder(); | |
482 } | |
483 | |
484 } // namespace nacl_arm_test | |
485 """ | |
486 | |
487 def generate_named_cc(decoder, decoder_name, filename, out): | |
488 """Implementation of the test decoder in .cc file | |
489 | |
490 Args: | |
491 tables: list of Table objects to process. | |
492 decoder_name: The name of the decoder state to build. | |
493 filename: The (localized) name for the .h file. | |
494 out: a COutput object to write to. | |
495 """ | |
496 if not decoder.primary: raise Exception('No tables provided.') | |
497 assert filename.endswith('.cc') | |
498 | |
499 values = { | |
500 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, | |
501 'NOT_TCB_MESSAGE' : dgen_output.NOT_TCB_BOILERPLATE, | |
502 'FILENAME_BASE' : filename[:-len('.cc')], | |
503 'decoder_name': decoder_name, | |
504 'entry_table_name': decoder.primary.name, | |
505 } | |
506 out.write(NAMED_CC_HEADER % values) | |
507 _generate_decoder_constructors(decoder, values, out) | |
508 _generate_decoder_method_bodies(decoder, values, out) | |
509 out.write(NAMED_CC_FOOTER % values) | |
510 | |
511 def _generate_decoder_constructors(decoder, values, out): | |
512 out.write(PARSE_CONSTRUCT_HEADER % values) | |
513 # Initialize each type of decoder in the decoder. | |
514 for d in decoder.action_filter(['name']).decoders(): | |
515 values['decoder'] = d.name | |
516 values['rule'] = '' | |
517 out.write(PARSE_CONSTRUCT_FIELDS % values) | |
518 # Now initialize fields for each decoder with a rule. | |
519 for d in decoder.action_filter(['name', 'rule']).rules(): | |
520 values['decoder'] = d.name | |
521 values['rule'] = d.rule | |
522 out.write(PARSE_CONSTRUCT_FIELDS % values) | |
523 out.write(PARSE_CONSTRUCT_FOOTER % values) | |
524 | |
525 def _generate_decoder_method_bodies(decoder, values, out): | |
526 for table in decoder.tables(): | |
527 opt_rows = dgen_opt.optimize_rows( | |
528 table.action_filter(['name', 'rule']).rows) | |
529 print ("Table %s: %d rows minimized to %d" | |
530 % (table.name, len(table.rows), len(opt_rows))) | |
531 | |
532 values['table_name'] = table.name | |
533 values['citation'] = table.citation, | |
534 out.write(PARSE_TABLE_METHOD_HEADER % values) | |
535 | |
536 # Add message to stop compilation warnings if this table | |
537 # doesn't require subtables to select a class decoder. | |
538 if not [r for r in opt_rows | |
539 if r.action.__class__.__name__ == 'DecoderMethod']: | |
540 out.write(" UNREFERENCED_PARAMETER(insn);") | |
541 | |
542 for row in opt_rows: | |
543 if row.action.__class__.__name__ == 'DecoderAction': | |
544 values['decoder'] = row.action.name | |
545 values['rule'] = row.action.rule if row.action.rule else '' | |
546 action = '%(rule)s%(decoder)s_instance_' % values | |
547 elif row.action.__class__.__name__ == 'DecoderMethod': | |
548 action = 'decode_%s(insn)' % row.action.name | |
549 else: | |
550 raise Exception('Bad table action: %s' % row.action) | |
551 # Each row consists of a set of bit patterns defining if the row | |
552 # is applicable. Convert this into a sequence of anded C test | |
553 # expressions. For example, convert the following pair of bit | |
554 # patterns: | |
555 # | |
556 # xxxx1010xxxxxxxxxxxxxxxxxxxxxxxx | |
557 # xxxxxxxxxxxxxxxxxxxxxxxxxxxx0101 | |
558 # | |
559 # Each instruction is masked to get the the bits, and then | |
560 # tested against the corresponding expected bits. Hence, the | |
561 # above example is converted to: | |
562 # | |
563 # ((insn & 0x0F000000) != 0x0C000000) && | |
564 # ((insn & 0x0000000F) != 0x00000005) | |
565 values['tests'] = ' && '.join(['(%s)' % p.to_c_expr('insn') | |
566 for p in row.patterns]) | |
567 values['action'] = action | |
568 out.write(PARSE_TABLE_METHOD_ROW % values) | |
569 out.write(PARSE_TABLE_METHOD_FOOTER % values) | |
570 | |
571 # Define the source for DECODER_tests.cc | |
572 TEST_CC_HEADER=""" | |
573 %(FILE_HEADER)s | |
574 %(NOT_TCB_MESSAGE)s | |
575 | |
576 #include "gtest/gtest.h" | |
577 #include "native_client/src/trusted/validator_arm/inst_classes_testers.h" | |
578 | |
579 namespace nacl_arm_test { | |
580 | |
581 """ | |
582 | |
583 TESTER_CLASS=""" | |
584 class %(rule)s%(decoder)sTester%(constraints)s | |
585 : public %(decoder)sTester%(constraints)s { | |
586 public: | |
587 %(rule)s%(decoder)sTester%(constraints)s() | |
588 : %(decoder)sTester%(constraints)s( | |
589 state_.%(rule)s%(decoder)s_instance_) | |
590 {} | |
591 }; | |
592 """ | |
593 | |
594 TEST_HARNESS=""" | |
595 // Defines a gtest testing harness for tests. | |
596 class %(decoder_name)sTests : public ::testing::Test { | |
597 protected: | |
598 %(decoder_name)sTests() {} | |
599 }; | |
600 """ | |
601 | |
602 TEST_FUNCTION=""" | |
603 TEST_F(%(decoder_name)sTests, | |
604 %(rule)s%(decoder)s%(constraints)s_%(pattern)s_Test) { | |
605 %(rule)s%(decoder)sTester%(constraints)s tester; | |
606 tester.Test("%(pattern)s"); | |
607 } | |
608 """ | |
609 | |
610 | |
611 TEST_CC_FOOTER=""" | |
612 } // namespace nacl_arm_test | |
613 | |
614 int main(int argc, char* argv[]) { | |
615 testing::InitGoogleTest(&argc, argv); | |
616 return RUN_ALL_TESTS(); | |
617 } | |
618 """ | |
619 | |
620 def generate_tests_cc(decoder, decoder_name, out): | |
621 if not decoder.primary: raise Exception('No tables provided.') | |
622 values = { | |
623 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, | |
624 'NOT_TCB_MESSAGE' : dgen_output.NOT_TCB_BOILERPLATE, | |
625 'decoder_name': decoder_name, | |
626 } | |
627 out.write(TEST_CC_HEADER % values) | |
628 _generate_rule_testers(decoder, values, out) | |
629 out.write(TEST_HARNESS % values) | |
630 _generate_test_patterns(decoder, values, out) | |
631 out.write(TEST_CC_FOOTER % values) | |
632 | |
633 def _generate_rule_testers(decoder, values, out): | |
634 for d in decoder.action_filter(['name', 'rule', 'constraints']).rules(): | |
635 values['decoder'] = d.name | |
636 values['rule'] = d.rule | |
637 values['constraints'] = d.constraints if d.constraints else '' | |
638 out.write(TESTER_CLASS % values) | |
639 | |
640 def _generate_test_patterns(decoder, values, out): | |
641 for d in decoder.decoders(): | |
642 if d.pattern: | |
643 values['decoder'] = d.name | |
644 values['rule'] = d.rule if d.rule else '' | |
645 values['constraints'] = d.constraints if d.constraints else '' | |
646 values['pattern'] = d.pattern | |
647 out.write(TEST_FUNCTION % values) | |
OLD | NEW |