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

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

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

Powered by Google App Engine
This is Rietveld 408576698