| Index: src/trusted/validator_x86/ncdis.c
|
| diff --git a/src/trusted/validator_x86/ncdis.c b/src/trusted/validator_x86/ncdis.c
|
| deleted file mode 100644
|
| index 3e6c743c8a5782209ea9e626c44f021382e38a05..0000000000000000000000000000000000000000
|
| --- a/src/trusted/validator_x86/ncdis.c
|
| +++ /dev/null
|
| @@ -1,542 +0,0 @@
|
| -/*
|
| - * Copyright (c) 2011 The Native Client Authors. All rights reserved.
|
| - * Use of this source code is governed by a BSD-style license that can be
|
| - * found in the LICENSE file.
|
| - */
|
| -
|
| -/*
|
| - * ncdis.c - disassemble using NaCl decoder.
|
| - * Mostly for testing.
|
| - */
|
| -
|
| -
|
| -#ifndef NACL_TRUSTED_BUT_NOT_TCB
|
| -#error("This file is not meant for use in the TCB")
|
| -#endif
|
| -
|
| -#include <errno.h>
|
| -#include <stdarg.h>
|
| -#include <stdio.h>
|
| -#include <stdlib.h>
|
| -#include <string.h>
|
| -
|
| -#include "native_client/src/shared/gio/gio.h"
|
| -#include "native_client/src/shared/utils/types.h"
|
| -#include "native_client/src/shared/utils/flags.h"
|
| -#include "native_client/src/shared/platform/nacl_log.h"
|
| -#include "native_client/src/trusted/validator/ncfileutil.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/nc_inst_state.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/ncopcode_desc.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/nc_decode_tables.h"
|
| -#include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode_verbose.h"
|
| -#include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate_internaltypes.h"
|
| -#include "native_client/src/trusted/validator_x86/nc_read_segment.h"
|
| -#include "native_client/src/trusted/validator_x86/ncdis_segments.h"
|
| -
|
| -/* True if we should use the full decoder when decoding. */
|
| -/* TODO(karl): When the full_decoder is working for both the x86-32 and
|
| - * x86-64 platforms, change to use full decoder for both as default.
|
| - */
|
| -static Bool NACL_FLAGS_full_decoder =
|
| -#if NACL_TARGET_SUBARCH == 64
|
| - TRUE
|
| -#else
|
| - FALSE
|
| -#endif
|
| - ;
|
| -
|
| -/* True if we should use the validator decoder when decoding. */
|
| -static Bool NACL_FLAGS_validator_decoder =
|
| -#if NACL_TARGET_SUBARCH == 64
|
| - FALSE
|
| -#else
|
| - TRUE
|
| -#endif
|
| - ;
|
| -
|
| -/* True if we should print internal representations while decoding. */
|
| -static Bool NACL_FLAGS_internal = FALSE;
|
| -
|
| -/* The name of the executable that is being run. */
|
| -static const char* exec_name = "???";
|
| -
|
| -static void Fatal(const char *fmt, ...) {
|
| - FILE* fp = stdout;
|
| - va_list ap;
|
| - fprintf(fp, "Fatal: ");
|
| - va_start(ap, fmt);
|
| - vfprintf(fp, fmt, ap);
|
| - va_end(ap);
|
| - exit(-1);
|
| -}
|
| -
|
| -void Info(const char *fmt, ...) {
|
| - FILE* fp = stdout;
|
| - va_list ap;
|
| - fprintf(fp, "Info: ");
|
| - va_start(ap, fmt);
|
| - vfprintf(fp, fmt, ap);
|
| - va_end(ap);
|
| -}
|
| -
|
| -static void usage(void) {
|
| - fprintf(stderr,
|
| - "usage: ncdis [options] [file]\n"
|
| - "\n"
|
| - "Options are:\n"
|
| - "--commands=<file>\n"
|
| - "\tAdditional command line arguments are specified in the given\n"
|
| - "\tfile ('#' acts as a comment character). Use '-' as its value to\n"
|
| - "\tredirect command line arguments from standard input.\n"
|
| - "--full_decoder\n"
|
| - "\tDisassemble the elf executable using native client's\n"
|
| - "\tfull decoder.\n"
|
| - "--help\n"
|
| - "\tPrint out this usage message\n"
|
| - "--hex_text=<file>\n"
|
| - "\tDefine code section as sequence of (textual) hexidecimal bytes\n"
|
| - "\tdefined in the given file. Lines beginning with '#' will be\n"
|
| - "\treated as comments. If the first non-comment line begins with\n"
|
| - "\t'@' the following hexidecimal number will be used as the\n"
|
| - "\tbeginning (RIP/EIP) instruction address of the code segment.\n"
|
| - "\tUse '-' as its value to redirect standard input as the\n"
|
| - "\ttext file to process.\n"
|
| - "-i=XXXX\n"
|
| - "\tXXXX specifies the sequence of hexidecimal digits that define\n"
|
| - "\tan instruction to be decoded.\n"
|
| - "--internal\n"
|
| - "\tFor the iterator model (only), prints out each the decoded\n"
|
| - "\tinstruction, followed by the internals for the matched\n"
|
| - "\tinstruction.\n"
|
| - "--pc=XXX\n"
|
| - "\tSet program counter (i.e. RIP or EIP) to XXX.\n"
|
| - "--self_document\n"
|
| - "\tProcess input hext_text file in such a way, that it also\n"
|
| - "\trepresents the output that will be generated by ncdis.\n"
|
| - "\tThat is, copy comment lines (i.e. lines beginning with\n"
|
| - "\t'#') to stdout. In addition, it assumes that each line\n"
|
| - "\tconsists of an '-i' command line argument (and possibly\n"
|
| - "\ta '--pc' command line argument, followed by a '#',\n"
|
| - "\tfollowed by the corresponding disassembled text. On such\n"
|
| - "\tlines, the input is copied up to (and including) the '#'.,\n"
|
| - "\tand then the disassembled instruction is printed.\n"
|
| - "--validator_decoder\n"
|
| - "\tDisassemble the file using the partial instruction decoder used\n"
|
| - "\tby the validator.\n"
|
| - );
|
| - exit(1);
|
| -}
|
| -
|
| -/* Converts command line flags to corresponding disassemble flags. */
|
| -static NaClDisassembleFlags NaClGetDisassembleFlags(void) {
|
| - NaClDisassembleFlags flags = 0;
|
| - if (NACL_FLAGS_validator_decoder) {
|
| - NaClAddBits(flags, NACL_DISASSEMBLE_FLAG(NaClDisassembleValidatorDecoder));
|
| - }
|
| - if (NACL_FLAGS_full_decoder) {
|
| - NaClAddBits(flags, NACL_DISASSEMBLE_FLAG(NaClDisassembleFull));
|
| - }
|
| - if (NACL_FLAGS_internal) {
|
| - NaClAddBits(flags, NACL_DISASSEMBLE_FLAG(NaClDisassembleAddInternals));
|
| - }
|
| - return flags;
|
| -}
|
| -
|
| -static int AnalyzeSections(ncfile *ncf) {
|
| - int badsections = 0;
|
| - int ii;
|
| - const Elf_Shdr* shdr = ncf->sheaders;
|
| -
|
| - for (ii = 0; ii < ncf->shnum; ii++) {
|
| - Info("section %d sh_addr %x offset %x flags %x\n",
|
| - ii, (uint32_t)shdr[ii].sh_addr,
|
| - (uint32_t)shdr[ii].sh_offset, (uint32_t)shdr[ii].sh_flags);
|
| - if ((shdr[ii].sh_flags & SHF_EXECINSTR) != SHF_EXECINSTR)
|
| - continue;
|
| - Info("parsing section %d\n", ii);
|
| - NaClDisassembleSegment(ncf->data + (shdr[ii].sh_addr - ncf->vbase),
|
| - shdr[ii].sh_addr, shdr[ii].sh_size,
|
| - NaClGetDisassembleFlags());
|
| - }
|
| - return -badsections;
|
| -}
|
| -
|
| -static void AnalyzeCodeSegments(ncfile *ncf, const char *fname) {
|
| - if (AnalyzeSections(ncf) < 0) {
|
| - fprintf(stderr, "%s: text validate failed\n", fname);
|
| - }
|
| -}
|
| -
|
| -/* Capture a sequence of bytes defining an instruction (up to a
|
| - * MAX_BYTES_PER_X86_INSTRUCTION). This sequence is used to run
|
| - * a (debug) test of the disassembler.
|
| - */
|
| -static uint8_t FLAGS_decode_instruction[NACL_MAX_BYTES_PER_X86_INSTRUCTION];
|
| -
|
| -/* Define the number of bytes supplied for a debug instruction. */
|
| -static int FLAGS_decode_instruction_size = 0;
|
| -
|
| -/* Flag defining the value of the pc to use when decoding an instruction
|
| - * through decode_instruction.
|
| - */
|
| -static uint32_t FLAGS_decode_pc = 0;
|
| -
|
| -/* Flag defining an input file to use as command line arguments
|
| - * (one per input line). When specified, run the disassembler
|
| - * on each command line. The empty string "" denotes that no command
|
| - * line file was specified. A dash ("-") denotes that standard input
|
| - * should be used to get command line arguments.
|
| - */
|
| -static char* FLAGS_commands = "";
|
| -
|
| -/* Flag defining the name of a hex text to be used as the code segment. Assumes
|
| - * that the pc associated with the code segment is defined by
|
| - * FLAGS_decode_pc.
|
| - */
|
| -static char* FLAGS_hex_text = "";
|
| -
|
| -/* Flag, when used in combination with the commands flag, will turn
|
| - * on input copy rules, making the genrated output contain comments
|
| - * and the command line arguments as part of the corresponding
|
| - * generated output. For more details on this, see ProcessInputFile
|
| - * below.
|
| - */
|
| -static Bool FLAGS_self_document = FALSE;
|
| -
|
| -/*
|
| - * Store default values of flags on the first call. On subsequent
|
| - * calls, resets the flags to the default value.
|
| - *
|
| - * *WARNING* In order for this to work, this function must be
|
| - * called before GrokFlags
|
| - *
|
| - * NOTE: we only allow the specification of -use_iter at the top-level
|
| - * command line..
|
| - */
|
| -static void ResetFlags(void) {
|
| - int i;
|
| - static uint32_t DEFAULT_decode_pc;
|
| - static char* DEFAULT_commands;
|
| - static Bool DEFAULT_self_document;
|
| - static Bool is_first_call = TRUE;
|
| - if (is_first_call) {
|
| - DEFAULT_decode_pc = FLAGS_decode_pc;
|
| - DEFAULT_commands = FLAGS_commands;
|
| - DEFAULT_self_document = FLAGS_self_document;
|
| - is_first_call = FALSE;
|
| - }
|
| -
|
| - FLAGS_decode_pc = DEFAULT_decode_pc;
|
| - FLAGS_commands = DEFAULT_commands;
|
| - FLAGS_self_document = DEFAULT_self_document;
|
| - /* Always clear the decode instruction. */
|
| - FLAGS_decode_instruction_size = 0;
|
| - for (i = 0; i < NACL_MAX_BYTES_PER_X86_INSTRUCTION; ++i) {
|
| - FLAGS_decode_instruction[i] = 0;
|
| - }
|
| -}
|
| -
|
| -/* Returns true if all characters in the string are zero. */
|
| -static Bool IsZero(const char* arg) {
|
| - while (*arg) {
|
| - if ('0' != *arg) {
|
| - return FALSE;
|
| - }
|
| - ++arg;
|
| - }
|
| - return TRUE;
|
| -}
|
| -
|
| -uint8_t HexToByte(const char* hex_value) {
|
| - unsigned long value = strtoul(hex_value, NULL, 16);
|
| - /* Verify that arg is all zeros when zero is returned. Otherwise,
|
| - * assume that the zero value was due to an error.
|
| - */
|
| - if (0L == value && !IsZero(hex_value)) {
|
| - Fatal("-i option specifies illegal hex value '%s'\n", hex_value);
|
| - }
|
| - return (uint8_t) value;
|
| -}
|
| -
|
| -/* Recognizes flags in argv, processes them, and then removes them.
|
| - * Returns the updated value for argc.
|
| - */
|
| -int GrokFlags(int argc, const char *argv[]) {
|
| - int i;
|
| - int new_argc;
|
| - char* hex_instruction;
|
| - Bool help = FALSE;
|
| - if (argc == 0) return 0;
|
| - exec_name = argv[0];
|
| - new_argc = 1;
|
| - for (i = 1; i < argc; ++i) {
|
| - const char* arg = argv[i];
|
| - if (GrokUint32HexFlag("--pc", arg, &FLAGS_decode_pc) ||
|
| - GrokCstringFlag("--commands", arg, &FLAGS_commands) ||
|
| - GrokCstringFlag("--hex_text", arg, &FLAGS_hex_text) ||
|
| - GrokBoolFlag("--self_document", arg, &FLAGS_self_document) ||
|
| - GrokBoolFlag("--internal", arg, &NACL_FLAGS_internal) ||
|
| - GrokBoolFlag("--help", arg, &help)) {
|
| - if (help) usage();
|
| - } else if (GrokBoolFlag("--validator_decoder", arg,
|
| - &NACL_FLAGS_validator_decoder)) {
|
| - NACL_FLAGS_full_decoder = !NACL_FLAGS_validator_decoder;
|
| - } else if (GrokBoolFlag("--full_decoder", arg,
|
| - &NACL_FLAGS_full_decoder)) {
|
| - NACL_FLAGS_validator_decoder = !NACL_FLAGS_full_decoder;
|
| - } else if (GrokCstringFlag("-i", arg, &hex_instruction)) {
|
| - int i = 0;
|
| - char buffer[3];
|
| - char* buf = &(hex_instruction[0]);
|
| - buffer[2] = '\0';
|
| - while (*buf) {
|
| - buffer[i++] = *(buf++);
|
| - if (i == 2) {
|
| - uint8_t byte = HexToByte(buffer);
|
| - FLAGS_decode_instruction[FLAGS_decode_instruction_size++] = byte;
|
| - if (FLAGS_decode_instruction_size >
|
| - NACL_MAX_BYTES_PER_X86_INSTRUCTION) {
|
| - Fatal("-i=%s specifies too long of a hex value\n", hex_instruction);
|
| - }
|
| - i = 0;
|
| - }
|
| - }
|
| - if (i != 0) {
|
| - Fatal("-i=%s doesn't specify a sequence of bytes\n", hex_instruction);
|
| - }
|
| - } else {
|
| - argv[new_argc++] = argv[i];
|
| - }
|
| - }
|
| - return new_argc;
|
| -}
|
| -
|
| -/* Process the command line arguments. */
|
| -static const char* GrokArgv(int argc, const char* argv[]) {
|
| - if (argc != 2) {
|
| - Fatal("no filename specified\n");
|
| - }
|
| - return argv[argc-1];
|
| -}
|
| -
|
| -static void ProcessCommandLine(int argc, const char* argv[]);
|
| -
|
| -/* Defines the maximum number of characters allowed on an input line
|
| - * of the input text defined by the commands command line option.
|
| - */
|
| -#define MAX_INPUT_LINE 4096
|
| -
|
| -/* Defines the characters used as (token) separators to recognize command
|
| - * line arguments when processing lines of text in the text file specified
|
| - * by the commands command line option.
|
| - */
|
| -#define CL_SEPARATORS " \t\n"
|
| -
|
| -/* Copies the text from the input line (which should be command line options),
|
| - * up to any trailing comments (i.e. the pound sign).
|
| - * input_line - The line of text to process.
|
| - * tokens - The extracted text from the input_line.
|
| - * max_length - The maximum length of input_line and tokens.
|
| - *
|
| - * Note: If input_line doesn't end with a null terminator, one is automatically
|
| - * inserted.
|
| - */
|
| -static void CopyCommandLineTokens(char* input_line,
|
| - char* token_text,
|
| - size_t max_length) {
|
| - size_t i;
|
| - for (i = 0; i < max_length; ++i) {
|
| - char ch;
|
| - if (max_length == i + 1) {
|
| - /* Be sure we end the string with a null terminator. */
|
| - input_line[i] = '\0';
|
| - }
|
| - ch = input_line[i];
|
| - token_text[i] = ch;
|
| - if (ch == '\0') return;
|
| - if (ch == '#') {
|
| - token_text[i] = '\0';
|
| - return;
|
| - }
|
| - }
|
| -}
|
| -
|
| -/* Tokenize the given text to find command line arguments, and
|
| - * add them to the given list of command line arguments.
|
| - *
|
| - * *WARNING* This function will (destructively) modify the
|
| - * contents of token_text, by converting command line option
|
| - * separator characters into newlines.
|
| - */
|
| -static void ExtractTokensAndAddToArgv(
|
| - char* token_text,
|
| - int* argc,
|
| - const char* argv[]) {
|
| - /* Note: Assume that each command line argument corresponds to
|
| - * non-blank text, which is a HACK, but should be sufficient for
|
| - * what we need.
|
| - */
|
| - char* token = strtok(token_text, CL_SEPARATORS);
|
| - while (token != NULL) {
|
| - argv[(*argc)++] = token;
|
| - token = strtok(NULL, CL_SEPARATORS);
|
| - }
|
| -}
|
| -
|
| -/* Print out the contents of text, up to the first occurence of the
|
| - * pound sign.
|
| - */
|
| -static void PrintUpToPound(const char text[]) {
|
| - int i;
|
| - struct Gio* g = NaClLogGetGio();
|
| - for (i = 0; i < MAX_INPUT_LINE; ++i) {
|
| - char ch = text[i];
|
| - switch (ch) {
|
| - case '#':
|
| - gprintf(g, "%c", ch);
|
| - return;
|
| - case '\0':
|
| - return;
|
| - default:
|
| - gprintf(g, "%c", ch);
|
| - break;
|
| - }
|
| - }
|
| -}
|
| -
|
| -/* Reads the given text file and processes the command line options specified
|
| - * inside of it. Each line specifies a separate sequence of command line
|
| - * arguments to process.
|
| - *
|
| - * Note:
|
| - * (a) The '#' is used as a comment delimiter.
|
| - * (b) whitespace lines are ignored.
|
| - * (c) If flag --self_document is specified, comment lines and whitespace
|
| - * lines will automatically be copied to stdout. In addition, command
|
| - * line arguments will be copied to stdout before processing them.
|
| - * Further, if the command line arguments are followed by a comment,
|
| - * only text up to (and including) the '#' will be copied. This allows
|
| - * the input file to contain the (hopefully single lined) output that
|
| - * would be generated by the given command line arguments. Therefore,
|
| - * if set up correctly, the output of the disassembler (in this case)
|
| - * should be the same as the input file (making it easy to use the
|
| - * input file as the the corresponding GOLD file to test against).
|
| - */
|
| -static void ProcessInputFile(FILE* file) {
|
| - char input_line[MAX_INPUT_LINE];
|
| - const Bool self_document = FLAGS_self_document;
|
| - while (fgets(input_line, MAX_INPUT_LINE, file) != NULL) {
|
| - char token_text[MAX_INPUT_LINE];
|
| - const char* line_argv[MAX_INPUT_LINE];
|
| - int line_argc = 0;
|
| -
|
| - /* Copy the input line (up to the first #) into token_text */
|
| - CopyCommandLineTokens(input_line, token_text, MAX_INPUT_LINE);
|
| -
|
| - /* Tokenize the commands to build argv.
|
| - * Note: Since each token is separated by a blank,
|
| - * and the input is no more than MAX_INPUT_LINE,
|
| - * we know (without checking) that line_argc
|
| - * will not exceed MAX_INPUT_LINE.
|
| - */
|
| - line_argv[line_argc++] = exec_name;
|
| - ExtractTokensAndAddToArgv(token_text, &line_argc, line_argv);
|
| -
|
| - /* Process the parsed input line. */
|
| - if (1 == line_argc) {
|
| - /* No command line arguments. */
|
| - if (self_document) {
|
| - printf("%s", input_line);
|
| - }
|
| - } else {
|
| - /* Process the tokenized command line. */
|
| - if (self_document) {
|
| - PrintUpToPound(input_line);
|
| - }
|
| - ProcessCommandLine(line_argc, line_argv);
|
| - }
|
| - }
|
| - ResetFlags();
|
| -}
|
| -
|
| -/* Run the disassembler using the given command line arguments. */
|
| -static void ProcessCommandLine(int argc, const char* argv[]) {
|
| - int new_argc;
|
| -
|
| - ResetFlags();
|
| - new_argc = GrokFlags(argc, argv);
|
| - if (FLAGS_decode_instruction_size > 0) {
|
| - /* Command line options specify an instruction to decode, run
|
| - * the disassembler on the instruction to print out the decoded
|
| - * results.
|
| - */
|
| - if (new_argc > 1) {
|
| - Fatal("unrecognized option '%s'\n", argv[1]);
|
| - }
|
| - NaClDisassembleSegment(FLAGS_decode_instruction, FLAGS_decode_pc,
|
| - FLAGS_decode_instruction_size,
|
| - NaClGetDisassembleFlags());
|
| - } else if (0 != strcmp(FLAGS_hex_text, "")) {
|
| - uint8_t bytes[MAX_INPUT_LINE];
|
| - size_t num_bytes;
|
| - NaClPcAddress pc;
|
| - if (0 == strcmp(FLAGS_hex_text, "-")) {
|
| - num_bytes = NaClReadHexTextWithPc(stdin, &pc, bytes, MAX_INPUT_LINE);
|
| - NaClDisassembleSegment(bytes, pc, (NaClMemorySize) num_bytes,
|
| - NaClGetDisassembleFlags());
|
| - } else {
|
| - FILE* input = fopen(FLAGS_hex_text, "r");
|
| - if (NULL == input) {
|
| - Fatal("Can't open hex text file: %s\n", FLAGS_hex_text);
|
| - }
|
| - num_bytes = NaClReadHexTextWithPc(input, &pc, bytes, MAX_INPUT_LINE);
|
| - fclose(input);
|
| - NaClDisassembleSegment(bytes, pc, (NaClMemorySize) num_bytes,
|
| - NaClGetDisassembleFlags());
|
| - }
|
| - } else if (0 != strcmp(FLAGS_commands, "")) {
|
| - /* Use the given input file to find command line arguments,
|
| - * and process.
|
| - */
|
| - if (0 == strcmp(FLAGS_commands, "-")) {
|
| - ProcessInputFile(stdin);
|
| - } else {
|
| - FILE* input = fopen(FLAGS_commands, "r");
|
| - if (NULL == input) {
|
| - Fatal("Can't open commands file: %s\n", FLAGS_commands);
|
| - }
|
| - ProcessInputFile(input);
|
| - fclose(input);
|
| - }
|
| - } else {
|
| - /* Command line should specify an executable to disassemble.
|
| - * Read the file and disassemble it.
|
| - */
|
| - ncfile *ncf;
|
| - const char* filename = GrokArgv(new_argc, argv);
|
| -
|
| - Info("processing %s", filename);
|
| - ncf = nc_loadfile_depending(filename, NULL);
|
| - if (ncf == NULL) {
|
| - Fatal("nc_loadfile(%s): %s\n", filename, strerror(errno));
|
| - }
|
| -
|
| - AnalyzeCodeSegments(ncf, filename);
|
| -
|
| - nc_freefile(ncf);
|
| - }
|
| -}
|
| -
|
| -int main(int argc, const char *argv[]) {
|
| - struct GioFile gout_file;
|
| - struct Gio* gout = (struct Gio*) &gout_file;
|
| - if (!GioFileRefCtor(&gout_file, stdout)) {
|
| - fprintf(stderr, "Unable to create gio file for stdout!\n");
|
| - return 1;
|
| - }
|
| - NaClLogModuleInitExtended(LOG_INFO, gout);
|
| - ProcessCommandLine(argc, argv);
|
| - NaClLogModuleFini();
|
| - GioFileDtor(gout);
|
| - return 0;
|
| -}
|
|
|