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

Side by Side Diff: src/trusted/validator_x86/ncdis.c

Issue 625923004: Delete old x86 validator. (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2011 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 /*
8 * ncdis.c - disassemble using NaCl decoder.
9 * Mostly for testing.
10 */
11
12
13 #ifndef NACL_TRUSTED_BUT_NOT_TCB
14 #error("This file is not meant for use in the TCB")
15 #endif
16
17 #include <errno.h>
18 #include <stdarg.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include "native_client/src/shared/gio/gio.h"
24 #include "native_client/src/shared/utils/types.h"
25 #include "native_client/src/shared/utils/flags.h"
26 #include "native_client/src/shared/platform/nacl_log.h"
27 #include "native_client/src/trusted/validator/ncfileutil.h"
28 #include "native_client/src/trusted/validator/x86/decoder/nc_inst_state.h"
29 #include "native_client/src/trusted/validator/x86/decoder/ncopcode_desc.h"
30 #include "native_client/src/trusted/validator/x86/decoder/nc_decode_tables.h"
31 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode_verbose .h"
32 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate_inter naltypes.h"
33 #include "native_client/src/trusted/validator_x86/nc_read_segment.h"
34 #include "native_client/src/trusted/validator_x86/ncdis_segments.h"
35
36 /* True if we should use the full decoder when decoding. */
37 /* TODO(karl): When the full_decoder is working for both the x86-32 and
38 * x86-64 platforms, change to use full decoder for both as default.
39 */
40 static Bool NACL_FLAGS_full_decoder =
41 #if NACL_TARGET_SUBARCH == 64
42 TRUE
43 #else
44 FALSE
45 #endif
46 ;
47
48 /* True if we should use the validator decoder when decoding. */
49 static Bool NACL_FLAGS_validator_decoder =
50 #if NACL_TARGET_SUBARCH == 64
51 FALSE
52 #else
53 TRUE
54 #endif
55 ;
56
57 /* True if we should print internal representations while decoding. */
58 static Bool NACL_FLAGS_internal = FALSE;
59
60 /* The name of the executable that is being run. */
61 static const char* exec_name = "???";
62
63 static void Fatal(const char *fmt, ...) {
64 FILE* fp = stdout;
65 va_list ap;
66 fprintf(fp, "Fatal: ");
67 va_start(ap, fmt);
68 vfprintf(fp, fmt, ap);
69 va_end(ap);
70 exit(-1);
71 }
72
73 void Info(const char *fmt, ...) {
74 FILE* fp = stdout;
75 va_list ap;
76 fprintf(fp, "Info: ");
77 va_start(ap, fmt);
78 vfprintf(fp, fmt, ap);
79 va_end(ap);
80 }
81
82 static void usage(void) {
83 fprintf(stderr,
84 "usage: ncdis [options] [file]\n"
85 "\n"
86 "Options are:\n"
87 "--commands=<file>\n"
88 "\tAdditional command line arguments are specified in the given\n"
89 "\tfile ('#' acts as a comment character). Use '-' as its value to\n"
90 "\tredirect command line arguments from standard input.\n"
91 "--full_decoder\n"
92 "\tDisassemble the elf executable using native client's\n"
93 "\tfull decoder.\n"
94 "--help\n"
95 "\tPrint out this usage message\n"
96 "--hex_text=<file>\n"
97 "\tDefine code section as sequence of (textual) hexidecimal bytes\n"
98 "\tdefined in the given file. Lines beginning with '#' will be\n"
99 "\treated as comments. If the first non-comment line begins with\n"
100 "\t'@' the following hexidecimal number will be used as the\n"
101 "\tbeginning (RIP/EIP) instruction address of the code segment.\n"
102 "\tUse '-' as its value to redirect standard input as the\n"
103 "\ttext file to process.\n"
104 "-i=XXXX\n"
105 "\tXXXX specifies the sequence of hexidecimal digits that define\n"
106 "\tan instruction to be decoded.\n"
107 "--internal\n"
108 "\tFor the iterator model (only), prints out each the decoded\n"
109 "\tinstruction, followed by the internals for the matched\n"
110 "\tinstruction.\n"
111 "--pc=XXX\n"
112 "\tSet program counter (i.e. RIP or EIP) to XXX.\n"
113 "--self_document\n"
114 "\tProcess input hext_text file in such a way, that it also\n"
115 "\trepresents the output that will be generated by ncdis.\n"
116 "\tThat is, copy comment lines (i.e. lines beginning with\n"
117 "\t'#') to stdout. In addition, it assumes that each line\n"
118 "\tconsists of an '-i' command line argument (and possibly\n"
119 "\ta '--pc' command line argument, followed by a '#',\n"
120 "\tfollowed by the corresponding disassembled text. On such\n"
121 "\tlines, the input is copied up to (and including) the '#'.,\n"
122 "\tand then the disassembled instruction is printed.\n"
123 "--validator_decoder\n"
124 "\tDisassemble the file using the partial instruction decoder used\n"
125 "\tby the validator.\n"
126 );
127 exit(1);
128 }
129
130 /* Converts command line flags to corresponding disassemble flags. */
131 static NaClDisassembleFlags NaClGetDisassembleFlags(void) {
132 NaClDisassembleFlags flags = 0;
133 if (NACL_FLAGS_validator_decoder) {
134 NaClAddBits(flags, NACL_DISASSEMBLE_FLAG(NaClDisassembleValidatorDecoder));
135 }
136 if (NACL_FLAGS_full_decoder) {
137 NaClAddBits(flags, NACL_DISASSEMBLE_FLAG(NaClDisassembleFull));
138 }
139 if (NACL_FLAGS_internal) {
140 NaClAddBits(flags, NACL_DISASSEMBLE_FLAG(NaClDisassembleAddInternals));
141 }
142 return flags;
143 }
144
145 static int AnalyzeSections(ncfile *ncf) {
146 int badsections = 0;
147 int ii;
148 const Elf_Shdr* shdr = ncf->sheaders;
149
150 for (ii = 0; ii < ncf->shnum; ii++) {
151 Info("section %d sh_addr %x offset %x flags %x\n",
152 ii, (uint32_t)shdr[ii].sh_addr,
153 (uint32_t)shdr[ii].sh_offset, (uint32_t)shdr[ii].sh_flags);
154 if ((shdr[ii].sh_flags & SHF_EXECINSTR) != SHF_EXECINSTR)
155 continue;
156 Info("parsing section %d\n", ii);
157 NaClDisassembleSegment(ncf->data + (shdr[ii].sh_addr - ncf->vbase),
158 shdr[ii].sh_addr, shdr[ii].sh_size,
159 NaClGetDisassembleFlags());
160 }
161 return -badsections;
162 }
163
164 static void AnalyzeCodeSegments(ncfile *ncf, const char *fname) {
165 if (AnalyzeSections(ncf) < 0) {
166 fprintf(stderr, "%s: text validate failed\n", fname);
167 }
168 }
169
170 /* Capture a sequence of bytes defining an instruction (up to a
171 * MAX_BYTES_PER_X86_INSTRUCTION). This sequence is used to run
172 * a (debug) test of the disassembler.
173 */
174 static uint8_t FLAGS_decode_instruction[NACL_MAX_BYTES_PER_X86_INSTRUCTION];
175
176 /* Define the number of bytes supplied for a debug instruction. */
177 static int FLAGS_decode_instruction_size = 0;
178
179 /* Flag defining the value of the pc to use when decoding an instruction
180 * through decode_instruction.
181 */
182 static uint32_t FLAGS_decode_pc = 0;
183
184 /* Flag defining an input file to use as command line arguments
185 * (one per input line). When specified, run the disassembler
186 * on each command line. The empty string "" denotes that no command
187 * line file was specified. A dash ("-") denotes that standard input
188 * should be used to get command line arguments.
189 */
190 static char* FLAGS_commands = "";
191
192 /* Flag defining the name of a hex text to be used as the code segment. Assumes
193 * that the pc associated with the code segment is defined by
194 * FLAGS_decode_pc.
195 */
196 static char* FLAGS_hex_text = "";
197
198 /* Flag, when used in combination with the commands flag, will turn
199 * on input copy rules, making the genrated output contain comments
200 * and the command line arguments as part of the corresponding
201 * generated output. For more details on this, see ProcessInputFile
202 * below.
203 */
204 static Bool FLAGS_self_document = FALSE;
205
206 /*
207 * Store default values of flags on the first call. On subsequent
208 * calls, resets the flags to the default value.
209 *
210 * *WARNING* In order for this to work, this function must be
211 * called before GrokFlags
212 *
213 * NOTE: we only allow the specification of -use_iter at the top-level
214 * command line..
215 */
216 static void ResetFlags(void) {
217 int i;
218 static uint32_t DEFAULT_decode_pc;
219 static char* DEFAULT_commands;
220 static Bool DEFAULT_self_document;
221 static Bool is_first_call = TRUE;
222 if (is_first_call) {
223 DEFAULT_decode_pc = FLAGS_decode_pc;
224 DEFAULT_commands = FLAGS_commands;
225 DEFAULT_self_document = FLAGS_self_document;
226 is_first_call = FALSE;
227 }
228
229 FLAGS_decode_pc = DEFAULT_decode_pc;
230 FLAGS_commands = DEFAULT_commands;
231 FLAGS_self_document = DEFAULT_self_document;
232 /* Always clear the decode instruction. */
233 FLAGS_decode_instruction_size = 0;
234 for (i = 0; i < NACL_MAX_BYTES_PER_X86_INSTRUCTION; ++i) {
235 FLAGS_decode_instruction[i] = 0;
236 }
237 }
238
239 /* Returns true if all characters in the string are zero. */
240 static Bool IsZero(const char* arg) {
241 while (*arg) {
242 if ('0' != *arg) {
243 return FALSE;
244 }
245 ++arg;
246 }
247 return TRUE;
248 }
249
250 uint8_t HexToByte(const char* hex_value) {
251 unsigned long value = strtoul(hex_value, NULL, 16);
252 /* Verify that arg is all zeros when zero is returned. Otherwise,
253 * assume that the zero value was due to an error.
254 */
255 if (0L == value && !IsZero(hex_value)) {
256 Fatal("-i option specifies illegal hex value '%s'\n", hex_value);
257 }
258 return (uint8_t) value;
259 }
260
261 /* Recognizes flags in argv, processes them, and then removes them.
262 * Returns the updated value for argc.
263 */
264 int GrokFlags(int argc, const char *argv[]) {
265 int i;
266 int new_argc;
267 char* hex_instruction;
268 Bool help = FALSE;
269 if (argc == 0) return 0;
270 exec_name = argv[0];
271 new_argc = 1;
272 for (i = 1; i < argc; ++i) {
273 const char* arg = argv[i];
274 if (GrokUint32HexFlag("--pc", arg, &FLAGS_decode_pc) ||
275 GrokCstringFlag("--commands", arg, &FLAGS_commands) ||
276 GrokCstringFlag("--hex_text", arg, &FLAGS_hex_text) ||
277 GrokBoolFlag("--self_document", arg, &FLAGS_self_document) ||
278 GrokBoolFlag("--internal", arg, &NACL_FLAGS_internal) ||
279 GrokBoolFlag("--help", arg, &help)) {
280 if (help) usage();
281 } else if (GrokBoolFlag("--validator_decoder", arg,
282 &NACL_FLAGS_validator_decoder)) {
283 NACL_FLAGS_full_decoder = !NACL_FLAGS_validator_decoder;
284 } else if (GrokBoolFlag("--full_decoder", arg,
285 &NACL_FLAGS_full_decoder)) {
286 NACL_FLAGS_validator_decoder = !NACL_FLAGS_full_decoder;
287 } else if (GrokCstringFlag("-i", arg, &hex_instruction)) {
288 int i = 0;
289 char buffer[3];
290 char* buf = &(hex_instruction[0]);
291 buffer[2] = '\0';
292 while (*buf) {
293 buffer[i++] = *(buf++);
294 if (i == 2) {
295 uint8_t byte = HexToByte(buffer);
296 FLAGS_decode_instruction[FLAGS_decode_instruction_size++] = byte;
297 if (FLAGS_decode_instruction_size >
298 NACL_MAX_BYTES_PER_X86_INSTRUCTION) {
299 Fatal("-i=%s specifies too long of a hex value\n", hex_instruction);
300 }
301 i = 0;
302 }
303 }
304 if (i != 0) {
305 Fatal("-i=%s doesn't specify a sequence of bytes\n", hex_instruction);
306 }
307 } else {
308 argv[new_argc++] = argv[i];
309 }
310 }
311 return new_argc;
312 }
313
314 /* Process the command line arguments. */
315 static const char* GrokArgv(int argc, const char* argv[]) {
316 if (argc != 2) {
317 Fatal("no filename specified\n");
318 }
319 return argv[argc-1];
320 }
321
322 static void ProcessCommandLine(int argc, const char* argv[]);
323
324 /* Defines the maximum number of characters allowed on an input line
325 * of the input text defined by the commands command line option.
326 */
327 #define MAX_INPUT_LINE 4096
328
329 /* Defines the characters used as (token) separators to recognize command
330 * line arguments when processing lines of text in the text file specified
331 * by the commands command line option.
332 */
333 #define CL_SEPARATORS " \t\n"
334
335 /* Copies the text from the input line (which should be command line options),
336 * up to any trailing comments (i.e. the pound sign).
337 * input_line - The line of text to process.
338 * tokens - The extracted text from the input_line.
339 * max_length - The maximum length of input_line and tokens.
340 *
341 * Note: If input_line doesn't end with a null terminator, one is automatically
342 * inserted.
343 */
344 static void CopyCommandLineTokens(char* input_line,
345 char* token_text,
346 size_t max_length) {
347 size_t i;
348 for (i = 0; i < max_length; ++i) {
349 char ch;
350 if (max_length == i + 1) {
351 /* Be sure we end the string with a null terminator. */
352 input_line[i] = '\0';
353 }
354 ch = input_line[i];
355 token_text[i] = ch;
356 if (ch == '\0') return;
357 if (ch == '#') {
358 token_text[i] = '\0';
359 return;
360 }
361 }
362 }
363
364 /* Tokenize the given text to find command line arguments, and
365 * add them to the given list of command line arguments.
366 *
367 * *WARNING* This function will (destructively) modify the
368 * contents of token_text, by converting command line option
369 * separator characters into newlines.
370 */
371 static void ExtractTokensAndAddToArgv(
372 char* token_text,
373 int* argc,
374 const char* argv[]) {
375 /* Note: Assume that each command line argument corresponds to
376 * non-blank text, which is a HACK, but should be sufficient for
377 * what we need.
378 */
379 char* token = strtok(token_text, CL_SEPARATORS);
380 while (token != NULL) {
381 argv[(*argc)++] = token;
382 token = strtok(NULL, CL_SEPARATORS);
383 }
384 }
385
386 /* Print out the contents of text, up to the first occurence of the
387 * pound sign.
388 */
389 static void PrintUpToPound(const char text[]) {
390 int i;
391 struct Gio* g = NaClLogGetGio();
392 for (i = 0; i < MAX_INPUT_LINE; ++i) {
393 char ch = text[i];
394 switch (ch) {
395 case '#':
396 gprintf(g, "%c", ch);
397 return;
398 case '\0':
399 return;
400 default:
401 gprintf(g, "%c", ch);
402 break;
403 }
404 }
405 }
406
407 /* Reads the given text file and processes the command line options specified
408 * inside of it. Each line specifies a separate sequence of command line
409 * arguments to process.
410 *
411 * Note:
412 * (a) The '#' is used as a comment delimiter.
413 * (b) whitespace lines are ignored.
414 * (c) If flag --self_document is specified, comment lines and whitespace
415 * lines will automatically be copied to stdout. In addition, command
416 * line arguments will be copied to stdout before processing them.
417 * Further, if the command line arguments are followed by a comment,
418 * only text up to (and including) the '#' will be copied. This allows
419 * the input file to contain the (hopefully single lined) output that
420 * would be generated by the given command line arguments. Therefore,
421 * if set up correctly, the output of the disassembler (in this case)
422 * should be the same as the input file (making it easy to use the
423 * input file as the the corresponding GOLD file to test against).
424 */
425 static void ProcessInputFile(FILE* file) {
426 char input_line[MAX_INPUT_LINE];
427 const Bool self_document = FLAGS_self_document;
428 while (fgets(input_line, MAX_INPUT_LINE, file) != NULL) {
429 char token_text[MAX_INPUT_LINE];
430 const char* line_argv[MAX_INPUT_LINE];
431 int line_argc = 0;
432
433 /* Copy the input line (up to the first #) into token_text */
434 CopyCommandLineTokens(input_line, token_text, MAX_INPUT_LINE);
435
436 /* Tokenize the commands to build argv.
437 * Note: Since each token is separated by a blank,
438 * and the input is no more than MAX_INPUT_LINE,
439 * we know (without checking) that line_argc
440 * will not exceed MAX_INPUT_LINE.
441 */
442 line_argv[line_argc++] = exec_name;
443 ExtractTokensAndAddToArgv(token_text, &line_argc, line_argv);
444
445 /* Process the parsed input line. */
446 if (1 == line_argc) {
447 /* No command line arguments. */
448 if (self_document) {
449 printf("%s", input_line);
450 }
451 } else {
452 /* Process the tokenized command line. */
453 if (self_document) {
454 PrintUpToPound(input_line);
455 }
456 ProcessCommandLine(line_argc, line_argv);
457 }
458 }
459 ResetFlags();
460 }
461
462 /* Run the disassembler using the given command line arguments. */
463 static void ProcessCommandLine(int argc, const char* argv[]) {
464 int new_argc;
465
466 ResetFlags();
467 new_argc = GrokFlags(argc, argv);
468 if (FLAGS_decode_instruction_size > 0) {
469 /* Command line options specify an instruction to decode, run
470 * the disassembler on the instruction to print out the decoded
471 * results.
472 */
473 if (new_argc > 1) {
474 Fatal("unrecognized option '%s'\n", argv[1]);
475 }
476 NaClDisassembleSegment(FLAGS_decode_instruction, FLAGS_decode_pc,
477 FLAGS_decode_instruction_size,
478 NaClGetDisassembleFlags());
479 } else if (0 != strcmp(FLAGS_hex_text, "")) {
480 uint8_t bytes[MAX_INPUT_LINE];
481 size_t num_bytes;
482 NaClPcAddress pc;
483 if (0 == strcmp(FLAGS_hex_text, "-")) {
484 num_bytes = NaClReadHexTextWithPc(stdin, &pc, bytes, MAX_INPUT_LINE);
485 NaClDisassembleSegment(bytes, pc, (NaClMemorySize) num_bytes,
486 NaClGetDisassembleFlags());
487 } else {
488 FILE* input = fopen(FLAGS_hex_text, "r");
489 if (NULL == input) {
490 Fatal("Can't open hex text file: %s\n", FLAGS_hex_text);
491 }
492 num_bytes = NaClReadHexTextWithPc(input, &pc, bytes, MAX_INPUT_LINE);
493 fclose(input);
494 NaClDisassembleSegment(bytes, pc, (NaClMemorySize) num_bytes,
495 NaClGetDisassembleFlags());
496 }
497 } else if (0 != strcmp(FLAGS_commands, "")) {
498 /* Use the given input file to find command line arguments,
499 * and process.
500 */
501 if (0 == strcmp(FLAGS_commands, "-")) {
502 ProcessInputFile(stdin);
503 } else {
504 FILE* input = fopen(FLAGS_commands, "r");
505 if (NULL == input) {
506 Fatal("Can't open commands file: %s\n", FLAGS_commands);
507 }
508 ProcessInputFile(input);
509 fclose(input);
510 }
511 } else {
512 /* Command line should specify an executable to disassemble.
513 * Read the file and disassemble it.
514 */
515 ncfile *ncf;
516 const char* filename = GrokArgv(new_argc, argv);
517
518 Info("processing %s", filename);
519 ncf = nc_loadfile_depending(filename, NULL);
520 if (ncf == NULL) {
521 Fatal("nc_loadfile(%s): %s\n", filename, strerror(errno));
522 }
523
524 AnalyzeCodeSegments(ncf, filename);
525
526 nc_freefile(ncf);
527 }
528 }
529
530 int main(int argc, const char *argv[]) {
531 struct GioFile gout_file;
532 struct Gio* gout = (struct Gio*) &gout_file;
533 if (!GioFileRefCtor(&gout_file, stdout)) {
534 fprintf(stderr, "Unable to create gio file for stdout!\n");
535 return 1;
536 }
537 NaClLogModuleInitExtended(LOG_INFO, gout);
538 ProcessCommandLine(argc, argv);
539 NaClLogModuleFini();
540 GioFileDtor(gout);
541 return 0;
542 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698