Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: src/trusted/validator/x86/testing/enuminsts/enuminsts.c

Issue 9861030: Modify enuminsts to be able to communicate matched instructions accross (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client/
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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 uint8_t itext[NACL_ENUM_MAX_INSTRUCTION_BYTES];
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
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 uint8_t itext[NACL_ENUM_MAX_INSTRUCTION_BYTES];
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 uint8_t ibytes[NACL_ENUM_MAX_INSTRUCTION_BYTES];
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) {
(...skipping 27 matching lines...) Expand all
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 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698