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