Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / validator_x86 / ncdis.c
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_internaltypes.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 }