OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. | 2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. |
3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 /* vdiff.c | 7 /* vdiff.c |
8 * exhaustive instruction enumeration test for x86 Native Client validators. | 8 * exhaustive instruction enumeration test for x86 Native Client validators. |
9 * | 9 * |
10 * This file is based on enuminsts.c, but specialized to comparing two | 10 * This file is based on enuminsts.c, but specialized to comparing two |
11 * validators instead of decoders. The enuminsts.c implementation also | 11 * validators instead of decoders. The enuminsts.c implementation also |
12 * had a bunch of Xed-specific logic which complicated the validator | 12 * had a bunch of Xed-specific logic which complicated the validator |
13 * comparison in unhelpful ways. | 13 * comparison in unhelpful ways. |
14 */ | 14 */ |
15 | 15 |
16 #ifndef NACL_TRUSTED_BUT_NOT_TCB | 16 #ifndef NACL_TRUSTED_BUT_NOT_TCB |
17 #error("This file is not meant for use in the TCB.") | 17 #error("This file is not meant for use in the TCB.") |
18 #endif | 18 #endif |
| 19 #if NACL_WINDOWS |
| 20 #define _CRT_RAND_S /* enable decl of rand_s() */ |
| 21 #endif |
19 | 22 |
20 #include "native_client/src/trusted/validator/x86/testing/enuminsts/enuminsts.h" | 23 #include "native_client/src/trusted/validator/x86/testing/enuminsts/enuminsts.h" |
21 | 24 |
22 #include <ctype.h> | 25 #include <ctype.h> |
23 #include <stdio.h> | 26 #include <stdio.h> |
24 #include <string.h> | 27 #include <string.h> |
25 #include <stdlib.h> | 28 #include <stdlib.h> |
26 #include <stdarg.h> | 29 #include <stdarg.h> |
| 30 #include <time.h> |
27 | 31 |
28 #include "native_client/src/include/portability_io.h" | 32 #include "native_client/src/include/portability_io.h" |
29 #include "native_client/src/shared/platform/nacl_log.h" | 33 #include "native_client/src/shared/platform/nacl_log.h" |
30 #include "native_client/src/shared/utils/flags.h" | 34 #include "native_client/src/shared/utils/flags.h" |
31 #include "native_client/src/trusted/validator/x86/testing/enuminsts/str_utils.h" | 35 #include "native_client/src/trusted/validator/x86/testing/enuminsts/str_utils.h" |
32 #include "native_client/src/trusted/validator/x86/testing/enuminsts/text2hex.h" | 36 #include "native_client/src/trusted/validator/x86/testing/enuminsts/text2hex.h" |
33 | 37 |
34 /* Defines the maximum buffer size used to hold text generated for the | 38 /* Defines the maximum buffer size used to hold text generated for the |
35 * disassembly of instructions, and corresponding error messages. | 39 * disassembly of instructions, and corresponding error messages. |
36 */ | 40 */ |
37 #define kBufferSize 1024 | 41 #define kBufferSize 1024 |
38 | 42 |
39 /* When true, print more messages (i.e. verbosely). */ | 43 /* When true, print more messages (i.e. verbosely). */ |
40 static Bool gVerbose = FALSE; | 44 static Bool gVerbose = FALSE; |
41 | 45 |
42 /* When true, don't print out messages. That is, only print instructions | 46 /* When true, don't print out messages. That is, only print instructions |
43 * defined by --print directives. | 47 * defined by --print directives. |
44 */ | 48 */ |
45 static Bool gSilent = FALSE; | 49 static Bool gSilent = FALSE; |
46 | 50 |
47 /* When true, don't report consecutive errors for consecutive instructions | 51 /* When true, don't report consecutive errors for consecutive instructions |
48 * with the same instruction mnemonic. | 52 * with the same instruction mnemonic. |
49 */ | 53 */ |
50 static Bool gSkipRepeatReports = FALSE; | 54 static Bool gSkipRepeatReports = FALSE; |
51 | 55 |
| 56 /* Set to true to enable checking of mnemonics (opcode names). |
| 57 */ |
| 58 static Bool gCheckMnemonics = TRUE; |
| 59 |
52 /* Count of errors that have a high certainty of being exploitable. */ | 60 /* Count of errors that have a high certainty of being exploitable. */ |
53 static int gSawLethalError = 0; | 61 static int gSawLethalError = 0; |
54 | 62 |
55 /* Defines the assumed text address for the test instruction */ | 63 /* Defines the assumed text address for the test instruction */ |
56 const int kTextAddress = 0x1000; | 64 const int kTextAddress = 0x1000; |
57 | 65 |
58 /* If non-negative, defines the prefix to test. */ | 66 /* If non-negative, defines the prefix to test. */ |
59 static unsigned int gPrefix = 0; | 67 static unsigned int gPrefix = 0; |
60 | 68 |
61 /* If non-negative, defines the opcode to test. */ | 69 /* If non-negative, defines the opcode to test. */ |
62 static int gOpcode = -1; | 70 static int gOpcode = -1; |
63 | 71 |
| 72 /* This option triggers a set of behaviors that help produce repeatable |
| 73 * output, for easier diffs on the buildbots. |
| 74 */ |
| 75 static Bool gEasyDiffMode; |
| 76 |
64 /* The production and new R-DFA validators */ | 77 /* The production and new R-DFA validators */ |
65 NaClEnumeratorDecoder* vProd; | 78 NaClEnumeratorDecoder* vProd; |
66 NaClEnumeratorDecoder* vDFA; | 79 NaClEnumeratorDecoder* vDFA; |
67 | 80 |
68 /* The name of the executable (i.e. argv[0] from the command line). */ | 81 /* The name of the executable (i.e. argv[0] from the command line). */ |
69 static char *gArgv0 = "argv0"; | 82 static const char *gArgv0 = "argv0"; |
| 83 #define FLAG_EasyDiff "--easydiff" |
70 | 84 |
71 /* Records that unexpected internal error occurred. */ | 85 /* Records that unexpected internal error occurred. */ |
72 void InternalError(const char *why) { | 86 void InternalError(const char *why) { |
73 fprintf(stderr, "%s: Internal Error: %s\n", gArgv0, why); | 87 fprintf(stderr, "%s: Internal Error: %s\n", gArgv0, why); |
74 gSawLethalError = 1; | 88 gSawLethalError = 1; |
75 } | 89 } |
76 | 90 |
77 /* Records that a fatal (i.e. non-recoverable) error occurred. */ | 91 /* Records that a fatal (i.e. non-recoverable) error occurred. */ |
78 void ReportFatalError(const char* why) { | 92 void ReportFatalError(const char* why) { |
79 char buffer[kBufferSize]; | 93 char buffer[kBufferSize]; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 } | 152 } |
139 | 153 |
140 static void CheckMnemonics(NaClEnumerator* pinst, NaClEnumerator* dinst) { | 154 static void CheckMnemonics(NaClEnumerator* pinst, NaClEnumerator* dinst) { |
141 const char* prod_opcode = vProd->_get_inst_mnemonic_fn(pinst); | 155 const char* prod_opcode = vProd->_get_inst_mnemonic_fn(pinst); |
142 const char* dfa_opcode = vDFA->_get_inst_mnemonic_fn(dinst); | 156 const char* dfa_opcode = vDFA->_get_inst_mnemonic_fn(dinst); |
143 | 157 |
144 if (0 != strcmp(prod_opcode, dfa_opcode)) { | 158 if (0 != strcmp(prod_opcode, dfa_opcode)) { |
145 /* avoid redundant messages... */ | 159 /* avoid redundant messages... */ |
146 if (NotOpcodeRepeat(prod_opcode)) { | 160 if (NotOpcodeRepeat(prod_opcode)) { |
147 printf("Warning: OPCODE MISMATCH: %s != %s\n", prod_opcode, dfa_opcode); | 161 printf("Warning: OPCODE MISMATCH: %s != %s\n", prod_opcode, dfa_opcode); |
148 /* PrintDisassembledInstructionVariants(pinst, dinst); */ | |
149 } | 162 } |
150 } | 163 } |
151 } | 164 } |
152 | 165 |
153 struct vdiff_stats { | 166 struct vdiff_stats { |
154 int64_t tried; | 167 int64_t tried; |
155 int64_t valid; | 168 int64_t valid; |
156 int64_t invalid; | 169 int64_t invalid; |
157 int64_t errors; | 170 int64_t errors; |
158 } gVDiffStats = {0, 0, 0, 0}; | 171 } gVDiffStats = {0, 0, 0, 0}; |
159 | 172 |
160 static void IncrTried() { | 173 static void IncrTried() { |
161 gVDiffStats.tried += 1; | 174 gVDiffStats.tried += 1; |
162 } | 175 } |
163 | 176 |
164 static void IncrValid() { | 177 static void IncrValid() { |
165 gVDiffStats.valid += 1; | 178 gVDiffStats.valid += 1; |
166 } | 179 } |
167 | 180 |
168 static void IncrInvalid() { | 181 static void IncrInvalid() { |
169 gVDiffStats.invalid += 1; | 182 gVDiffStats.invalid += 1; |
170 } | 183 } |
171 | 184 |
172 static void IncrErrors() { | 185 static void IncrErrors() { |
173 gVDiffStats.errors += 1; | 186 gVDiffStats.errors += 1; |
174 } | 187 } |
175 | 188 |
176 static void PrintStats() { | 189 static void PrintStats() { |
177 printf("valid: %" NACL_PRIu64 "\n", gVDiffStats.valid); | 190 if (!gEasyDiffMode) { |
178 printf("invalid: %" NACL_PRIu64 "\n", gVDiffStats.invalid); | 191 printf("Stats:\n"); |
| 192 printf("valid: %" NACL_PRIu64 "\n", gVDiffStats.valid); |
| 193 printf("invalid: %" NACL_PRIu64 "\n", gVDiffStats.invalid); |
| 194 } |
179 printf("errors: %" NACL_PRIu64 "\n", gVDiffStats.errors); | 195 printf("errors: %" NACL_PRIu64 "\n", gVDiffStats.errors); |
180 printf("tried: %" NACL_PRIu64 "\n", gVDiffStats.tried); | 196 printf("tried: %" NACL_PRIu64 "\n", gVDiffStats.tried); |
181 printf(" =? %" NACL_PRIu64 " valid + invalid + errors\n", | 197 printf(" =? %" NACL_PRIu64 " valid + invalid + errors\n", |
182 gVDiffStats.valid + gVDiffStats.invalid + gVDiffStats.errors); | 198 gVDiffStats.valid + gVDiffStats.invalid + gVDiffStats.errors); |
183 } | 199 } |
184 | 200 |
185 static void InitInst(NaClEnumerator *nacle, | 201 static void InitInst(NaClEnumerator *nacle, |
186 uint8_t *itext, size_t nbytes) | 202 uint8_t *itext, size_t nbytes) |
187 { | 203 { |
188 memcpy(nacle->_itext, itext, nbytes); | 204 memcpy(nacle->_itext, itext, nbytes); |
(...skipping 24 matching lines...) Expand all Loading... |
213 rdfa_okay = vDFA->_maybe_inst_validates_fn(&dinst); | 229 rdfa_okay = vDFA->_maybe_inst_validates_fn(&dinst); |
214 | 230 |
215 if (prod_okay) { | 231 if (prod_okay) { |
216 if (rdfa_okay) { | 232 if (rdfa_okay) { |
217 if (vProd->_inst_length_fn(&pinst) == | 233 if (vProd->_inst_length_fn(&pinst) == |
218 vDFA->_inst_length_fn(&dinst)) { | 234 vDFA->_inst_length_fn(&dinst)) { |
219 /* Both validators see a legal instruction, */ | 235 /* Both validators see a legal instruction, */ |
220 /* and they agree on critical details. */ | 236 /* and they agree on critical details. */ |
221 IncrValid(); | 237 IncrValid(); |
222 /* Warn if decoders disagree opcode name. */ | 238 /* Warn if decoders disagree opcode name. */ |
223 CheckMnemonics(&pinst, &dinst); | 239 if (gCheckMnemonics) CheckMnemonics(&pinst, &dinst); |
224 } else { | 240 } else { |
225 DecoderError("LENGTH MISMATCH", &pinst, &dinst, ""); | 241 DecoderError("LENGTH MISMATCH", &pinst, &dinst, ""); |
226 IncrErrors(); | 242 IncrErrors(); |
227 } | 243 } |
228 } else { | 244 } else { |
229 /* Validators disagree on instruction legality */ | 245 /* Validators disagree on instruction legality */ |
230 DecoderError("VALIDATORS DISAGREE", &pinst, &dinst, ""); | 246 DecoderError("VALIDATORS DISAGREE", &pinst, &dinst, ""); |
231 IncrErrors(); | 247 IncrErrors(); |
232 } | 248 } |
233 } else if (rdfa_okay) { | 249 } else if (rdfa_okay) { |
234 /* Validators disagree on instruction legality */ | 250 /* Validators disagree on instruction legality */ |
235 DecoderError("VALIDATORS DISAGREE", &pinst, &dinst, ""); | 251 DecoderError("VALIDATORS DISAGREE", &pinst, &dinst, ""); |
236 IncrErrors(); | 252 IncrErrors(); |
237 } else { | 253 } else { |
238 /* Both validators see an illegal instruction */ | 254 /* Both validators see an illegal instruction */ |
239 IncrInvalid(); | 255 IncrInvalid(); |
240 } | 256 } |
241 | 257 |
242 /* no error */ | |
243 if (gVerbose) { | 258 if (gVerbose) { |
244 PrintDisassembledInstructionVariants(&pinst, &dinst); | 259 PrintDisassembledInstructionVariants(&pinst, &dinst); |
245 } | 260 } |
246 } while (0); | 261 } while (0); |
247 } | 262 } |
248 | 263 |
| 264 /* A function type for instruction "TestAll" functions. |
| 265 * Parameters: |
| 266 * prefix: up to four bytes of prefix. |
| 267 * prefix_length: size_t on [0..4] specifying length of prefix. |
| 268 * print_prefix: For easy diff of test output, avoid printing |
| 269 * the value of a randomly selected REX prefix. |
| 270 */ |
| 271 typedef void (*TestAllFunction)(const unsigned int prefix, |
| 272 const size_t prefix_length, |
| 273 const char* print_prefix); |
| 274 |
| 275 /* Create a char* rendition of a prefix string, appending bytes |
| 276 * in ps. When using a randomly generated REX prefix on the bots, |
| 277 * it's useful to avoid printing the actual REX prefix so that |
| 278 * output can be diffed from run-to-run. For example, instead of |
| 279 * printing "0F45" you might print "0FXX". Parameters: |
| 280 * prefix: The part of the prefix value to print |
| 281 * ps: 'postscript', string to append to prefix value |
| 282 * str: where to put the ASCII version of the prefix |
| 283 */ |
| 284 static char* StrPrefix(const unsigned int prefix, char* ps, char* str) { |
| 285 sprintf(str, "%x%s", prefix, (ps == NULL) ? "" : ps); |
| 286 return str; |
| 287 } |
| 288 |
249 /* Enumerate and test all 24-bit opcode+modrm+sib patterns for a | 289 /* Enumerate and test all 24-bit opcode+modrm+sib patterns for a |
250 * particular prefix. | 290 * particular prefix. |
251 */ | 291 */ |
252 static void TestAllWithPrefix(unsigned int prefix, size_t prefix_length) { | 292 static void TestAllWithPrefix(const unsigned int prefix, |
253 const int kInstByteCount = NACL_ENUM_MAX_INSTRUCTION_BYTES; | 293 const size_t prefix_length, |
254 const int kIterByteCount = 3; | 294 const char* print_prefix) { |
| 295 const size_t kInstByteCount = NACL_ENUM_MAX_INSTRUCTION_BYTES; |
| 296 const size_t kIterByteCount = 3; |
255 InstByteArray itext; | 297 InstByteArray itext; |
256 size_t i; | 298 size_t i; |
257 int op, modrm, sib; | 299 int op, modrm, sib; |
258 int min_op; | 300 int min_op; |
259 int max_op; | 301 int max_op; |
260 | 302 |
261 if ((gPrefix > 0) && (gPrefix != prefix)) return; | 303 if ((gPrefix > 0) && (gPrefix != prefix)) return; |
262 | 304 |
263 PrintProgress("TestAllWithPrefix(%x)\n", prefix); | 305 PrintProgress("TestAllWithPrefix(%s)\n", print_prefix); |
264 /* set up prefix */ | 306 /* set up prefix */ |
265 memcpy(itext, &prefix, prefix_length); | 307 memcpy(itext, &prefix, prefix_length); |
266 /* set up filler bytes */ | 308 /* set up filler bytes */ |
267 for (i = prefix_length + kIterByteCount; | 309 for (i = prefix_length + kIterByteCount; |
268 i < NACL_ENUM_MAX_INSTRUCTION_BYTES; i++) { | 310 i < NACL_ENUM_MAX_INSTRUCTION_BYTES; i++) { |
269 itext[i] = (uint8_t)i; | 311 itext[i] = (uint8_t)i; |
270 } | 312 } |
271 if (gOpcode < 0) { | 313 if (gOpcode < 0) { |
272 min_op = 0; | 314 min_op = 0; |
273 max_op = 256; | 315 max_op = 256; |
274 } else { | 316 } else { |
275 min_op = gOpcode; | 317 min_op = gOpcode; |
276 max_op = gOpcode + 1; | 318 max_op = gOpcode + 1; |
277 } | 319 } |
278 for (op = min_op; op < max_op; op++) { | 320 for (op = min_op; op < max_op; op++) { |
279 itext[prefix_length] = op; | 321 itext[prefix_length] = op; |
280 PrintProgress("%02x 00 00\n", op); | 322 PrintProgress("%02x 00 00\n", op); |
281 for (modrm = 0; modrm < 256; modrm++) { | 323 for (modrm = 0; modrm < 256; modrm++) { |
282 itext[prefix_length + 1] = modrm; | 324 itext[prefix_length + 1] = modrm; |
283 for (sib = 0; sib < 256; sib++) { | 325 for (sib = 0; sib < 256; sib++) { |
284 itext[prefix_length + 2] = sib; | 326 itext[prefix_length + 2] = sib; |
285 TryOneInstruction(itext, kInstByteCount); | 327 TryOneInstruction(itext, kInstByteCount); |
286 } | 328 } |
287 } | 329 } |
288 } | 330 } |
289 } | 331 } |
290 | 332 |
| 333 #if NACL_TARGET_SUBARCH == 64 |
| 334 /* REX prefixes range from 0x40 to 0x4f. */ |
| 335 const uint32_t kREXBase = 0x40; |
| 336 const uint32_t kREXRange = 0x10; |
| 337 const uint32_t kREXMax = 0x50; /* kREXBase + kREXRange */ |
| 338 |
| 339 /* Generate a random REX prefix, to use for the entire run. */ |
| 340 static uint32_t RandomRexPrefix() { |
| 341 static uint32_t static_rex_prefix = 0; |
| 342 |
| 343 if (0 == static_rex_prefix) { |
| 344 #if NACL_LINUX || NACL_OSX |
| 345 static_rex_prefix = kREXBase + (random() % kREXRange); |
| 346 #elif NACL_WINDOWS |
| 347 if (rand_s(&static_rex_prefix) != 0) { |
| 348 ReportFatalError("rand_s() failed\n"); |
| 349 } else { |
| 350 static_rex_prefix = kREXBase + (static_rex_prefix % kREXRange); |
| 351 } |
| 352 #else |
| 353 # error "Unknown operating system." |
| 354 #endif |
| 355 } |
| 356 return static_rex_prefix; |
| 357 } |
| 358 #endif |
| 359 |
| 360 #define AppendPrefixByte(oldprefix, pbyte) (((oldprefix) << 8) | (pbyte)) |
291 /* For x86-64, enhance the iteration by looping through REX prefixes. | 361 /* For x86-64, enhance the iteration by looping through REX prefixes. |
292 */ | 362 */ |
293 static void TestAllWithPrefixREX(unsigned int prefix, size_t prefix_length) { | 363 static void WithREX(TestAllFunction testall, |
| 364 const unsigned int prefix, |
| 365 const size_t prefix_length) { |
| 366 char pstr[kBufferSize]; |
294 #if NACL_TARGET_SUBARCH == 64 | 367 #if NACL_TARGET_SUBARCH == 64 |
295 unsigned char REXp; | 368 unsigned char irex; |
296 unsigned int rprefix; | 369 unsigned int rprefix; |
297 /* test with REX prefixes */ | 370 /* test with REX prefixes */ |
298 for (REXp = 0x40; REXp < 0x50; REXp++) { | 371 printf("WithREX(testall, %x, %d, %d)\n", prefix, |
299 rprefix = (prefix << 8 | REXp); | 372 (int)prefix_length, gEasyDiffMode); |
300 printf("Testing with prefix %x\n", rprefix); | 373 if (gEasyDiffMode) { |
301 TestAllWithPrefix(rprefix, prefix_length + 1); | 374 printf("With random REX prefix.\n"); |
| 375 irex = RandomRexPrefix(); |
| 376 rprefix = AppendPrefixByte(prefix, irex); |
| 377 testall(rprefix, prefix_length + 1, StrPrefix(prefix, "XX", pstr)); |
| 378 } else { |
| 379 for (irex = kREXBase; irex < kREXMax; irex++) { |
| 380 rprefix = AppendPrefixByte(prefix, irex); |
| 381 printf("With REX prefix %x\n", rprefix); |
| 382 testall(rprefix, prefix_length + 1, StrPrefix(rprefix, "", pstr)); |
| 383 } |
302 } | 384 } |
303 #endif | 385 #endif |
304 /* test with no REX prefix */ | 386 /* test with no REX prefix */ |
305 TestAllWithPrefix(prefix, prefix_length); | 387 testall(prefix, prefix_length, StrPrefix(prefix, NULL, pstr)); |
306 } | 388 } |
| 389 #undef AppendPrefixByte |
307 | 390 |
308 /* For all prefixes, call TestAllWithPrefix() to enumrate and test | 391 /* For all prefixes, call TestAllWithPrefix() to enumrate and test |
309 * all instructions. | 392 * all instructions. |
310 */ | 393 */ |
311 static void TestAllInstructions() { | 394 static void TestAllInstructions() { |
312 gSkipRepeatReports = TRUE; | 395 gSkipRepeatReports = TRUE; |
313 /* NOTE: Prefix byte order needs to be reversed when written as | 396 /* NOTE: Prefix byte order needs to be reversed when written as |
314 * an integer. For example, for integer prefix 0x3a0f, 0f will | 397 * an integer. For example, for integer prefix 0x3a0f, 0f will |
315 * go in instruction byte 0, and 3a in byte 1. | 398 * go in instruction byte 0, and 3a in byte 1. |
316 */ | 399 */ |
317 /* TODO(bradchen): extend enuminsts-64 to iterate over 64-bit prefixes. */ | 400 WithREX(TestAllWithPrefix, 0, 0); |
318 TestAllWithPrefixREX(0, 0); | 401 WithREX(TestAllWithPrefix, 0x0f, 1); /* two-byte opcode */ |
319 TestAllWithPrefixREX(0x0f, 1); | 402 WithREX(TestAllWithPrefix, 0x0ff2, 2); /* SSE2 */ |
320 TestAllWithPrefixREX(0x0ff2, 2); | 403 WithREX(TestAllWithPrefix, 0x0ff3, 2); /* SSE */ |
321 TestAllWithPrefixREX(0x0ff3, 2); | 404 WithREX(TestAllWithPrefix, 0x0f66, 2); /* SSE2 */ |
322 TestAllWithPrefixREX(0x0f66, 2); | 405 WithREX(TestAllWithPrefix, 0x380f, 2); /* SSSE3 */ |
323 TestAllWithPrefixREX(0x0f0f, 2); | 406 WithREX(TestAllWithPrefix, 0x3a0f, 2); /* SSE4 */ |
324 TestAllWithPrefixREX(0x380f, 2); | 407 WithREX(TestAllWithPrefix, 0x380f66, 3); /* SSE4+ */ |
325 TestAllWithPrefixREX(0x3a0f, 2); | 408 WithREX(TestAllWithPrefix, 0x380ff2, 3); /* SSE4+ */ |
326 TestAllWithPrefixREX(0x380f66, 3); | 409 WithREX(TestAllWithPrefix, 0x3a0f66, 3); /* SSE4+ */ |
327 TestAllWithPrefixREX(0x380ff2, 3); | |
328 TestAllWithPrefixREX(0x3a0f66, 3); | |
329 } | 410 } |
330 | 411 |
331 /* Used to test one instruction at a time, for example, in regression | 412 /* Used to test one instruction at a time, for example, in regression |
332 * testing, or for instruction arguments from the command line. | 413 * testing, or for instruction arguments from the command line. |
333 */ | 414 */ |
334 static void TestOneInstruction(char *asciihex) { | 415 static void TestOneInstruction(const char *asciihex) { |
335 InstByteArray ibytes; | 416 InstByteArray ibytes; |
336 int nbytes; | 417 int nbytes; |
337 | 418 |
338 nbytes = Text2Bytes(ibytes, asciihex, "Command-line argument", -1); | 419 nbytes = Text2Bytes(ibytes, asciihex, "Command-line argument", -1); |
339 if (nbytes == 0) return; | 420 if (nbytes == 0) return; |
340 if (gVerbose) { | 421 if (gVerbose) { |
341 int i; | 422 int i; |
342 printf("trying %s (", asciihex); | 423 printf("trying %s (", asciihex); |
343 for (i = 0; i < nbytes; ++i) { | 424 for (i = 0; i < nbytes; ++i) { |
344 printf("%02x", ibytes[i]); | 425 printf("%02x", ibytes[i]); |
(...skipping 28 matching lines...) Expand all Loading... |
373 */ | 454 */ |
374 TestOneInstruction("262e7e00"); | 455 TestOneInstruction("262e7e00"); |
375 TestOneInstruction("2e3e7900"); | 456 TestOneInstruction("2e3e7900"); |
376 /* From the AMD manual, "An instruction may have only one REX prefix */ | 457 /* From the AMD manual, "An instruction may have only one REX prefix */ |
377 /* which must immediately precede the opcode or first excape byte */ | 458 /* which must immediately precede the opcode or first excape byte */ |
378 /* in the instruction encoding." */ | 459 /* in the instruction encoding." */ |
379 TestOneInstruction("406601d8"); /* illegal; REX before data16 */ | 460 TestOneInstruction("406601d8"); /* illegal; REX before data16 */ |
380 TestOneInstruction("664001d8"); /* legal; REX after data16 */ | 461 TestOneInstruction("664001d8"); /* legal; REX after data16 */ |
381 TestOneInstruction("414001d8"); /* illegal; two REX bytes */ | 462 TestOneInstruction("414001d8"); /* illegal; two REX bytes */ |
382 | 463 |
383 /* Reset the opcode repeat test, so as not to silence erros */ | 464 /* Reset the opcode repeat test, so as not to silence errors */ |
384 /* that happened in the regression suite. */ | 465 /* that happened in the regression suite. */ |
385 (void)NotOpcodeRepeat(""); | 466 (void)NotOpcodeRepeat(""); |
386 } | 467 } |
387 | 468 |
388 /* Define decoders that can be registered. */ | 469 /* Define decoders that can be registered. */ |
389 extern NaClEnumeratorDecoder* RegisterNaClDecoder(); | 470 extern NaClEnumeratorDecoder* RegisterNaClDecoder(); |
390 extern NaClEnumeratorDecoder* RegisterRagelDecoder(); | 471 extern NaClEnumeratorDecoder* RegisterRagelDecoder(); |
391 | 472 |
392 /* Initialize the set of available decoders. */ | 473 /* Initialize the set of available decoders. */ |
393 static void NaClInitializeAvailableDecoders() { | 474 static void VDiffInitializeAvailableDecoders() { |
394 vProd = RegisterNaClDecoder(); | 475 vProd = RegisterNaClDecoder(); |
395 vDFA = RegisterRagelDecoder(); | 476 vDFA = RegisterRagelDecoder(); |
396 } | 477 } |
397 | 478 |
398 int main(int argc, char *argv[]) { | 479 static int ParseArgv(const int argc, const char* argv[]) { |
399 int testargs; | 480 int nextarg; |
| 481 |
| 482 gArgv0 = argv[0]; |
| 483 nextarg = 1; |
| 484 if (nextarg < argc && |
| 485 0 == strcmp(argv[nextarg], FLAG_EasyDiff)) { |
| 486 gEasyDiffMode = TRUE; |
| 487 gCheckMnemonics = FALSE; |
| 488 nextarg += 1; |
| 489 } |
| 490 return nextarg; |
| 491 } |
| 492 |
| 493 int main(const int argc, const char *argv[]) { |
| 494 int nextarg; |
400 | 495 |
401 NaClLogModuleInit(); | 496 NaClLogModuleInit(); |
402 NaClLogSetVerbosity(LOG_FATAL); | 497 NaClLogSetVerbosity(LOG_FATAL); |
403 NaClInitializeAvailableDecoders(); | 498 #if NACL_LINUX || NACL_OSX |
| 499 srandom(time(NULL)); |
| 500 #endif |
| 501 VDiffInitializeAvailableDecoders(); |
404 | 502 |
405 gArgv0 = argv[0]; | 503 nextarg = ParseArgv(argc, argv); |
406 testargs = 1; | 504 if (nextarg == argc) { |
407 | |
408 if (testargs == argc) { | |
409 if (gPrefix == 0) RunRegressionTests(); | 505 if (gPrefix == 0) RunRegressionTests(); |
410 TestAllInstructions(); | 506 TestAllInstructions(); |
411 } else { | 507 } else { |
412 int i; | 508 int i; |
413 gVerbose = TRUE; | 509 gVerbose = TRUE; |
414 for (i = testargs; i < argc; ++i) { | 510 for (i = nextarg; i < argc; ++i) { |
415 TestOneInstruction(argv[i]); | 511 TestOneInstruction(argv[i]); |
416 } | 512 } |
417 } | 513 } |
418 PrintStats(); | 514 PrintStats(); |
419 } | 515 } |
OLD | NEW |