OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. | 2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. |
3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 /* enuminsts.c | 7 /* enuminsts.c |
8 * exhaustive instruction enumeration test for x86 Native Client decoder. | 8 * exhaustive instruction enumeration test for x86 Native Client decoder. |
9 */ | 9 */ |
10 | 10 |
11 /* TODO(karl) - Fix the calls to the decoder for x86-32 to use the same decoder | 11 /* TODO(karl) - Fix the calls to the decoder for x86-32 to use the same decoder |
12 * as the x86-32 validator, and document how to properly test the | 12 * as the x86-32 validator, and document how to properly test the |
13 * x86-32 decoder. | 13 * x86-32 decoder. |
14 */ | 14 */ |
15 | 15 |
16 #include "native_client/src/trusted/validator/x86/testing/enuminsts/enuminsts.h" | 16 #include "native_client/src/trusted/validator/x86/testing/enuminsts/enuminsts.h" |
17 | 17 |
18 #include <ctype.h> | 18 #include <ctype.h> |
19 #include <stdio.h> | 19 #include <stdio.h> |
20 #include <string.h> | 20 #include <string.h> |
21 #include <stdlib.h> | 21 #include <stdlib.h> |
| 22 #include <stdarg.h> |
22 | 23 |
23 #include "native_client/src/shared/platform/nacl_log.h" | 24 #include "native_client/src/shared/platform/nacl_log.h" |
| 25 #include "native_client/src/trusted/validator/x86/testing/enuminsts/input_tester
.h" |
24 #include "native_client/src/trusted/validator/x86/testing/enuminsts/str_utils.h" | 26 #include "native_client/src/trusted/validator/x86/testing/enuminsts/str_utils.h" |
25 | 27 |
26 /* When non-zero, prints out additional debugging messages. */ | 28 /* When non-zero, prints out additional debugging messages. */ |
27 #define kDebug 0 | 29 #define kDebug 0 |
28 | 30 |
29 /* Defines the maximum buffer size used to hold text generated for the | 31 /* Defines the maximum buffer size used to hold text generated for the |
30 * disassembly of instructions, and corresponding error messages. | 32 * disassembly of instructions, and corresponding error messages. |
31 */ | 33 */ |
32 #define kBufferSize 1024 | 34 #define kBufferSize 1024 |
33 | 35 |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 fprintf(stderr, " --illegal=XX: Filter instructions to only consider " | 168 fprintf(stderr, " --illegal=XX: Filter instructions to only consider " |
167 "those instructions\n"); | 169 "those instructions\n"); |
168 fprintf(stderr, " that are illegal instructions, as defined by " | 170 fprintf(stderr, " that are illegal instructions, as defined by " |
169 "decoder XX\n"); | 171 "decoder XX\n"); |
170 fprintf(stderr, " --legal=XX: Filter instructions to only consider " | 172 fprintf(stderr, " --legal=XX: Filter instructions to only consider " |
171 "those instructions\n"); | 173 "those instructions\n"); |
172 fprintf(stderr, " that are legal instructions, as defined by " | 174 fprintf(stderr, " that are legal instructions, as defined by " |
173 "decoder XX\n"); | 175 "decoder XX\n"); |
174 fprintf(stderr, " --nacllegal: only compare NaCl legal instructions\n"); | 176 fprintf(stderr, " --nacllegal: only compare NaCl legal instructions\n"); |
175 fprintf(stderr, " that are legal for nacl decoder(s).\n"); | 177 fprintf(stderr, " that are legal for nacl decoder(s).\n"); |
| 178 fprintf(stderr, " --opcode_bytes=XX: Prints out opcode bytes for set of\n" |
| 179 " enumerated instructions. To be used by decoder --in\n"); |
| 180 fprintf(stderr, |
| 181 " --opcode_bytes_plus_desc=XX: Prints out opcode bytes for set of" |
| 182 " enumerated instruction, plus a print description (as a\n" |
| 183 " comment). To be used by decoder --n\n"); |
176 fprintf(stderr, " --print=XX: Prints out set of enumerated " | 184 fprintf(stderr, " --print=XX: Prints out set of enumerated " |
177 "instructions,\n"); | 185 "instructions,\n"); |
178 fprintf(stderr, " for the specified decoder XX (may be " | 186 fprintf(stderr, " for the specified decoder XX (may be " |
179 "repeated).\n"); | 187 "repeated).\n"); |
180 fprintf(stderr, " Also registers decoder XX if needed.\n"); | 188 fprintf(stderr, " Also registers decoder XX if needed.\n"); |
181 fprintf(stderr, | |
182 " --printenum: Print out enumeration of filtered instruction \n" | |
183 " opcode sequences\n"); | |
184 fprintf(stderr, " --prefix=XX: only process given prefix\n"); | 189 fprintf(stderr, " --prefix=XX: only process given prefix\n"); |
185 fprintf(stderr, " --opcode=XX: only process given opcode for " | 190 fprintf(stderr, " --opcode=XX: only process given opcode for " |
186 "each prefix\n"); | 191 "each prefix\n"); |
187 fprintf(stderr, " --opcode_bytes: Enumerate opcode bytes found by " | |
188 "NaCl disassembler\n"); | |
189 fprintf(stderr, " --nops: Don't operand compare nops.\n"); | 192 fprintf(stderr, " --nops: Don't operand compare nops.\n"); |
190 fprintf(stderr, " --skipcontiguous: Only skip contiguous errors\n"); | 193 fprintf(stderr, " --skipcontiguous: Only skip contiguous errors\n"); |
191 fprintf(stderr, " --verbose: add verbose comments to output\n"); | 194 fprintf(stderr, " --verbose: add verbose comments to output\n"); |
192 fprintf(stderr, " --xedimplemented: only compare NaCl instruction that " | 195 fprintf(stderr, " --xedimplemented: only compare NaCl instruction that " |
193 "are also implemented in xed\n"); | 196 "are also implemented in xed\n"); |
194 exit(gSawLethalError); | 197 exit(gSawLethalError); |
195 } | 198 } |
196 | 199 |
197 /* Records that unexpected internal error occurred. */ | 200 /* Records that unexpected internal error occurred. */ |
198 void InternalError(const char *why) { | 201 void InternalError(const char *why) { |
199 fprintf(stderr, "%s: Internal Error: %s\n", gArgv0, why); | 202 fprintf(stderr, "%s: Internal Error: %s\n", gArgv0, why); |
200 gSawLethalError = 1; | 203 gSawLethalError = 1; |
201 } | 204 } |
202 | 205 |
203 /* Records that a fatal (i.e. non-recoverable) error occurred. */ | 206 /* Records that a fatal (i.e. non-recoverable) error occurred. */ |
204 static void ReportFatalError(const char* why) { | 207 void ReportFatalError(const char* why) { |
205 char buffer[kBufferSize]; | 208 char buffer[kBufferSize]; |
206 snprintf(buffer, kBufferSize, "%s - quitting!", why); | 209 snprintf(buffer, kBufferSize, "%s - quitting!", why); |
207 InternalError(buffer); | 210 InternalError(buffer); |
208 exit(1); | 211 exit(1); |
209 } | 212 } |
210 | 213 |
211 /* Returns true if the given opcode sequence text is in the | 214 /* Returns true if the given opcode sequence text is in the |
212 * given instruction list. | 215 * given instruction list. |
213 */ | 216 */ |
214 static Bool InInstructionList(InstList* list, uint8_t* itext, size_t nbytes) { | 217 static Bool InInstructionList(InstList* list, uint8_t* itext, size_t nbytes) { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
259 } | 262 } |
260 | 263 |
261 /* Print error message "why", and show instructions that failed for | 264 /* Print error message "why", and show instructions that failed for |
262 * that reason. | 265 * that reason. |
263 */ | 266 */ |
264 static void CinstInternalError(ComparedInstruction* cinst, const char* why) { | 267 static void CinstInternalError(ComparedInstruction* cinst, const char* why) { |
265 PrintDisassembledInstructionVariants(cinst); | 268 PrintDisassembledInstructionVariants(cinst); |
266 InternalError(why); | 269 InternalError(why); |
267 } | 270 } |
268 | 271 |
| 272 /* Prints out progress messages. */ |
| 273 static void PrintVProgress(const char* format, va_list ap) { |
| 274 if (gSilent) { |
| 275 /* Generating opcode sequences, so add special prefix so that we |
| 276 * can print these out when read by the corresponding input decoder. |
| 277 */ |
| 278 printf("#PROGRESS#"); |
| 279 } |
| 280 vprintf(format, ap); |
| 281 } |
| 282 |
| 283 static void PrintProgress(const char* format, ...) ATTRIBUTE_FORMAT_PRINTF(1,2); |
| 284 |
| 285 /* Prints out progress messages. */ |
| 286 static void PrintProgress(const char* format, ...) { |
| 287 va_list ap; |
| 288 va_start(ap, format); |
| 289 PrintVProgress(format, ap); |
| 290 va_end(ap); |
| 291 } |
| 292 |
269 /* Initial value for last bad opcode. */ | 293 /* Initial value for last bad opcode. */ |
270 #define NOT_AN_OPCODE "not an opcode" | 294 #define NOT_AN_OPCODE "not an opcode" |
271 | 295 |
272 /* Holds the name of the last (bad) mnemonic name matched. | 296 /* Holds the name of the last (bad) mnemonic name matched. |
273 * Uses the mnemonic name associated with instructions decoded | 297 * Uses the mnemonic name associated with instructions decoded |
274 * by the first decoder. | 298 * by the first decoder. |
275 */ | 299 */ |
276 static char last_bad_mnemonic[kBufferSize] = NOT_AN_OPCODE; | 300 static char last_bad_mnemonic[kBufferSize] = NOT_AN_OPCODE; |
277 | 301 |
278 /* Returns how many decoder errors were skipped for an opcode. */ | 302 /* Returns how many decoder errors were skipped for an opcode. */ |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
333 return; | 357 return; |
334 } | 358 } |
335 } | 359 } |
336 } | 360 } |
337 | 361 |
338 /* If reached, did not skip, so report the error. */ | 362 /* If reached, did not skip, so report the error. */ |
339 printf("**** ERROR: %s: %s\n", why, (details == NULL ? "" : details)); | 363 printf("**** ERROR: %s: %s\n", why, (details == NULL ? "" : details)); |
340 PrintDisassembledInstructionVariants(cinst); | 364 PrintDisassembledInstructionVariants(cinst); |
341 } | 365 } |
342 | 366 |
343 /* Returns the integer corresponding to a hex value in ASCII. This would | |
344 * be faster as an array lookup, however since it's only used for command | |
345 * line input it doesn't matter. | |
346 */ | |
347 static unsigned int A2INibble(char nibble) { | |
348 switch (nibble) { | |
349 case '0': return 0; | |
350 case '1': return 1; | |
351 case '2': return 2; | |
352 case '3': return 3; | |
353 case '4': return 4; | |
354 case '5': return 5; | |
355 case '6': return 6; | |
356 case '7': return 7; | |
357 case '8': return 8; | |
358 case '9': return 9; | |
359 case 'a': | |
360 case 'A': return 0xA; | |
361 case 'b': | |
362 case 'B': return 0xB; | |
363 case 'c': | |
364 case 'C': return 0xC; | |
365 case 'd': | |
366 case 'D': return 0xD; | |
367 case 'e': | |
368 case 'E': return 0xE; | |
369 case 'f': | |
370 case 'F': return 0xF; | |
371 default: break; | |
372 } | |
373 fprintf(stderr, "bad hex value %c", nibble); | |
374 exit(1); | |
375 } | |
376 | |
377 /* Convert a two-character string representing an byte value in hex | |
378 * into the corresponding byte value. | |
379 */ | |
380 static unsigned int A2IByte(char nibble1, char nibble2) { | |
381 return A2INibble(nibble2) + A2INibble(nibble1) * 0x10; | |
382 } | |
383 | |
384 /* Generates a buffer containing the context message to print. | |
385 * Arguments are: | |
386 * context - String describing the context (i.e. filename or | |
387 * command line argument description). | |
388 * line - The line number associated with the context (if negative, | |
389 * it assumes that the line number shouldn't be reported). | |
390 */ | |
391 static const char* TextContext(const char* context, | |
392 int line) { | |
393 if (line < 0) { | |
394 return context; | |
395 } else { | |
396 static char buffer[kBufferSize]; | |
397 snprintf(buffer, kBufferSize, "%s line %d", context, line); | |
398 return buffer; | |
399 } | |
400 } | |
401 | |
402 /* Installs byte into the byte buffer. Returns the new value for num_bytes. | |
403 * Arguments are: | |
404 * ibytes - The found sequence of opcode bytes. | |
405 * num_bytes - The number of bytes currently in ibytes. | |
406 * mini_buf - The buffer containing the two hexidecimal characters to convert. | |
407 * context - String describing the context (i.e. filename or | |
408 * command line argument description). | |
409 * line - The line number associated with the context (if negative, | |
410 * it assumes that the line number shouldn't be reported). | |
411 */ | |
412 static int InstallTextByte(uint8_t ibytes[NACL_ENUM_MAX_INSTRUCTION_BYTES], | |
413 int num_bytes, | |
414 char mini_buf[2], | |
415 const char* itext, | |
416 const char* context, | |
417 int line) { | |
418 if (num_bytes == NACL_ENUM_MAX_INSTRUCTION_BYTES) { | |
419 char buffer[kBufferSize]; | |
420 snprintf(buffer, kBufferSize, | |
421 "%s: opcode sequence too long in '%s'", | |
422 TextContext(context, line), itext); | |
423 ReportFatalError(buffer); | |
424 } | |
425 ibytes[num_bytes] = A2IByte(mini_buf[0], mini_buf[1]); | |
426 return num_bytes + 1; | |
427 } | |
428 | |
429 /* Reads a line of text defining the sequence of bytes that defines | |
430 * an instruction, and converts that to the corresponding sequence of | |
431 * opcode bytes. Returns the number of bytes found. Arguments are: | |
432 * ibytes - The found sequence of opcode bytes. | |
433 * itext - The sequence of bytes to convert. | |
434 * context - String describing the context (i.e. filename or | |
435 * command line argument description). | |
436 * line - The line number associated with the context (if negative, | |
437 * it assumes that the line number shouldn't be reported). | |
438 */ | |
439 static int Text2Bytes(uint8_t ibytes[NACL_ENUM_MAX_INSTRUCTION_BYTES], | |
440 char* itext, | |
441 const char* context, | |
442 int line) { | |
443 char mini_buf[2]; | |
444 size_t mini_buf_index; | |
445 char *next; | |
446 char ch; | |
447 int num_bytes = 0; | |
448 Bool continue_translation = TRUE; | |
449 | |
450 /* Now process text of itext. */ | |
451 next = &itext[0]; | |
452 mini_buf_index = 0; | |
453 while (continue_translation && (ch = *(next++))) { | |
454 switch (ch) { | |
455 case '#': | |
456 /* Comment, skip reading any more characters. */ | |
457 continue_translation = FALSE; | |
458 break; | |
459 case '0': | |
460 case '1': | |
461 case '2': | |
462 case '3': | |
463 case '4': | |
464 case '5': | |
465 case '6': | |
466 case '7': | |
467 case '8': | |
468 case '9': | |
469 case 'a': | |
470 case 'b': | |
471 case 'c': | |
472 case 'd': | |
473 case 'e': | |
474 case 'f': | |
475 case 'A': | |
476 case 'B': | |
477 case 'C': | |
478 case 'D': | |
479 case 'E': | |
480 case 'F': | |
481 /* Hexidecimal character. Add to mini buffer, and install | |
482 * if two bytes. | |
483 */ | |
484 mini_buf[mini_buf_index++] = ch; | |
485 if (2 == mini_buf_index) { | |
486 num_bytes = InstallTextByte(ibytes, num_bytes, mini_buf, itext, | |
487 context, line); | |
488 mini_buf_index = 0; | |
489 } | |
490 break; | |
491 case ' ': | |
492 case '\t': | |
493 case '\n': | |
494 /* Space - assume it is a separator between bytes. */ | |
495 switch(mini_buf_index) { | |
496 case 0: | |
497 break; | |
498 case 2: | |
499 num_bytes = InstallTextByte(ibytes, num_bytes, mini_buf, itext, | |
500 context, line); | |
501 mini_buf_index = 0; | |
502 break; | |
503 default: | |
504 continue_translation = FALSE; | |
505 } | |
506 break; | |
507 default: { | |
508 char buffer[kBufferSize]; | |
509 snprintf(buffer, kBufferSize, | |
510 "%s: contains bad text:\n '%s'\n", | |
511 TextContext(context, line), itext); | |
512 ReportFatalError(buffer); | |
513 break; | |
514 } | |
515 } | |
516 } | |
517 | |
518 /* If only a single byte was used to define hex value, convert it. */ | |
519 if (mini_buf_index > 0) { | |
520 char buffer[kBufferSize]; | |
521 snprintf(buffer, kBufferSize, | |
522 "%s: Opcode sequence must be an even number of chars '%s'", | |
523 TextContext(context, line), itext); | |
524 ReportFatalError(buffer); | |
525 } | |
526 | |
527 return num_bytes; | |
528 } | |
529 | |
530 #if NACL_TARGET_SUBARCH == 64 | 367 #if NACL_TARGET_SUBARCH == 64 |
531 | |
532 /* The instructions: | 368 /* The instructions: |
533 * 48 89 e5 mov rbp, rsp | 369 * 48 89 e5 mov rbp, rsp |
534 * 4a 89 e5 mov rbp, rsp | 370 * 4a 89 e5 mov rbp, rsp |
535 * look bad based on the simple rule, but are safe because they are | 371 * look bad based on the simple rule, but are safe because they are |
536 * moving a safe address between two protected registers. | 372 * moving a safe address between two protected registers. |
537 */ | 373 */ |
538 static int IsSpecialSafeRegWrite(ComparedInstruction *cinst) { | 374 static int IsSpecialSafeRegWrite(ComparedInstruction *cinst) { |
539 uint8_t byte0 = cinst->_enumerator._itext[0]; | 375 uint8_t byte0 = cinst->_enumerator._itext[0]; |
540 uint8_t byte1 = cinst->_enumerator._itext[1]; | 376 uint8_t byte1 = cinst->_enumerator._itext[1]; |
541 uint8_t byte2 = cinst->_enumerator._itext[2]; | 377 uint8_t byte2 = cinst->_enumerator._itext[2]; |
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
791 | 627 |
792 /* Print out decodings for print only directives. Returns true | 628 /* Print out decodings for print only directives. Returns true |
793 * if print only directives followed. This function is used | 629 * if print only directives followed. This function is used |
794 * to short circuit instruction comparison, when printing of | 630 * to short circuit instruction comparison, when printing of |
795 * filtered instructions on the command line is specified. | 631 * filtered instructions on the command line is specified. |
796 */ | 632 */ |
797 static Bool PrintInstOnly(ComparedInstruction *cinst) { | 633 static Bool PrintInstOnly(ComparedInstruction *cinst) { |
798 Bool result = FALSE; | 634 Bool result = FALSE; |
799 size_t i; | 635 size_t i; |
800 for (i = 0; i < cinst->_enumerator._num_decoders; ++i) { | 636 for (i = 0; i < cinst->_enumerator._num_decoders; ++i) { |
801 if (cinst->_enumerator._decoder[i]->_print_only) { | 637 NaClEnumeratorDecoder* decoder = cinst->_enumerator._decoder[i]; |
| 638 if (decoder->_print) { |
802 cinst->_enumerator._decoder[i]->_print_inst_fn(&cinst->_enumerator); | 639 cinst->_enumerator._decoder[i]->_print_inst_fn(&cinst->_enumerator); |
803 result = TRUE; | 640 result = TRUE; |
804 } | 641 } |
| 642 if (decoder->_print_opcode_sequence || |
| 643 decoder->_print_opcode_sequence_plus_desc) { |
| 644 size_t length = decoder->_inst_length_fn(&cinst->_enumerator); |
| 645 for (i = 0; i < length; ++i) { |
| 646 printf("%02x", cinst->_enumerator._itext[i]); |
| 647 } |
| 648 if (decoder->_print_opcode_sequence_plus_desc && |
| 649 decoder->_is_inst_legal_fn(&cinst->_enumerator) && |
| 650 (NULL != decoder->_get_inst_mnemonic_fn) && |
| 651 (NULL != decoder->_get_inst_operands_text_fn)) { |
| 652 printf("#%s %s", decoder->_get_inst_mnemonic_fn(&cinst->_enumerator), |
| 653 decoder->_get_inst_operands_text_fn(&cinst->_enumerator)); |
| 654 } |
| 655 printf("\n"); |
| 656 result = TRUE; |
| 657 } |
805 } | 658 } |
806 return result; | 659 return result; |
807 } | 660 } |
808 | 661 |
809 /* If non-null, the list of instruction bytes to ignore. */ | 662 /* If non-null, the list of instruction bytes to ignore. */ |
810 static InstList* kIgnoredInstructions = NULL; | 663 static InstList* kIgnoredInstructions = NULL; |
811 | 664 |
812 /* Test comparison for a single instruction. | 665 /* Test comparison for a single instruction. |
813 */ | 666 */ |
814 static void TryOneInstruction(ComparedInstruction *cinst, | 667 static void TryOneInstruction(ComparedInstruction *cinst, |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
873 } | 726 } |
874 } | 727 } |
875 return found_legal; | 728 return found_legal; |
876 } | 729 } |
877 | 730 |
878 /* Enumerate and test all 24-bit opcode+modrm+sib patterns for a | 731 /* Enumerate and test all 24-bit opcode+modrm+sib patterns for a |
879 * particular prefix. | 732 * particular prefix. |
880 */ | 733 */ |
881 static void TestAllWithPrefix(ComparedInstruction *cinst, | 734 static void TestAllWithPrefix(ComparedInstruction *cinst, |
882 int prefix, int prefix_length) { | 735 int prefix, int prefix_length) { |
883 const int kFillerByteCount = 15; | 736 const int kFillerByteCount = NACL_ENUM_MAX_INSTRUCTION_BYTES; |
884 const int kInstByteCount = 15; | 737 const int kInstByteCount = NACL_ENUM_MAX_INSTRUCTION_BYTES; |
885 const int kIterByteCount = 3; | 738 const int kIterByteCount = 3; |
886 uint8_t itext[kBufferSize]; | 739 InstByteArray itext; |
887 int i, op, modrm, sib; | 740 int i, op, modrm, sib; |
888 int min_op; | 741 int min_op; |
889 int max_op; | 742 int max_op; |
890 | 743 |
891 if ((gPrefix >= 0) && (gPrefix != prefix)) return; | 744 if ((gPrefix >= 0) && (gPrefix != prefix)) return; |
892 | 745 |
893 if (!gSilent) printf("TestAllWithPrefix(%x)\n", prefix); | 746 PrintProgress("TestAllWithPrefix(%x)\n", prefix); |
894 /* set up prefix */ | 747 /* set up prefix */ |
895 memcpy(itext, &prefix, prefix_length); | 748 memcpy(itext, &prefix, prefix_length); |
896 /* set up filler bytes */ | 749 /* set up filler bytes */ |
897 for (i = 0; i < kFillerByteCount; i++) { | 750 for (i = 0; i < kFillerByteCount; i++) { |
898 itext[i + prefix_length + kIterByteCount] = (uint8_t)i; | 751 itext[i + prefix_length + kIterByteCount] = (uint8_t)i; |
899 } | 752 } |
900 if (gOpcode < 0) { | 753 if (gOpcode < 0) { |
901 min_op = 0; | 754 min_op = 0; |
902 max_op = 256; | 755 max_op = 256; |
903 } else { | 756 } else { |
904 min_op = gOpcode; | 757 min_op = gOpcode; |
905 max_op = gOpcode + 1; | 758 max_op = gOpcode + 1; |
906 } | 759 } |
907 for (op = min_op; op < max_op; op++) { | 760 for (op = min_op; op < max_op; op++) { |
908 itext[prefix_length] = op; | 761 itext[prefix_length] = op; |
909 ResetSkipCounts(NULL); | 762 ResetSkipCounts(NULL); |
910 if (!gSilent) printf("%02x 00 00\n", op); | 763 PrintProgress("%02x 00 00\n", op); |
911 for (modrm = 0; modrm < 256; modrm++) { | 764 for (modrm = 0; modrm < 256; modrm++) { |
912 itext[prefix_length + 1] = modrm; | 765 itext[prefix_length + 1] = modrm; |
913 for (sib = 0; sib < 256; sib++) { | 766 for (sib = 0; sib < 256; sib++) { |
914 itext[prefix_length + 2] = sib; | 767 itext[prefix_length + 2] = sib; |
915 TryOneInstruction(cinst, itext, kInstByteCount); | 768 TryOneInstruction(cinst, itext, kInstByteCount); |
916 /* If all decoders decode without using the sib byte, don't | 769 /* If all decoders decode without using the sib byte, don't |
917 * bother to try more variants. | 770 * bother to try more variants. |
918 */ | 771 */ |
919 if (IsLegalInstShorterThan(cinst, prefix_length + 3)) break; | 772 if (IsLegalInstShorterThan(cinst, prefix_length + 3)) break; |
920 } | 773 } |
(...skipping 24 matching lines...) Expand all Loading... |
945 TestAllWithPrefix(cinst, 0x0ff3, 2); | 798 TestAllWithPrefix(cinst, 0x0ff3, 2); |
946 TestAllWithPrefix(cinst, 0x0f66, 2); | 799 TestAllWithPrefix(cinst, 0x0f66, 2); |
947 TestAllWithPrefix(cinst, 0x0f0f, 2); | 800 TestAllWithPrefix(cinst, 0x0f0f, 2); |
948 TestAllWithPrefix(cinst, 0x380f, 2); | 801 TestAllWithPrefix(cinst, 0x380f, 2); |
949 TestAllWithPrefix(cinst, 0x3a0f, 2); | 802 TestAllWithPrefix(cinst, 0x3a0f, 2); |
950 TestAllWithPrefix(cinst, 0x380f66, 3); | 803 TestAllWithPrefix(cinst, 0x380f66, 3); |
951 TestAllWithPrefix(cinst, 0x380ff2, 3); | 804 TestAllWithPrefix(cinst, 0x380ff2, 3); |
952 TestAllWithPrefix(cinst, 0x3a0f66, 3); | 805 TestAllWithPrefix(cinst, 0x3a0f66, 3); |
953 } | 806 } |
954 | 807 |
| 808 /* Enumerate and test each instruction on stdin. */ |
| 809 static void TestInputInstructions(ComparedInstruction *cinst) { |
| 810 int i; |
| 811 InstByteArray itext; |
| 812 int num_bytes = 0; |
| 813 while (TRUE) { |
| 814 num_bytes = ReadAnInstruction(itext); |
| 815 if (num_bytes == 0) return; |
| 816 for (i = num_bytes; i < NACL_ENUM_MAX_INSTRUCTION_BYTES; ++i) { |
| 817 itext[i] = (uint8_t) i; |
| 818 } |
| 819 TryOneInstruction(cinst, itext, NACL_ENUM_MAX_INSTRUCTION_BYTES); |
| 820 } |
| 821 } |
| 822 |
955 /* Used to test one instruction at a time, for example, in regression | 823 /* Used to test one instruction at a time, for example, in regression |
956 * testing, or for instruction arguments from the command line. | 824 * testing, or for instruction arguments from the command line. |
957 */ | 825 */ |
958 static void TestOneInstruction(ComparedInstruction *cinst, char *asciihex) { | 826 static void TestOneInstruction(ComparedInstruction *cinst, char *asciihex) { |
959 uint8_t ibytes[NACL_ENUM_MAX_INSTRUCTION_BYTES]; | 827 InstByteArray ibytes; |
960 int nbytes; | 828 int nbytes; |
961 | 829 |
962 nbytes = Text2Bytes(ibytes, asciihex, "Command-line argument", -1); | 830 nbytes = Text2Bytes(ibytes, asciihex, "Command-line argument", -1); |
963 if (nbytes == 0) return; | 831 if (nbytes == 0) return; |
964 if (gVerbose) { | 832 if (gVerbose) { |
965 int i; | 833 int i; |
966 printf("trying %s (", asciihex); | 834 printf("trying %s (", asciihex); |
967 for (i = 0; i < nbytes; ++i) { | 835 for (i = 0; i < nbytes; ++i) { |
968 printf("%02x", ibytes[i]); | 836 printf("%02x", ibytes[i]); |
969 } | 837 } |
(...skipping 22 matching lines...) Expand all Loading... |
992 TestOneInstruction(cinst, "e9a0ffffff"); | 860 TestOneInstruction(cinst, "e9a0ffffff"); |
993 TestOneInstruction(cinst, "4883ec08"); | 861 TestOneInstruction(cinst, "4883ec08"); |
994 TestOneInstruction(cinst, "0f00040500112233445566778899aa"); | 862 TestOneInstruction(cinst, "0f00040500112233445566778899aa"); |
995 /* Below are newly discovered mistakes in call instructions, where the wrong | 863 /* Below are newly discovered mistakes in call instructions, where the wrong |
996 * byte length was required by x86-64 nacl validator. | 864 * byte length was required by x86-64 nacl validator. |
997 */ | 865 */ |
998 TestOneInstruction(cinst, "262e7e00"); | 866 TestOneInstruction(cinst, "262e7e00"); |
999 TestOneInstruction(cinst, "2e3e7900"); | 867 TestOneInstruction(cinst, "2e3e7900"); |
1000 } | 868 } |
1001 | 869 |
| 870 /* Returns the decoder with the given name, if it is registered. Otherwise, |
| 871 * returns NULL. |
| 872 */ |
| 873 static NaClEnumeratorDecoder* |
| 874 NaClGetRegisteredDecoder(ComparedInstruction* cinst, |
| 875 const char* decoder_name) { |
| 876 size_t i; |
| 877 for (i = 0; i < cinst->_enumerator._num_decoders; ++i) { |
| 878 if (0 == strcmp(cinst->_enumerator._decoder[i]->_id_name, decoder_name)) { |
| 879 return cinst->_enumerator._decoder[i]; |
| 880 } |
| 881 } |
| 882 return NULL; |
| 883 } |
| 884 |
1002 /* Register the decoder with the given name, returning the corresponding | 885 /* Register the decoder with the given name, returning the corresponding |
1003 * decoder. | 886 * decoder. |
1004 */ | 887 */ |
1005 static NaClEnumeratorDecoder* | 888 static NaClEnumeratorDecoder* |
1006 NaClRegisterEnumeratorDecoder(ComparedInstruction* cinst, | 889 NaClRegisterEnumeratorDecoder(ComparedInstruction* cinst, |
1007 const char* decoder_name) { | 890 const char* decoder_name) { |
| 891 size_t i; |
1008 /* First check if already registered. If so, simply return it. */ | 892 /* First check if already registered. If so, simply return it. */ |
1009 size_t i; | 893 NaClEnumeratorDecoder* decoder = |
1010 for (i = 0; i < cinst->_enumerator._num_decoders; ++i) { | 894 NaClGetRegisteredDecoder(cinst, decoder_name); |
1011 if (0 == strcmp(cinst->_enumerator._decoder[i]->_id_name, decoder_name)) { | 895 if (NULL != decoder) return decoder; |
1012 return cinst->_enumerator._decoder[i]; | |
1013 } | |
1014 } | |
1015 | 896 |
1016 /* If reached, not registered yet. See if one with the given name | 897 /* If reached, not registered yet. See if one with the given name |
1017 * is available (i.e. preregistered). | 898 * is available (i.e. preregistered). |
1018 */ | 899 */ |
1019 for (i = 0; i < kNumAvailableDecoders; ++i) { | 900 for (i = 0; i < kNumAvailableDecoders; ++i) { |
1020 NaClEnumeratorDecoder* decoder = kAvailableDecoders[i]; | 901 decoder = kAvailableDecoders[i]; |
1021 if (0 == strcmp(decoder->_id_name, decoder_name)) { | 902 if (0 == strcmp(decoder->_id_name, decoder_name)) { |
1022 if (cinst->_enumerator._num_decoders < NACL_MAX_ENUM_DECODERS) { | 903 if (cinst->_enumerator._num_decoders < NACL_MAX_ENUM_DECODERS) { |
1023 cinst->_enumerator._decoder[cinst->_enumerator._num_decoders++] = | 904 cinst->_enumerator._decoder[cinst->_enumerator._num_decoders++] = |
1024 decoder; | 905 decoder; |
1025 return decoder; | 906 return decoder; |
1026 } | 907 } |
1027 } | 908 } |
1028 } | 909 } |
1029 | 910 |
1030 /* If reached, can't find a decoder with the given name, abort. */ | 911 /* If reached, can't find a decoder with the given name, abort. */ |
1031 printf("Can't find decoder '%s', aborting!\n", decoder_name); | 912 fprintf(stderr, "Can't find decoder '%s', aborting!\n", decoder_name); |
1032 exit(1); | 913 exit(1); |
1033 } | 914 } |
1034 | 915 |
1035 /* Install legal filter values for corresponding available decoders. */ | 916 /* Install legal filter values for corresponding available decoders. */ |
1036 static void NaClInstallLegalFilter(ComparedInstruction* cinst, | 917 static void NaClInstallLegalFilter(ComparedInstruction* cinst, |
1037 const char* decoder_name, | 918 const char* decoder_name, |
1038 Bool new_value) { | 919 Bool new_value) { |
1039 NaClRegisterEnumeratorDecoder(cinst, decoder_name)->_legal_only = new_value; | 920 NaClRegisterEnumeratorDecoder(cinst, decoder_name)->_legal_only = new_value; |
1040 } | 921 } |
1041 | 922 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1101 } | 982 } |
1102 | 983 |
1103 /* Reads the bytes defined in line, and coverts it to the corresponding | 984 /* Reads the bytes defined in line, and coverts it to the corresponding |
1104 * ignored instruction. Then adds it to the list of ignored instructions. | 985 * ignored instruction. Then adds it to the list of ignored instructions. |
1105 */ | 986 */ |
1106 static void ReadInstListInst(InstList* list, | 987 static void ReadInstListInst(InstList* list, |
1107 char line[kBufferSize], | 988 char line[kBufferSize], |
1108 const char* context, | 989 const char* context, |
1109 int line_number) { | 990 int line_number) { |
1110 int i; | 991 int i; |
1111 uint8_t ibytes[NACL_ENUM_MAX_INSTRUCTION_BYTES]; | 992 InstByteArray ibytes; |
1112 int num_bytes = Text2Bytes(ibytes, line, context, line_number); | 993 int num_bytes = Text2Bytes(ibytes, line, context, line_number); |
1113 | 994 |
1114 /* Ignore line if no opcode sequence. */ | 995 /* Ignore line if no opcode sequence. */ |
1115 if (num_bytes == 0) return; | 996 if (num_bytes == 0) return; |
1116 | 997 |
1117 /* First update the instruction pointers. */ | 998 /* First update the instruction pointers. */ |
1118 if (list->num_insts_ == list->insts_size_) { | 999 if (list->num_insts_ == list->insts_size_) { |
1119 ExpandInstListInsts(list); | 1000 ExpandInstListInsts(list); |
1120 } | 1001 } |
1121 ++list->num_insts_; | 1002 ++list->num_insts_; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1169 } | 1050 } |
1170 | 1051 |
1171 /* Very simple command line arg parsing. Returns index to the first | 1052 /* Very simple command line arg parsing. Returns index to the first |
1172 * arg that doesn't begin with '--', or argc if there are none. | 1053 * arg that doesn't begin with '--', or argc if there are none. |
1173 */ | 1054 */ |
1174 static int ParseArgs(ComparedInstruction* cinst, int argc, char *argv[]) { | 1055 static int ParseArgs(ComparedInstruction* cinst, int argc, char *argv[]) { |
1175 int i; | 1056 int i; |
1176 uint32_t prefix; | 1057 uint32_t prefix; |
1177 uint32_t opcode; | 1058 uint32_t opcode; |
1178 char* cstr_value; | 1059 char* cstr_value; |
| 1060 int opcode_bytes_count = 0; |
1179 | 1061 |
1180 for (i = 1; i < argc; i++) { | 1062 for (i = 1; i < argc; i++) { |
1181 if (argv[i][0] == '-') { | 1063 if (argv[i][0] == '-') { |
1182 do { | 1064 do { |
1183 if (strcmp(argv[i], "--help") == 0) { | 1065 if (strcmp(argv[i], "--help") == 0) { |
1184 Usage(); | 1066 Usage(); |
1185 } else if (GrokBoolFlag("--checkoperands", argv[i], &gCheckOperands) || | 1067 } else if (GrokBoolFlag("--checkoperands", argv[i], &gCheckOperands) || |
1186 GrokBoolFlag("--nacllegal", argv[i], | 1068 GrokBoolFlag("--nacllegal", argv[i], |
1187 &gNaClLegal) || | 1069 &gNaClLegal) || |
1188 GrokBoolFlag("--xedimplemented", argv[i], | 1070 GrokBoolFlag("--xedimplemented", argv[i], |
1189 &gXedImplemented) || | 1071 &gXedImplemented) || |
1190 GrokBoolFlag("--nops", argv[i], &gNoCompareNops)|| | 1072 GrokBoolFlag("--nops", argv[i], &gNoCompareNops)|| |
1191 GrokBoolFlag("--opcode_bytes", argv[i], | |
1192 &cinst->_enumerator._print_opcode_bytes_only) || | |
1193 GrokBoolFlag("--printenum", argv[i], | |
1194 &cinst->_enumerator. | |
1195 _print_enumerated_instruction) || | |
1196 GrokBoolFlag("--skipcontiguous", argv[i], | 1073 GrokBoolFlag("--skipcontiguous", argv[i], |
1197 &gSkipContiguous) || | 1074 &gSkipContiguous) || |
1198 GrokBoolFlag("--verbose", argv[i], &gVerbose)) { | 1075 GrokBoolFlag("--verbose", argv[i], &gVerbose)) { |
| 1076 } else if (GrokCstringFlag("--opcode_bytes", argv[i], &cstr_value)) { |
| 1077 NaClRegisterEnumeratorDecoder(cinst, cstr_value) |
| 1078 ->_print_opcode_sequence = TRUE; |
| 1079 gSilent = TRUE; |
| 1080 ++opcode_bytes_count; |
| 1081 } else if (GrokCstringFlag("--opcode_bytes_plus_desc", |
| 1082 argv[i], &cstr_value)) { |
| 1083 NaClEnumeratorDecoder* decoder = |
| 1084 NaClRegisterEnumeratorDecoder(cinst, cstr_value); |
| 1085 decoder->_print_opcode_sequence_plus_desc = TRUE; |
| 1086 if ((NULL == decoder->_get_inst_mnemonic_fn) || |
| 1087 (NULL == decoder->_get_inst_operands_text_fn)) { |
| 1088 fprintf(stderr, "%s doesn't define how to print out description\n", |
| 1089 argv[i]); |
| 1090 } |
| 1091 gSilent = TRUE; |
| 1092 ++opcode_bytes_count; |
| 1093 /* Print out a special message to be picked up by the input decoder, |
| 1094 * so that it will look for instruction mnemonic and operands. |
| 1095 */ |
| 1096 printf("#OPCODEPLUSDESC#\n"); |
1199 } else if (GrokCstringFlag("--ignored", argv[i], &cstr_value)) { | 1097 } else if (GrokCstringFlag("--ignored", argv[i], &cstr_value)) { |
1200 ReadInstList(&kIgnoredInstructions, cstr_value); | 1098 ReadInstList(&kIgnoredInstructions, cstr_value); |
1201 } else if (GrokCstringFlag("--ignore_mnemonic", argv[i], &cstr_value)) { | 1099 } else if (GrokCstringFlag("--ignore_mnemonic", argv[i], &cstr_value)) { |
1202 ReadInstList(&kIgnoreMnemonics, cstr_value); | 1100 ReadInstList(&kIgnoreMnemonics, cstr_value); |
1203 } else if (GrokCstringFlag("--print", argv[i], &cstr_value)) { | 1101 } else if (GrokCstringFlag("--print", argv[i], &cstr_value)) { |
1204 NaClRegisterEnumeratorDecoder(cinst, cstr_value)->_print_only = TRUE; | 1102 NaClRegisterEnumeratorDecoder(cinst, cstr_value)->_print = TRUE; |
| 1103 gSilent = TRUE; |
1205 } else if (GrokUint32HexFlag("--prefix", argv[i], &prefix)) { | 1104 } else if (GrokUint32HexFlag("--prefix", argv[i], &prefix)) { |
1206 gPrefix = (int) prefix; | 1105 gPrefix = (int) prefix; |
1207 printf("using prefix %x\n", gPrefix); | 1106 printf("using prefix %x\n", gPrefix); |
1208 } else if (GrokUint32HexFlag("--opcode", argv[i], &opcode) && | 1107 } else if (GrokUint32HexFlag("--opcode", argv[i], &opcode) && |
1209 opcode < 256) { | 1108 opcode < 256) { |
1210 gOpcode = (int) opcode; | 1109 gOpcode = (int) opcode; |
1211 printf("using opcode %x\n", gOpcode); | 1110 printf("using opcode %x\n", gOpcode); |
1212 } else if (GrokCstringFlag("--legal", argv[i], &cstr_value)) { | 1111 } else if (GrokCstringFlag("--legal", argv[i], &cstr_value)) { |
1213 NaClInstallLegalFilter(cinst, cstr_value, TRUE); | 1112 NaClInstallLegalFilter(cinst, cstr_value, TRUE); |
1214 } else if (GrokCstringFlag("--illegal", argv[i], &cstr_value)) { | 1113 } else if (GrokCstringFlag("--illegal", argv[i], &cstr_value)) { |
1215 NaClInstallLegalFilter(cinst, cstr_value, FALSE); | 1114 NaClInstallLegalFilter(cinst, cstr_value, FALSE); |
1216 } else if (argv[i] == strfind(argv[i], "--")) { | 1115 } else if (argv[i] == strfind(argv[i], "--")) { |
1217 NaClRegisterEnumeratorDecoder(cinst, argv[i] + 2); | 1116 NaClRegisterEnumeratorDecoder(cinst, argv[i] + 2); |
1218 } else { | 1117 } else { |
1219 fprintf(stderr, "Can't recognize option %s\n", argv[i]); | 1118 fprintf(stderr, "Can't recognize option %s\n", argv[i]); |
1220 exit(1); | 1119 exit(1); |
1221 } | 1120 } |
| 1121 if (opcode_bytes_count > 1) { |
| 1122 fprintf(stderr, "Can't have more than one opcode_bytes command " |
| 1123 "line argument\n"); |
| 1124 exit(1); |
| 1125 } |
1222 } while (0); | 1126 } while (0); |
1223 } else return i; | 1127 } else return i; |
1224 } | 1128 } |
1225 return argc; | 1129 return argc; |
1226 } | 1130 } |
1227 | 1131 |
1228 /* Define set of available enumerator decoders. */ | 1132 /* Define set of available enumerator decoders. */ |
1229 static void NaClPreregisterEnumeratorDecoder(ComparedInstruction* cinst, | 1133 static void NaClPreregisterEnumeratorDecoder(ComparedInstruction* cinst, |
1230 NaClEnumeratorDecoder* decoder) { | 1134 NaClEnumeratorDecoder* decoder) { |
1231 if (kNumAvailableDecoders >= NACL_MAX_AVAILABLE_DECODERS) { | 1135 if (kNumAvailableDecoders >= NACL_MAX_AVAILABLE_DECODERS) { |
1232 printf("Too many preregistered enumerator decoders\n"); | 1136 fprintf(stderr, "Too many preregistered enumerator decoders\n"); |
1233 exit(1); | 1137 exit(1); |
1234 } | 1138 } |
| 1139 decoder->_legal_only = TRUE; |
| 1140 decoder->_print = FALSE; |
| 1141 decoder->_print_opcode_sequence = FALSE; |
| 1142 decoder->_print_opcode_sequence_plus_desc = FALSE; |
1235 kAvailableDecoders[kNumAvailableDecoders++] = decoder; | 1143 kAvailableDecoders[kNumAvailableDecoders++] = decoder; |
1236 } | 1144 } |
1237 | 1145 |
1238 /* Define decoders that can be registered. */ | 1146 /* Define decoders that can be registered. */ |
1239 extern NaClEnumeratorDecoder* RegisterXedDecoder(); | 1147 extern NaClEnumeratorDecoder* RegisterXedDecoder(); |
1240 extern NaClEnumeratorDecoder* RegisterNaClDecoder(); | 1148 extern NaClEnumeratorDecoder* RegisterNaClDecoder(); |
1241 | 1149 |
1242 /* Initialize the set of available decoders. */ | 1150 /* Initialize the set of available decoders. */ |
1243 static void NaClInitializeAvailableDecoders() { | 1151 static void NaClInitializeAvailableDecoders() { |
1244 kNumAvailableDecoders = 0; | 1152 kNumAvailableDecoders = 0; |
1245 #ifdef NACL_XED_DECODER | 1153 #ifdef NACL_XED_DECODER |
1246 NaClPreregisterEnumeratorDecoder(&gCinst, RegisterXedDecoder()); | 1154 NaClPreregisterEnumeratorDecoder(&gCinst, RegisterXedDecoder()); |
1247 #endif | 1155 #endif |
1248 NaClPreregisterEnumeratorDecoder(&gCinst, RegisterNaClDecoder()); | 1156 NaClPreregisterEnumeratorDecoder(&gCinst, RegisterNaClDecoder()); |
| 1157 NaClPreregisterEnumeratorDecoder(&gCinst, RegisterInputDecoder()); |
1249 } | 1158 } |
1250 | 1159 |
1251 /* Initialize the ComparedInstruction data structure. */ | 1160 /* Initialize the ComparedInstruction data structure. */ |
1252 static void NaClInitializeComparedInstruction(ComparedInstruction* cinst) { | 1161 static void NaClInitializeComparedInstruction(ComparedInstruction* cinst) { |
1253 cinst->_enumerator._num_decoders = 0; | 1162 cinst->_enumerator._num_decoders = 0; |
1254 cinst->_enumerator._print_opcode_bytes_only = FALSE; | |
1255 cinst->_enumerator._print_enumerated_instruction = FALSE; | |
1256 } | 1163 } |
1257 | 1164 |
1258 | |
1259 /* Install parsed globals, as appropriate into the corresponding | 1165 /* Install parsed globals, as appropriate into the corresponding |
1260 * decoders. | 1166 * decoders. |
1261 */ | 1167 */ |
1262 static void InstallFlags(NaClEnumerator* enumerator) { | 1168 static void InstallFlags(NaClEnumerator* enumerator) { |
1263 size_t i; | 1169 size_t i; |
1264 for (i = 0; i < enumerator->_num_decoders; ++i) { | 1170 for (i = 0; i < enumerator->_num_decoders; ++i) { |
1265 enumerator->_decoder[i]->_install_flag_fn(enumerator, | 1171 enumerator->_decoder[i]->_install_flag_fn(enumerator, |
1266 "--nops", | 1172 "--nops", |
1267 &gNoCompareNops); | 1173 &gNoCompareNops); |
1268 enumerator->_decoder[i]->_install_flag_fn(enumerator, | 1174 enumerator->_decoder[i]->_install_flag_fn(enumerator, |
1269 "--xedimplemented", | 1175 "--xedimplemented", |
1270 &gXedImplemented); | 1176 &gXedImplemented); |
1271 } | 1177 } |
1272 if (enumerator->_print_opcode_bytes_only || | |
1273 enumerator->_print_enumerated_instruction) { | |
1274 gSilent = TRUE; | |
1275 } | |
1276 } | 1178 } |
1277 | 1179 |
1278 int main(int argc, char *argv[]) { | 1180 int main(int argc, char *argv[]) { |
1279 int testargs; | 1181 int testargs; |
1280 | 1182 |
1281 NaClLogModuleInit(); | 1183 NaClLogModuleInit(); |
1282 NaClLogSetVerbosity(LOG_FATAL); | 1184 NaClLogSetVerbosity(LOG_FATAL); |
1283 NaClInitializeAvailableDecoders(); | 1185 NaClInitializeAvailableDecoders(); |
1284 NaClInitializeComparedInstruction(&gCinst); | 1186 NaClInitializeComparedInstruction(&gCinst); |
1285 | 1187 |
1286 gArgv0 = argv[0]; | 1188 gArgv0 = argv[0]; |
1287 if (argc == 1) Usage(); | 1189 if (argc == 1) Usage(); |
1288 | 1190 |
1289 testargs = ParseArgs(&gCinst, argc, argv); | 1191 testargs = ParseArgs(&gCinst, argc, argv); |
1290 InstallFlags(&gCinst._enumerator); | 1192 InstallFlags(&gCinst._enumerator); |
1291 | 1193 |
1292 | 1194 |
1293 if (gCinst._enumerator._num_decoders == 0) { | 1195 if (gCinst._enumerator._num_decoders == 0) { |
1294 fprintf(stderr, "No decoder specified, can't continue\n"); | 1196 fprintf(stderr, "No decoder specified, can't continue\n"); |
1295 exit(1); | 1197 exit(1); |
1296 } | 1198 } |
1297 | 1199 |
1298 if (testargs == argc) { | 1200 if (testargs == argc) { |
1299 if (gPrefix < 0) RunRegressionTests(&gCinst); | 1201 if (NULL == NaClGetRegisteredDecoder(&gCinst, "in")) { |
1300 TestAllInstructions(&gCinst); | 1202 if (gPrefix < 0) RunRegressionTests(&gCinst); |
| 1203 TestAllInstructions(&gCinst); |
| 1204 } else { |
| 1205 TestInputInstructions(&gCinst); |
| 1206 } |
1301 } else { | 1207 } else { |
1302 int i; | 1208 int i; |
1303 gSilent = FALSE; | |
1304 gVerbose = TRUE; | 1209 gVerbose = TRUE; |
1305 for (i = testargs; i < argc; ++i) { | 1210 for (i = testargs; i < argc; ++i) { |
1306 TestOneInstruction(&gCinst, argv[i]); | 1211 TestOneInstruction(&gCinst, argv[i]); |
1307 } | 1212 } |
1308 } | 1213 } |
1309 exit(gSawLethalError); | 1214 exit(gSawLethalError); |
1310 } | 1215 } |
OLD | NEW |