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 |