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

Side by Side Diff: src/trusted/validator/x86/testing/enuminsts/text2hex.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, 8 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 /*
8 * exhaustive instruction enumeration test for x86 Native Client decoder. 8 * Hexidecimal text to bytes conversion tools.
9 */ 9 */
10 10
11 /* TODO(karl) - Fix the calls to the decoder for x86-32 to use the same decoder 11 #include "native_client/src/trusted/validator/x86/testing/enuminsts/text2hex.h"
12 * as the x86-32 validator, and document how to properly test the
13 * x86-32 decoder.
14 */
15 12
16 #include "native_client/src/trusted/validator/x86/testing/enuminsts/enuminsts.h" 13 #include <stdio.h>
17 14
18 #include <ctype.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22
23 #include "native_client/src/shared/platform/nacl_log.h"
24 #include "native_client/src/trusted/validator/x86/testing/enuminsts/str_utils.h"
25
26 /* When non-zero, prints out additional debugging messages. */
27 #define kDebug 0
28
29 /* Defines the maximum buffer size used to hold text generated for the
30 * disassembly of instructions, and corresponding error messages.
31 */
32 #define kBufferSize 1024 15 #define kBufferSize 1024
33 16
34 /* When true, print more messages (i.e. verbosely). */
35 static Bool gVerbose = FALSE;
36
37 /* When true, don't print out messages. That is, only print instructions
38 * defined by --print directives.
39 */
40 static Bool gSilent = FALSE;
41
42 /* When true, don't report consecutive errors for consecutive instructions
43 * with the same instruction mnemonic.
44 */
45 static Bool gSkipRepeatReports = FALSE;
46
47 /* When true, check for operand differences when processing each instruction. */
48 static Bool gCheckOperands = FALSE;
49
50 /* Count of errors that have a high certainty of being exploitable. */
51 static int gSawLethalError = 0;
52
53 /* Defines the assumed text address for the test instruction */
54 const int kTextAddress = 0x1000;
55
56 /* If non-negative, defines the prefix to test. */
57 static int gPrefix = -1;
58
59 /* If non-negative, defines the opcode to test. */
60 static int gOpcode = -1;
61
62 /* If true, check if nacl instruction is NACL legal. */
63 static Bool gNaClLegal = FALSE;
64
65 /* If true, check if nacl instruction is also implemented in xed. */
66 static Bool gXedImplemented = FALSE;
67
68 /* If true, don't bother to do operand compares for nop's. */
69 static Bool gNoCompareNops = FALSE;
70
71 /* If true, only skip contiguous errors. */
72 static Bool gSkipContiguous = FALSE;
73
74 static const char* target_machine = "x86-"
75 #if NACL_TARGET_SUBARCH == 64
76 "64"
77 #else
78 "32"
79 #endif
80 ;
81
82 /* Defines maximum number of available decoders (See comments on
83 * struct NaClEnumeratorDecoder in enuminst.h for details on what
84 * a decoder is.
85 */
86 #define NACL_MAX_AVAILABLE_DECODERS 10
87
88 /* Holds the set of available decoders. */
89 NaClEnumeratorDecoder* kAvailableDecoders[NACL_MAX_AVAILABLE_DECODERS];
90
91 /* Holds the number of (pre)registered available decoders. */
92 size_t kNumAvailableDecoders;
93
94 /* This struct holds a list of instruction opcode sequences that we
95 * want to treat specially. Used to filter out problem cases from
96 * the enumeration.
97 */
98 typedef struct {
99 /* Pointer to array of bytes for the instruction. */
100 uint8_t* bytes_;
101 /* The size of bytes_. */
102 size_t bytes_size_;
103 /* Pointer to array of instructions. Each element is
104 * the index into bytes_ where the corresponding byte sequence
105 * of the instruction begins. The next element in the array is
106 * the end point for the current instruction.
107 */
108 size_t* insts_;
109 /* The size of insts_. */
110 size_t insts_size_;
111 /* Number of instructions stored in insts_. */
112 size_t num_insts_;
113 /* Number of bytes stored in bytes_. */
114 size_t num_bytes_;
115 } InstList;
116
117 /* This struct holds state concerning an instruction, both from the
118 * various available decoders. Some of the state information is
119 * redundant, preserved to avoid having to recompute it.
120 */
121 typedef struct {
122 /* Holds the set of decoders to enumerate over. */
123 NaClEnumerator _enumerator;
124 /* True if a decoder or comparison failed due to an error with
125 * the way the instruction was decoded.
126 */
127 Bool _decoder_error;
128 } ComparedInstruction;
129
130 /* The state to use to compare instructions. */
131 static ComparedInstruction gCinst;
132
133 /* The name of the executable (i.e. argv[0] from the command line). */
134 static char *gArgv0 = "argv0";
135
136 /* Prints out summary of how to use this executable. and then exits. */
137 static void Usage() {
138 size_t i;
139 fprintf(stderr, "usage: %s [decoders] [options] [hexbytes ...]\n",
140 gArgv0);
141 fprintf(stderr, "\n");
142 fprintf(stderr, " Compare %s instruction decoders\n",
143 target_machine);
144 fprintf(stderr, "\n");
145 fprintf(stderr, " With no arguments, enumerate all %s instructions.\n",
146 target_machine);
147 fprintf(stderr, " With arguments, decode each sequence of "
148 "opcode bytes.\n");
149 fprintf(stderr, "\n");
150 fprintf(stderr, "Available decoders are (select using --name):\n");
151 fprintf(stderr, "\n");
152 for (i = 0; i < kNumAvailableDecoders; ++i) {
153 fprintf(stderr, " %s: %s\n",
154 kAvailableDecoders[i]->_id_name,
155 kAvailableDecoders[i]->_usage_message);
156 }
157 fprintf(stderr, "\n");
158 fprintf(stderr, "Options are:\n");
159 fprintf(stderr, " --checkoperands: enables operand comparison (slow)\n");
160 fprintf(stderr, " --ignore_mnemonic=file: ignore mnemonic name "
161 "comparison\n");
162 fprintf(stderr, " for instruction sequences in file (may be "
163 "repeated)\n");
164 fprintf(stderr, " --ignored=<file>: ignore instruction sequences "
165 "in file (may be repeated)\n");
166 fprintf(stderr, " --illegal=XX: Filter instructions to only consider "
167 "those instructions\n");
168 fprintf(stderr, " that are illegal instructions, as defined by "
169 "decoder XX\n");
170 fprintf(stderr, " --legal=XX: Filter instructions to only consider "
171 "those instructions\n");
172 fprintf(stderr, " that are legal instructions, as defined by "
173 "decoder XX\n");
174 fprintf(stderr, " --nacllegal: only compare NaCl legal instructions\n");
175 fprintf(stderr, " that are legal for nacl decoder(s).\n");
176 fprintf(stderr, " --print=XX: Prints out set of enumerated "
177 "instructions,\n");
178 fprintf(stderr, " for the specified decoder XX (may be "
179 "repeated).\n");
180 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");
185 fprintf(stderr, " --opcode=XX: only process given opcode for "
186 "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");
190 fprintf(stderr, " --skipcontiguous: Only skip contiguous errors\n");
191 fprintf(stderr, " --verbose: add verbose comments to output\n");
192 fprintf(stderr, " --xedimplemented: only compare NaCl instruction that "
193 "are also implemented in xed\n");
194 exit(gSawLethalError);
195 }
196
197 /* Records that unexpected internal error occurred. */
198 void InternalError(const char *why) {
199 fprintf(stderr, "%s: Internal Error: %s\n", gArgv0, why);
200 gSawLethalError = 1;
201 }
202
203 /* Records that a fatal (i.e. non-recoverable) error occurred. */
204 static void ReportFatalError(const char* why) {
205 char buffer[kBufferSize];
206 snprintf(buffer, kBufferSize, "%s - quitting!", why);
207 InternalError(buffer);
208 exit(1);
209 }
210
211 /* Returns true if the given opcode sequence text is in the
212 * given instruction list.
213 */
214 static Bool InInstructionList(InstList* list, uint8_t* itext, size_t nbytes) {
215 size_t i;
216 size_t j;
217 if (NULL == list) return FALSE;
218 for (i = 0; i < list->num_insts_; ++i) {
219 Bool found_match = TRUE;
220 size_t start = list->insts_[i];
221 size_t end = list->insts_[i + 1];
222 size_t inst_bytes = (end - start);
223 if (inst_bytes < nbytes) continue;
224 for (j = 0; j < inst_bytes; j++) {
225 if (itext[j] != list->bytes_[start + j]) {
226 found_match = FALSE;
227 break;
228 }
229 }
230 if (found_match) {
231 return TRUE;
232 }
233 }
234 return FALSE;
235 }
236
237 /* Takes the given text and sends it to each of the instruction
238 * decoders to decode the first instruction in the given text.
239 * Commonly the decoded instruction will be shorter than nbytes.
240 */
241 static void ParseFirstInstruction(ComparedInstruction *cinst,
242 uint8_t *itext, size_t nbytes) {
243 size_t i;
244 memcpy(cinst->_enumerator._itext, itext, nbytes);
245 cinst->_enumerator._num_bytes = nbytes;
246 cinst->_decoder_error = FALSE;
247 for (i = 0; i < cinst->_enumerator._num_decoders; ++i) {
248 cinst->_enumerator._decoder[i]->
249 _parse_inst_fn(&cinst->_enumerator, kTextAddress);
250 }
251 }
252
253 /* Prints out the instruction each decoder disassembled */
254 static void PrintDisassembledInstructionVariants(ComparedInstruction* cinst) {
255 size_t i;
256 for (i = 0; i < cinst->_enumerator._num_decoders; ++i) {
257 cinst->_enumerator._decoder[i]->_print_inst_fn(&cinst->_enumerator);
258 }
259 }
260
261 /* Print error message "why", and show instructions that failed for
262 * that reason.
263 */
264 static void CinstInternalError(ComparedInstruction* cinst, const char* why) {
265 PrintDisassembledInstructionVariants(cinst);
266 InternalError(why);
267 }
268
269 /* Initial value for last bad opcode. */
270 #define NOT_AN_OPCODE "not an opcode"
271
272 /* Holds the name of the last (bad) mnemonic name matched.
273 * Uses the mnemonic name associated with instructions decoded
274 * by the first decoder.
275 */
276 static char last_bad_mnemonic[kBufferSize] = NOT_AN_OPCODE;
277
278 /* Returns how many decoder errors were skipped for an opcode. */
279 static int nSkipped = 0;
280
281 /* Changes the last bad mnemonic name to the new value. */
282 static void ChangeLastBadMnemonic(const char* new_value) {
283 cstrncpy(last_bad_mnemonic, new_value, kBufferSize);
284 }
285
286 /* Reset the counters for skipping decoder errors, assuming
287 * the last_bad_opcode (if non-null) was the given value.
288 */
289 static void ResetSkipCounts(const char* last_opcode) {
290 nSkipped = 0;
291 ChangeLastBadMnemonic((last_opcode == NULL) ? "not an opcode" : last_opcode);
292 }
293
294 /* Report number of instructions with errors that were skipped, and
295 * then reset the skip counts.
296 */
297 static void ReportOnSkippedErrors(ComparedInstruction* cinst,
298 const char* mnemonic) {
299 if (nSkipped > 0 && gSilent) {
300 printf("...skipped %d errors for %s\n", nSkipped, last_bad_mnemonic);
301 }
302 ResetSkipCounts(mnemonic);
303 }
304
305 /* Report a disagreement between decoders. To reduce
306 * noice from uninteresting related errors, gSkipRepeatReports will
307 * avoid printing consecutive errors for the same opcode.
308 */
309 static void DecoderError(const char *why,
310 ComparedInstruction *cinst,
311 const char *details) {
312 size_t i;
313 cinst->_decoder_error = TRUE;
314
315 /* Don't print errors when running silently. In such cases we
316 * are generating valid opcode sequences for a decoder, and problems
317 * should be ignored.
318 */
319 if (gSilent) return;
320
321 /* Check if we have already reported for instruction mnemonic,
322 * based on the mnemonic used by the first decoder.
323 */
324 if (gSkipRepeatReports) {
325 /* Look for first possible name for instruction. */
326 for (i = 0; i < cinst->_enumerator._num_decoders; ++i) {
327 NaClEnumeratorDecoder *decoder = cinst->_enumerator._decoder[i];
328 if (NULL == decoder->_get_inst_mnemonic_fn) continue;
329 const char* mnemonic = cinst->_enumerator._decoder[0]->
330 _get_inst_mnemonic_fn(&cinst->_enumerator);
331 if (strcmp(mnemonic, last_bad_mnemonic) == 0) {
332 nSkipped += 1;
333 return;
334 }
335 }
336 }
337
338 /* If reached, did not skip, so report the error. */
339 printf("**** ERROR: %s: %s\n", why, (details == NULL ? "" : details));
340 PrintDisassembledInstructionVariants(cinst);
341 }
342
343 /* Returns the integer corresponding to a hex value in ASCII. This would 17 /* 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 18 * be faster as an array lookup, however since it's only used for command
345 * line input it doesn't matter. 19 * line input it doesn't matter.
346 */ 20 */
347 static unsigned int A2INibble(char nibble) { 21 static unsigned int A2INibble(const char nibble) {
348 switch (nibble) { 22 switch (nibble) {
349 case '0': return 0; 23 case '0': return 0;
350 case '1': return 1; 24 case '1': return 1;
351 case '2': return 2; 25 case '2': return 2;
352 case '3': return 3; 26 case '3': return 3;
353 case '4': return 4; 27 case '4': return 4;
354 case '5': return 5; 28 case '5': return 5;
355 case '6': return 6; 29 case '6': return 6;
356 case '7': return 7; 30 case '7': return 7;
357 case '8': return 8; 31 case '8': return 8;
(...skipping 12 matching lines...) Expand all
370 case 'F': return 0xF; 44 case 'F': return 0xF;
371 default: break; 45 default: break;
372 } 46 }
373 fprintf(stderr, "bad hex value %c", nibble); 47 fprintf(stderr, "bad hex value %c", nibble);
374 exit(1); 48 exit(1);
375 } 49 }
376 50
377 /* Convert a two-character string representing an byte value in hex 51 /* Convert a two-character string representing an byte value in hex
378 * into the corresponding byte value. 52 * into the corresponding byte value.
379 */ 53 */
380 static unsigned int A2IByte(char nibble1, char nibble2) { 54 static unsigned int A2IByte(const char nibble1, const char nibble2) {
381 return A2INibble(nibble2) + A2INibble(nibble1) * 0x10; 55 return A2INibble(nibble2) + A2INibble(nibble1) * 0x10;
382 } 56 }
383 57
384 /* Generates a buffer containing the context message to print. 58 /* Generates a buffer containing the context message to print.
385 * Arguments are: 59 * Arguments are:
386 * context - String describing the context (i.e. filename or 60 * context - String describing the context (i.e. filename or
387 * command line argument description). 61 * command line argument description).
388 * line - The line number associated with the context (if negative, 62 * line - The line number associated with the context (if negative,
389 * it assumes that the line number shouldn't be reported). 63 * it assumes that the line number shouldn't be reported).
390 */ 64 */
391 static const char* TextContext(const char* context, 65 static const char* TextContext(const char* context,
392 int line) { 66 const int line) {
393 if (line < 0) { 67 if (line < 0) {
394 return context; 68 return context;
395 } else { 69 } else {
396 static char buffer[kBufferSize]; 70 static char buffer[kBufferSize];
397 snprintf(buffer, kBufferSize, "%s line %d", context, line); 71 snprintf(buffer, kBufferSize, "%s line %d", context, line);
398 return buffer; 72 return buffer;
399 } 73 }
400 } 74 }
401 75
402 /* Installs byte into the byte buffer. Returns the new value for num_bytes. 76 /* Installs byte into the byte buffer. Returns the new value for num_bytes.
403 * Arguments are: 77 * Arguments are:
404 * ibytes - The found sequence of opcode bytes. 78 * ibytes - The found sequence of opcode bytes.
405 * num_bytes - The number of bytes currently in ibytes. 79 * num_bytes - The number of bytes currently in ibytes.
406 * mini_buf - The buffer containing the two hexidecimal characters to convert. 80 * mini_buf - The buffer containing the two hexidecimal characters to convert.
407 * context - String describing the context (i.e. filename or 81 * context - String describing the context (i.e. filename or
408 * command line argument description). 82 * command line argument description).
409 * line - The line number associated with the context (if negative, 83 * line - The line number associated with the context (if negative,
410 * it assumes that the line number shouldn't be reported). 84 * it assumes that the line number shouldn't be reported).
411 */ 85 */
412 static int InstallTextByte(uint8_t ibytes[NACL_ENUM_MAX_INSTRUCTION_BYTES], 86 static int InstallTextByte(InstByteArray ibytes,
413 int num_bytes, 87 int num_bytes,
414 char mini_buf[2], 88 const char mini_buf[2],
415 const char* itext, 89 const char* itext,
416 const char* context, 90 const char* context,
417 int line) { 91 const int line) {
418 if (num_bytes == NACL_ENUM_MAX_INSTRUCTION_BYTES) { 92 if (num_bytes == NACL_ENUM_MAX_INSTRUCTION_BYTES) {
419 char buffer[kBufferSize]; 93 char buffer[kBufferSize];
420 snprintf(buffer, kBufferSize, 94 snprintf(buffer, kBufferSize,
421 "%s: opcode sequence too long in '%s'", 95 "%s: opcode sequence too long in '%s'",
422 TextContext(context, line), itext); 96 TextContext(context, line), itext);
423 ReportFatalError(buffer); 97 ReportFatalError(buffer);
424 } 98 }
425 ibytes[num_bytes] = A2IByte(mini_buf[0], mini_buf[1]); 99 ibytes[num_bytes] = A2IByte(mini_buf[0], mini_buf[1]);
426 return num_bytes + 1; 100 return num_bytes + 1;
427 } 101 }
428 102
429 /* Reads a line of text defining the sequence of bytes that defines 103 /* Reads a line of text defining the sequence of bytes that defines
430 * an instruction, and converts that to the corresponding sequence of 104 * an instruction, and converts that to the corresponding sequence of
431 * opcode bytes. Returns the number of bytes found. Arguments are: 105 * opcode bytes. Returns the number of bytes found. Arguments are:
432 * ibytes - The found sequence of opcode bytes. 106 * ibytes - The found sequence of opcode bytes.
433 * itext - The sequence of bytes to convert. 107 * itext - The sequence of bytes to convert.
434 * context - String describing the context (i.e. filename or 108 * context - String describing the context (i.e. filename or
435 * command line argument description). 109 * command line argument description).
436 * line - The line number associated with the context (if negative, 110 * line - The line number associated with the context (if negative,
437 * it assumes that the line number shouldn't be reported). 111 * it assumes that the line number shouldn't be reported).
438 */ 112 */
439 static int Text2Bytes(uint8_t ibytes[NACL_ENUM_MAX_INSTRUCTION_BYTES], 113 int Text2Bytes(InstByteArray ibytes,
440 char* itext, 114 const char* itext,
441 const char* context, 115 const char* context,
442 int line) { 116 const int line) {
443 char mini_buf[2]; 117 char mini_buf[2];
444 size_t mini_buf_index; 118 size_t mini_buf_index;
445 char *next; 119 char *next;
446 char ch; 120 char ch;
447 int num_bytes = 0; 121 int num_bytes = 0;
448 Bool continue_translation = TRUE; 122 Bool continue_translation = TRUE;
449 123
450 /* Now process text of itext. */ 124 /* Now process text of itext. */
451 next = &itext[0]; 125 next = (char*) &itext[0];
452 mini_buf_index = 0; 126 mini_buf_index = 0;
453 while (continue_translation && (ch = *(next++))) { 127 while (continue_translation && (ch = *(next++))) {
454 switch (ch) { 128 switch (ch) {
455 case '#': 129 case '#':
456 /* Comment, skip reading any more characters. */ 130 /* Comment, skip reading any more characters. */
457 continue_translation = FALSE; 131 continue_translation = FALSE;
458 break; 132 break;
459 case '0': 133 case '0':
460 case '1': 134 case '1':
461 case '2': 135 case '2':
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 if (mini_buf_index > 0) { 193 if (mini_buf_index > 0) {
520 char buffer[kBufferSize]; 194 char buffer[kBufferSize];
521 snprintf(buffer, kBufferSize, 195 snprintf(buffer, kBufferSize,
522 "%s: Opcode sequence must be an even number of chars '%s'", 196 "%s: Opcode sequence must be an even number of chars '%s'",
523 TextContext(context, line), itext); 197 TextContext(context, line), itext);
524 ReportFatalError(buffer); 198 ReportFatalError(buffer);
525 } 199 }
526 200
527 return num_bytes; 201 return num_bytes;
528 } 202 }
529
530 #if NACL_TARGET_SUBARCH == 64
531
532 /* The instructions:
533 * 48 89 e5 mov rbp, rsp
534 * 4a 89 e5 mov rbp, rsp
535 * look bad based on the simple rule, but are safe because they are
536 * moving a safe address between two protected registers.
537 */
538 static int IsSpecialSafeRegWrite(ComparedInstruction *cinst) {
539 uint8_t byte0 = cinst->_enumerator._itext[0];
540 uint8_t byte1 = cinst->_enumerator._itext[1];
541 uint8_t byte2 = cinst->_enumerator._itext[2];
542
543 return ((byte0 == 0x48 && byte1 == 0x89 && byte2 == 0xe5) ||
544 (byte0 == 0x48 && byte1 == 0x89 && byte2 == 0xec) ||
545 (byte0 == 0x48 && byte1 == 0x8b && byte2 == 0xe5) ||
546 (byte0 == 0x48 && byte1 == 0x8b && byte2 == 0xec) ||
547 (byte0 == 0x4a && byte1 == 0x89 && byte2 == 0xe5) ||
548 (byte0 == 0x4a && byte1 == 0x89 && byte2 == 0xec) ||
549 (byte0 == 0x4a && byte1 == 0x8b && byte2 == 0xe5) ||
550 (byte0 == 0x4a && byte1 == 0x8b && byte2 == 0xec));
551 }
552
553 /* If we get this far, and Xed says it writes a NaCl reserved
554 * register, this is a lethal error.
555 */
556 static Bool BadRegWrite(ComparedInstruction *cinst) {
557 size_t i;
558 NaClEnumeratorDecoder* xed_decoder = NULL;
559 size_t noperands;
560 size_t ilength;
561
562 /* First see if there is a xed decoder to compare against. */
563 for (i = 0; i < cinst->_enumerator._num_decoders; ++i) {
564 if (0 == strcmp("xed", cinst->_enumerator._decoder[i]->_id_name)) {
565 xed_decoder = cinst->_enumerator._decoder[i];
566 break;
567 }
568 }
569
570 /* Quit if we don't have the right support for this function. */
571 if ((NULL == xed_decoder) ||
572 !xed_decoder->_is_inst_legal_fn(&cinst->_enumerator) ||
573 (NULL == xed_decoder->_get_inst_num_operands_fn) ||
574 (NULL == xed_decoder->_writes_to_reserved_reg_fn)) return 0;
575
576 /* If reached, we found the xed decoder. */
577 noperands = xed_decoder->_get_inst_num_operands_fn(&cinst->_enumerator);
578 ilength = xed_decoder->_inst_length_fn(&cinst->_enumerator);
579 for (i = 0; i < cinst->_enumerator._num_decoders; ++i) {
580 size_t j;
581 NaClEnumeratorDecoder* other_decoder = cinst->_enumerator._decoder[i];
582
583 /* don't compare against self. */
584 if (xed_decoder == other_decoder) break;
585
586 /* don't compare if the other decoder doesn't know how to validate. */
587 if (NULL == other_decoder->_segment_validates_fn) break;
588 if (!other_decoder->_is_inst_legal_fn(&cinst->_enumerator)) break;
589
590 for (j = 0; j < noperands ; j++) {
591 if (xed_decoder->_writes_to_reserved_reg_fn(&cinst->_enumerator, j)) {
592 if (other_decoder->_segment_validates_fn(&cinst->_enumerator,
593 cinst->_enumerator._itext,
594 ilength,
595 kTextAddress)) {
596 char sbuf[kBufferSize];
597 /* Report problem if other decoder accepted instruction, but is
598 * not one of the special safe writes.
599 */
600 if (!IsSpecialSafeRegWrite(cinst)) continue;
601 gSawLethalError = 1;
602 snprintf(sbuf, kBufferSize, "(%s) xed operand %d\n",
603 other_decoder->_id_name, (int) j);
604 DecoderError("ILLEGAL REGISTER WRITE", cinst, sbuf);
605 return TRUE;
606 }
607 }
608 }
609 }
610 return FALSE;
611 }
612 #endif
613
614 /* Compare operands of each decoder's disassembled instruction, reporting
615 * an error if decoders disagree.
616 */
617 static Bool AreInstOperandsEqual(ComparedInstruction *cinst) {
618 size_t i;
619 size_t num_decoders = 0;
620 const char* operands[NACL_MAX_ENUM_DECODERS];
621 NaClEnumeratorDecoder* operands_decoder[NACL_MAX_ENUM_DECODERS];
622 NaClEnumerator* enumerator = &cinst->_enumerator;
623
624 /* If no decoders, vacuously true. */
625 if (0 == enumerator->_num_decoders) return FALSE;
626
627 /* Collect operand lists and corresponding decoders. */
628 for (i = 0; i < enumerator->_num_decoders; ++i) {
629 /* Start by verifying that we can find operands. */
630 NaClEnumeratorDecoder *decoder = enumerator->_decoder[i];
631 if (NULL == decoder->_get_inst_operands_text_fn) continue;
632 if (!decoder->_is_inst_legal_fn(enumerator)) continue;
633
634 /* HACK ALERT! Special case "nops" by removing operands. We do this
635 * assuming it doesn't matter what the argumnents are, the effect is
636 * the same.
637 */
638 if (gNoCompareNops &&
639 (NULL != decoder->_get_inst_mnemonic_fn) &&
640 (0 == strcmp("nop", decoder->_get_inst_mnemonic_fn(enumerator)))) {
641 operands[num_decoders] = "";
642 operands_decoder[num_decoders++] = decoder;
643 continue;
644 }
645
646 /* Not special case, record operand and decoder. */
647 operands[num_decoders] = decoder->_get_inst_operands_text_fn(enumerator);
648 if (NULL == operands[num_decoders]) operands[num_decoders] = "";
649 operands_decoder[num_decoders++] = decoder;
650 }
651
652 /* Now test if operands compare between decoders. */
653 for (i = 1; i < num_decoders; ++i) {
654 if (0 != strncmp(operands[i-1], operands[i], kBufferSize)) {
655 char sbuf[kBufferSize];
656 snprintf(sbuf, kBufferSize, "(%s) '%s' != (%s)'%s'",
657 operands_decoder[i-1]->_id_name, operands[i-1],
658 operands_decoder[i]->_id_name, operands[i]);
659 DecoderError("OPERAND MISMATCH", cinst, sbuf);
660 return FALSE;
661 }
662 }
663
664 if (kDebug && (num_decoders > 0)) {
665 printf("operands match: %s\n", operands[0]);
666 }
667 return TRUE;
668 }
669
670 /* If non-null, the list of instructions for which mnemonics should
671 * not be compared.
672 */
673 static InstList* kIgnoreMnemonics = NULL;
674
675 /* Compares mnemonic names between decoder's disassembled instructions,
676 * returning true if they agree on the mnemonic name.
677 */
678 static Bool AreInstMnemonicsEqual(ComparedInstruction *cinst) {
679 size_t i;
680 size_t num_decoders = 0;
681 const char* name[NACL_MAX_ENUM_DECODERS];
682 NaClEnumeratorDecoder* name_decoder[NACL_MAX_ENUM_DECODERS];
683
684 /* If no decoders, vacuously true. */
685 if (0 == cinst->_enumerator._num_decoders) return 0;
686
687 /* Collect mnemonics of corresponding decoders (if defined). */
688 for (i = 0; i < cinst->_enumerator._num_decoders; ++i) {
689 /* Start by verifying that we can get name name. */
690 NaClEnumeratorDecoder *decoder = cinst->_enumerator._decoder[i];
691 if (NULL == decoder->_get_inst_mnemonic_fn) continue;
692 if (!decoder->_is_inst_legal_fn(&cinst->_enumerator)) continue;
693
694 /* If on ignore list, ignore. */
695 if (InInstructionList(kIgnoreMnemonics,
696 cinst->_enumerator._itext,
697 decoder->_inst_length_fn(&cinst->_enumerator)))
698 continue;
699
700 /* Record mnemonic name and decoder for comparisons below. */
701 name[num_decoders] = decoder->_get_inst_mnemonic_fn(&cinst->_enumerator);
702 name_decoder[num_decoders++] = decoder;
703 }
704
705 /* Now compare mnemonics that were defined. */
706 for (i = 1; i < num_decoders; ++i) {
707 if (strncmp(name[i-1], name[i], kBufferSize) != 0) {
708 char sbuf[kBufferSize];
709 snprintf(sbuf, kBufferSize, "(%s) %s != (%s) %s",
710 name_decoder[i-1]->_id_name, name[i-1],
711 name_decoder[i]->_id_name, name[i]);
712 DecoderError("MNEMONIC MISMATCH", cinst, sbuf);
713 return FALSE;
714 }
715 }
716
717 if (kDebug && (num_decoders > 0)) {
718 printf("names match: %s\n", name[0]);
719 }
720 return TRUE;
721 }
722
723 /* Returns true if the decoder decodes the instruction correctly,
724 * and also (to the best it can determine) validates when
725 * specified to do so on the command line.
726 */
727 static Bool ConsiderInstLegal(NaClEnumerator* enumerator,
728 NaClEnumeratorDecoder* decoder) {
729 if (!decoder->_is_inst_legal_fn(enumerator)) return FALSE;
730 if (!gNaClLegal) return TRUE;
731 if (NULL == decoder->_maybe_inst_validates_fn) return TRUE;
732 return decoder->_maybe_inst_validates_fn(enumerator);
733 }
734
735 /* Returns true only if the legal filters allow the instruction to
736 * be processed.
737 */
738 static Bool RemovedByInstLegalFilters(ComparedInstruction* cinst) {
739 size_t i;
740 for (i = 0; i < cinst->_enumerator._num_decoders; ++i) {
741 if (ConsiderInstLegal(&cinst->_enumerator,
742 cinst->_enumerator._decoder[i])
743 != cinst->_enumerator._decoder[i]->_legal_only) {
744 return TRUE;
745 }
746 }
747 return FALSE;
748 }
749
750 /* Returns true if the instruction has the same length for all decoders.
751 * Reports length differences if found.
752 */
753 static Bool AreInstructionLengthsEqual(ComparedInstruction *cinst) {
754 size_t i;
755 size_t num_decoders = 0;
756 size_t length[NACL_MAX_ENUM_DECODERS];
757 NaClEnumeratorDecoder* length_decoder[NACL_MAX_ENUM_DECODERS];
758
759 /* If no decoders, vacuously true. */
760 if (0 == cinst->_enumerator._num_decoders) return TRUE;
761
762 /* Collect the instruction length for each decoder. */
763 for (i = 0; i < cinst->_enumerator._num_decoders; ++i) {
764 if (cinst->_enumerator._decoder[i]->
765 _is_inst_legal_fn(&cinst->_enumerator)) {
766 length[num_decoders] = cinst->_enumerator._decoder[i]->
767 _inst_length_fn(&cinst->_enumerator);
768 length_decoder[num_decoders] = cinst->_enumerator._decoder[i];
769 ++num_decoders;
770 }
771 }
772
773 /* Print out where lengths differ, if they differ. */
774 for (i = 1; i < num_decoders; ++i) {
775 if (length[i-1] != length[i]) {
776 char sbuf[kBufferSize];
777 snprintf(sbuf, kBufferSize, "(%s) %"NACL_PRIuS" != (%s) %"NACL_PRIuS,
778 length_decoder[i-1]->_id_name, length[i-1],
779 length_decoder[i]->_id_name, length[i]);
780 DecoderError("LENGTH MISMATCH", cinst, sbuf);
781 gSawLethalError = 1;
782 return FALSE;
783 }
784 }
785
786 if (kDebug && (num_decoders > 0)) {
787 printf("length match: %"NACL_PRIuS"\n", length[0]);
788 }
789 return TRUE;
790 }
791
792 /* Print out decodings for print only directives. Returns true
793 * if print only directives followed. This function is used
794 * to short circuit instruction comparison, when printing of
795 * filtered instructions on the command line is specified.
796 */
797 static Bool PrintInstOnly(ComparedInstruction *cinst) {
798 Bool result = FALSE;
799 size_t i;
800 for (i = 0; i < cinst->_enumerator._num_decoders; ++i) {
801 if (cinst->_enumerator._decoder[i]->_print_only) {
802 cinst->_enumerator._decoder[i]->_print_inst_fn(&cinst->_enumerator);
803 result = TRUE;
804 }
805 }
806 return result;
807 }
808
809 /* If non-null, the list of instruction bytes to ignore. */
810 static InstList* kIgnoredInstructions = NULL;
811
812 /* Test comparison for a single instruction.
813 */
814 static void TryOneInstruction(ComparedInstruction *cinst,
815 uint8_t *itext, size_t nbytes) {
816 do {
817 if (gVerbose) {
818 size_t i;
819 printf("================");
820 for (i = 0; i < nbytes; ++i) {
821 printf("%02x", itext[i]);
822 }
823 printf("\n");
824 }
825
826 /* Try to parse the sequence of test bytes. */
827 ParseFirstInstruction(cinst, itext, nbytes);
828
829 /* Don't bother to compare ignored instructions. */
830 if (InInstructionList(kIgnoredInstructions, itext, nbytes)) break;
831
832 /* Apply filters */
833 if (RemovedByInstLegalFilters(cinst)) break;
834
835 /* Print the instruction if print only option chosen, and then quit. */
836 if (PrintInstOnly(cinst)) break;
837
838 /* Apply comparison checks to the decoded instructions. */
839 if (!AreInstructionLengthsEqual(cinst)) break;
840 if (!AreInstMnemonicsEqual(cinst)) break;
841 if (gCheckOperands && !AreInstOperandsEqual(cinst)) break;
842 #if NACL_TARGET_SUBARCH == 64
843 if (BadRegWrite(cinst)) break;
844 #endif
845
846 /* no error */
847 if (gVerbose) {
848 PrintDisassembledInstructionVariants(cinst);
849 }
850 } while (0);
851
852 /* saw error; should have already printed stuff. Only
853 * report on skipped errors if we found an error-free
854 * instruction.
855 */
856 if (gSkipContiguous && (!cinst->_decoder_error)) {
857 ReportOnSkippedErrors(cinst, NULL);
858 }
859 }
860
861 /* Returns true if for all decoders recognize legal instructions, they use
862 * less than len bytes.
863 */
864 static int IsLegalInstShorterThan(ComparedInstruction *cinst, int len) {
865 size_t i;
866 Bool found_legal = FALSE;
867 for (i = 0; i < cinst->_enumerator._num_decoders; ++i) {
868 if (cinst->_enumerator._decoder[i]->
869 _is_inst_legal_fn(&cinst->_enumerator)) {
870 found_legal = TRUE;
871 if (cinst->_enumerator._decoder[i]->_inst_length_fn(&cinst->_enumerator)
872 >= len) return FALSE;
873 }
874 }
875 return found_legal;
876 }
877
878 /* Enumerate and test all 24-bit opcode+modrm+sib patterns for a
879 * particular prefix.
880 */
881 static void TestAllWithPrefix(ComparedInstruction *cinst,
882 int prefix, int prefix_length) {
883 const int kFillerByteCount = 15;
884 const int kInstByteCount = 15;
885 const int kIterByteCount = 3;
886 uint8_t itext[kBufferSize];
887 int i, op, modrm, sib;
888 int min_op;
889 int max_op;
890
891 if ((gPrefix >= 0) && (gPrefix != prefix)) return;
892
893 if (!gSilent) printf("TestAllWithPrefix(%x)\n", prefix);
894 /* set up prefix */
895 memcpy(itext, &prefix, prefix_length);
896 /* set up filler bytes */
897 for (i = 0; i < kFillerByteCount; i++) {
898 itext[i + prefix_length + kIterByteCount] = (uint8_t)i;
899 }
900 if (gOpcode < 0) {
901 min_op = 0;
902 max_op = 256;
903 } else {
904 min_op = gOpcode;
905 max_op = gOpcode + 1;
906 }
907 for (op = min_op; op < max_op; op++) {
908 itext[prefix_length] = op;
909 ResetSkipCounts(NULL);
910 if (!gSilent) printf("%02x 00 00\n", op);
911 for (modrm = 0; modrm < 256; modrm++) {
912 itext[prefix_length + 1] = modrm;
913 for (sib = 0; sib < 256; sib++) {
914 itext[prefix_length + 2] = sib;
915 TryOneInstruction(cinst, itext, kInstByteCount);
916 /* If all decoders decode without using the sib byte, don't
917 * bother to try more variants.
918 */
919 if (IsLegalInstShorterThan(cinst, prefix_length + 3)) break;
920 }
921 /* If all decoders decode without using the modrm byte, don't
922 * bother to try more variants.
923 */
924 if (IsLegalInstShorterThan(cinst, prefix_length + 2)) break;
925 }
926 /* Force flushing of skipped errors, since we are now moving on
927 * to the next opcode.
928 */
929 ReportOnSkippedErrors(cinst, NULL);
930 }
931 }
932
933 /* For all prefixes, call TestAllWithPrefix() to enumrate and test
934 * all instructions.
935 */
936 static void TestAllInstructions(ComparedInstruction *cinst) {
937 gSkipRepeatReports = TRUE;
938 /* NOTE: Prefix byte order needs to be reversed when written as
939 * an integer. For example, for integer prefix 0x3a0f, 0f will
940 * go in instruction byte 0, and 3a in byte 1.
941 */
942 TestAllWithPrefix(cinst, 0, 0);
943 TestAllWithPrefix(cinst, 0x0f, 1);
944 TestAllWithPrefix(cinst, 0x0ff2, 2);
945 TestAllWithPrefix(cinst, 0x0ff3, 2);
946 TestAllWithPrefix(cinst, 0x0f66, 2);
947 TestAllWithPrefix(cinst, 0x0f0f, 2);
948 TestAllWithPrefix(cinst, 0x380f, 2);
949 TestAllWithPrefix(cinst, 0x3a0f, 2);
950 TestAllWithPrefix(cinst, 0x380f66, 3);
951 TestAllWithPrefix(cinst, 0x380ff2, 3);
952 TestAllWithPrefix(cinst, 0x3a0f66, 3);
953 }
954
955 /* Used to test one instruction at a time, for example, in regression
956 * testing, or for instruction arguments from the command line.
957 */
958 static void TestOneInstruction(ComparedInstruction *cinst, char *asciihex) {
959 uint8_t ibytes[NACL_ENUM_MAX_INSTRUCTION_BYTES];
960 int nbytes;
961
962 nbytes = Text2Bytes(ibytes, asciihex, "Command-line argument", -1);
963 if (nbytes == 0) return;
964 if (gVerbose) {
965 int i;
966 printf("trying %s (", asciihex);
967 for (i = 0; i < nbytes; ++i) {
968 printf("%02x", ibytes[i]);
969 }
970 printf(")\n");
971 }
972 TryOneInstruction(cinst, ibytes, (size_t) nbytes);
973 }
974
975 /* A set of test cases that have caused problems in the past.
976 * This is a bit stale; most of the test cases came from xed_compare.py.
977 * Mostly this program has been tested by TestAllInstructions(),
978 * possible since this program is much faster than xed_compare.py
979 */
980 static void RunRegressionTests(ComparedInstruction *cinst) {
981 TestOneInstruction(cinst, "0024c2");
982 TestOneInstruction(cinst, "017967");
983 TestOneInstruction(cinst, "0f12c0");
984 TestOneInstruction(cinst, "0f13c0");
985 TestOneInstruction(cinst, "0f17c0");
986 TestOneInstruction(cinst, "0f01c1");
987 TestOneInstruction(cinst, "0f00300000112233445566778899aa");
988 TestOneInstruction(cinst, "cc");
989 TestOneInstruction(cinst, "C3");
990 TestOneInstruction(cinst, "0f00290000112233445566778899aa");
991 TestOneInstruction(cinst, "80e4f7");
992 TestOneInstruction(cinst, "e9a0ffffff");
993 TestOneInstruction(cinst, "4883ec08");
994 TestOneInstruction(cinst, "0f00040500112233445566778899aa");
995 /* Below are newly discovered mistakes in call instructions, where the wrong
996 * byte length was required by x86-64 nacl validator.
997 */
998 TestOneInstruction(cinst, "262e7e00");
999 TestOneInstruction(cinst, "2e3e7900");
1000 }
1001
1002 /* Register the decoder with the given name, returning the corresponding
1003 * decoder.
1004 */
1005 static NaClEnumeratorDecoder*
1006 NaClRegisterEnumeratorDecoder(ComparedInstruction* cinst,
1007 const char* decoder_name) {
1008 /* First check if already registered. If so, simply return it. */
1009 size_t i;
1010 for (i = 0; i < cinst->_enumerator._num_decoders; ++i) {
1011 if (0 == strcmp(cinst->_enumerator._decoder[i]->_id_name, decoder_name)) {
1012 return cinst->_enumerator._decoder[i];
1013 }
1014 }
1015
1016 /* If reached, not registered yet. See if one with the given name
1017 * is available (i.e. preregistered).
1018 */
1019 for (i = 0; i < kNumAvailableDecoders; ++i) {
1020 NaClEnumeratorDecoder* decoder = kAvailableDecoders[i];
1021 if (0 == strcmp(decoder->_id_name, decoder_name)) {
1022 if (cinst->_enumerator._num_decoders < NACL_MAX_ENUM_DECODERS) {
1023 cinst->_enumerator._decoder[cinst->_enumerator._num_decoders++] =
1024 decoder;
1025 return decoder;
1026 }
1027 }
1028 }
1029
1030 /* If reached, can't find a decoder with the given name, abort. */
1031 printf("Can't find decoder '%s', aborting!\n", decoder_name);
1032 exit(1);
1033 }
1034
1035 /* Install legal filter values for corresponding available decoders. */
1036 static void NaClInstallLegalFilter(ComparedInstruction* cinst,
1037 const char* decoder_name,
1038 Bool new_value) {
1039 NaClRegisterEnumeratorDecoder(cinst, decoder_name)->_legal_only = new_value;
1040 }
1041
1042 /* The initial size for bytes_ when creating an instruction list.
1043 */
1044 static const size_t kInitialInstBytesSize = 1024;
1045
1046 /* The initial size for insts_ when creating an instruction list.
1047 */
1048 static const size_t kInitialInstListInstsSize = 256;
1049
1050 /* Creates an initially empty list of instructions. */
1051 static InstList* CreateEmptyInstList() {
1052 InstList* list = (InstList*) malloc(sizeof(InstList));
1053 if (NULL == list) ReportFatalError("Out of memory");
1054 list->bytes_ = (uint8_t*) malloc(kInitialInstBytesSize);
1055 list->bytes_size_ = kInitialInstBytesSize;
1056 list->insts_ = (size_t*) malloc(kInitialInstListInstsSize);
1057 list->insts_size_ = kInitialInstListInstsSize;
1058 list->insts_[0] = 0;
1059 list->num_insts_ = 0;
1060 list->num_bytes_ = 0;
1061 return list;
1062 }
1063 /* Expands the bytes_ field of the instruction list so that
1064 * more instructions can be added.
1065 */
1066 static void ExpandInstListBytes(InstList* list) {
1067 size_t i;
1068 uint8_t* new_buffer;
1069 size_t new_size = list->bytes_size_ *2;
1070 if (new_size < list->bytes_size_) {
1071 ReportFatalError("Instruction list file too big");
1072 }
1073 new_buffer = (uint8_t*) malloc(new_size);
1074 if (NULL == new_buffer) ReportFatalError("Out of memory");
1075 for (i = 0; i < list->num_bytes_; ++i) {
1076 new_buffer[i] = list->bytes_[i];
1077 }
1078 free(list->bytes_);
1079 list->bytes_ = new_buffer;
1080 list->bytes_size_ = new_size;
1081 }
1082
1083 /* Expands the insts_ field of the instruction list so that
1084 * more instructions can be added.
1085 */
1086 static void ExpandInstListInsts(InstList* list) {
1087 size_t i;
1088 size_t* new_buffer;
1089 size_t new_size = list->insts_size_ * 2;
1090
1091 if (new_size < list->insts_size_)
1092 ReportFatalError("Instruction list file too big");
1093 new_buffer = (size_t*) malloc(new_size);
1094 if (NULL == new_buffer) ReportFatalError("Out of memory");
1095 for (i = 0; i < list->num_insts_; ++i) {
1096 new_buffer[i] = list->insts_[i];
1097 }
1098 free(list->insts_);
1099 list->insts_ = new_buffer;
1100 list->insts_size_ = new_size;
1101 }
1102
1103 /* Reads the bytes defined in line, and coverts it to the corresponding
1104 * ignored instruction. Then adds it to the list of ignored instructions.
1105 */
1106 static void ReadInstListInst(InstList* list,
1107 char line[kBufferSize],
1108 const char* context,
1109 int line_number) {
1110 int i;
1111 uint8_t ibytes[NACL_ENUM_MAX_INSTRUCTION_BYTES];
1112 int num_bytes = Text2Bytes(ibytes, line, context, line_number);
1113
1114 /* Ignore line if no opcode sequence. */
1115 if (num_bytes == 0) return;
1116
1117 /* First update the instruction pointers. */
1118 if (list->num_insts_ == list->insts_size_) {
1119 ExpandInstListInsts(list);
1120 }
1121 ++list->num_insts_;
1122 list->insts_[list->num_insts_] =
1123 list->insts_[list->num_insts_ - 1];
1124
1125 /* Now install the bytes. */
1126 for (i = 0; i < num_bytes; ++i) {
1127 /* Be sure we have room for the byte. */
1128 if (list->num_bytes_ == list->bytes_size_) {
1129 ExpandInstListBytes(list);
1130 }
1131
1132 /* Record into the ignore instruction list. */
1133 list->bytes_[list->num_bytes_++] = ibytes[i];
1134 list->insts_[list->num_insts_] = list->num_bytes_;
1135 }
1136 }
1137
1138 /* Reads a file containing a list of instruction bytes to ignore,
1139 * and adds it to the end of the list of instructions.
1140 */
1141 static void GetInstList(InstList** list,
1142 FILE* file,
1143 const char* filename) {
1144 char line[kBufferSize];
1145 int line_number = 0;
1146 if (NULL == *list) {
1147 *list = CreateEmptyInstList();
1148 }
1149 while (TRUE) {
1150 ++line_number;
1151 if (fgets(line, kBufferSize, file) == NULL) return;
1152 ReadInstListInst(*list, line, filename, line_number);
1153 }
1154 return;
1155 }
1156
1157 /* Read the file containing a list of instruction bytes,
1158 * and adds it to the end of the list of instructions.
1159 */
1160 static void ReadInstList(InstList** list, const char* filename) {
1161 FILE* file = fopen(filename, "r");
1162 if (NULL == file) {
1163 char buffer[kBufferSize];
1164 snprintf(buffer, kBufferSize, "%s: unable to open", filename);
1165 ReportFatalError(buffer);
1166 }
1167 GetInstList(list, file, filename);
1168 fclose(file);
1169 }
1170
1171 /* Very simple command line arg parsing. Returns index to the first
1172 * arg that doesn't begin with '--', or argc if there are none.
1173 */
1174 static int ParseArgs(ComparedInstruction* cinst, int argc, char *argv[]) {
1175 int i;
1176 uint32_t prefix;
1177 uint32_t opcode;
1178 char* cstr_value;
1179
1180 for (i = 1; i < argc; i++) {
1181 if (argv[i][0] == '-') {
1182 do {
1183 if (strcmp(argv[i], "--help") == 0) {
1184 Usage();
1185 } else if (GrokBoolFlag("--checkoperands", argv[i], &gCheckOperands) ||
1186 GrokBoolFlag("--nacllegal", argv[i],
1187 &gNaClLegal) ||
1188 GrokBoolFlag("--xedimplemented", argv[i],
1189 &gXedImplemented) ||
1190 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],
1197 &gSkipContiguous) ||
1198 GrokBoolFlag("--verbose", argv[i], &gVerbose)) {
1199 } else if (GrokCstringFlag("--ignored", argv[i], &cstr_value)) {
1200 ReadInstList(&kIgnoredInstructions, cstr_value);
1201 } else if (GrokCstringFlag("--ignore_mnemonic", argv[i], &cstr_value)) {
1202 ReadInstList(&kIgnoreMnemonics, cstr_value);
1203 } else if (GrokCstringFlag("--print", argv[i], &cstr_value)) {
1204 NaClRegisterEnumeratorDecoder(cinst, cstr_value)->_print_only = TRUE;
1205 } else if (GrokUint32HexFlag("--prefix", argv[i], &prefix)) {
1206 gPrefix = (int) prefix;
1207 printf("using prefix %x\n", gPrefix);
1208 } else if (GrokUint32HexFlag("--opcode", argv[i], &opcode) &&
1209 opcode < 256) {
1210 gOpcode = (int) opcode;
1211 printf("using opcode %x\n", gOpcode);
1212 } else if (GrokCstringFlag("--legal", argv[i], &cstr_value)) {
1213 NaClInstallLegalFilter(cinst, cstr_value, TRUE);
1214 } else if (GrokCstringFlag("--illegal", argv[i], &cstr_value)) {
1215 NaClInstallLegalFilter(cinst, cstr_value, FALSE);
1216 } else if (argv[i] == strfind(argv[i], "--")) {
1217 NaClRegisterEnumeratorDecoder(cinst, argv[i] + 2);
1218 } else {
1219 fprintf(stderr, "Can't recognize option %s\n", argv[i]);
1220 exit(1);
1221 }
1222 } while (0);
1223 } else return i;
1224 }
1225 return argc;
1226 }
1227
1228 /* Define set of available enumerator decoders. */
1229 static void NaClPreregisterEnumeratorDecoder(ComparedInstruction* cinst,
1230 NaClEnumeratorDecoder* decoder) {
1231 if (kNumAvailableDecoders >= NACL_MAX_AVAILABLE_DECODERS) {
1232 printf("Too many preregistered enumerator decoders\n");
1233 exit(1);
1234 }
1235 kAvailableDecoders[kNumAvailableDecoders++] = decoder;
1236 }
1237
1238 /* Define decoders that can be registered. */
1239 extern NaClEnumeratorDecoder* RegisterXedDecoder();
1240 extern NaClEnumeratorDecoder* RegisterNaClDecoder();
1241
1242 /* Initialize the set of available decoders. */
1243 static void NaClInitializeAvailableDecoders() {
1244 kNumAvailableDecoders = 0;
1245 #ifdef NACL_XED_DECODER
1246 NaClPreregisterEnumeratorDecoder(&gCinst, RegisterXedDecoder());
1247 #endif
1248 NaClPreregisterEnumeratorDecoder(&gCinst, RegisterNaClDecoder());
1249 }
1250
1251 /* Initialize the ComparedInstruction data structure. */
1252 static void NaClInitializeComparedInstruction(ComparedInstruction* cinst) {
1253 cinst->_enumerator._num_decoders = 0;
1254 cinst->_enumerator._print_opcode_bytes_only = FALSE;
1255 cinst->_enumerator._print_enumerated_instruction = FALSE;
1256 }
1257
1258
1259 /* Install parsed globals, as appropriate into the corresponding
1260 * decoders.
1261 */
1262 static void InstallFlags(NaClEnumerator* enumerator) {
1263 size_t i;
1264 for (i = 0; i < enumerator->_num_decoders; ++i) {
1265 enumerator->_decoder[i]->_install_flag_fn(enumerator,
1266 "--nops",
1267 &gNoCompareNops);
1268 enumerator->_decoder[i]->_install_flag_fn(enumerator,
1269 "--xedimplemented",
1270 &gXedImplemented);
1271 }
1272 if (enumerator->_print_opcode_bytes_only ||
1273 enumerator->_print_enumerated_instruction) {
1274 gSilent = TRUE;
1275 }
1276 }
1277
1278 int main(int argc, char *argv[]) {
1279 int testargs;
1280
1281 NaClLogModuleInit();
1282 NaClLogSetVerbosity(LOG_FATAL);
1283 NaClInitializeAvailableDecoders();
1284 NaClInitializeComparedInstruction(&gCinst);
1285
1286 gArgv0 = argv[0];
1287 if (argc == 1) Usage();
1288
1289 testargs = ParseArgs(&gCinst, argc, argv);
1290 InstallFlags(&gCinst._enumerator);
1291
1292
1293 if (gCinst._enumerator._num_decoders == 0) {
1294 fprintf(stderr, "No decoder specified, can't continue\n");
1295 exit(1);
1296 }
1297
1298 if (testargs == argc) {
1299 if (gPrefix < 0) RunRegressionTests(&gCinst);
1300 TestAllInstructions(&gCinst);
1301 } else {
1302 int i;
1303 gSilent = FALSE;
1304 gVerbose = TRUE;
1305 for (i = testargs; i < argc; ++i) {
1306 TestOneInstruction(&gCinst, argv[i]);
1307 }
1308 }
1309 exit(gSawLethalError);
1310 }
OLDNEW
« no previous file with comments | « src/trusted/validator/x86/testing/enuminsts/text2hex.h ('k') | src/trusted/validator/x86/testing/enuminsts/xed_tester.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698