| OLD | NEW |
| (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 } | |
| OLD | NEW |