Index: src/trusted/validator_x86/ncval.c |
diff --git a/src/trusted/validator_x86/ncval.c b/src/trusted/validator_x86/ncval.c |
deleted file mode 100644 |
index 86e41d38499c0a72cda359da37c52a28ef6965a3..0000000000000000000000000000000000000000 |
--- a/src/trusted/validator_x86/ncval.c |
+++ /dev/null |
@@ -1,954 +0,0 @@ |
-/* |
- * Copyright (c) 2012 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. |
- */ |
- |
-/* |
- * ncval.c - command line validator for NaCl. |
- * Mostly for testing. |
- */ |
- |
- |
-#ifndef NACL_TRUSTED_BUT_NOT_TCB |
-#error("This file is not meant for use in the TCB") |
-#endif |
- |
-#include "native_client/src/include/portability.h" |
- |
-#include <stdio.h> |
-#include <stdlib.h> |
-#include <stdarg.h> |
-#include <string.h> |
-#include <errno.h> |
-#include <sys/timeb.h> |
-#include <time.h> |
-#include "native_client/src/include/nacl_macros.h" |
-#include "native_client/src/shared/gio/gio.h" |
-#include "native_client/src/shared/platform/nacl_log.h" |
-#include "native_client/src/shared/utils/flags.h" |
-#include "native_client/src/trusted/validator/ncfileutil.h" |
-#include "native_client/src/trusted/cpu_features/arch/x86/cpu_x86.h" |
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter.h" |
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter_internal.h" |
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter_detailed.h" |
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_jumps.h" |
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_opcode_histogram.h" |
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_memory_protect.h" |
-#include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.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.h" |
-#include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate_detailed.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" |
- |
-#if NACL_TARGET_SUBARCH == 64 |
-#include "native_client/src/trusted/validator/x86/decoder/nc_decode_tables.h" |
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncval_decode_tables.h" |
-#include "native_client/src/trusted/validator_x86/ncdis_decode_tables.h" |
-#endif |
- |
-/* To turn on debugging of instruction decoding, change value of |
- * DEBUGGING to 1. |
- */ |
-#define DEBUGGING 0 |
- |
-#include "native_client/src/shared/utils/debugging.h" |
- |
-/* Forward declarations. */ |
-static void usage(int exit_code); |
- |
-#if NACL_TARGET_SUBARCH == 32 |
-/* Flag defining if statistics should be printed for callback validator |
- * model. |
- */ |
-static Bool NACL_FLAGS_stats_print = FALSE; |
-#endif |
- |
-/* Flag defining if detailed error messages should be generated. When |
- * false, runs performance model as used by sel_ldr. |
- */ |
-static Bool NACL_FLAGS_detailed_errors = TRUE; |
- |
-/* Flag defining the name of a hex text to be used as the code segment. |
- */ |
-static char *NACL_FLAGS_hex_text = ""; |
- |
-/* Define if we should process segments (rather than sections) when applying SFI |
- * validator. |
- */ |
-static Bool NACL_FLAGS_analyze_segments = FALSE; |
- |
-/* Define how many times we will analyze the code segment. |
- * Note: Values, other than 1, is only used for profiling. |
- */ |
-static int NACL_FLAGS_validate_attempts = 1; |
- |
-/* Define the set of CPU features to use while validating. */ |
-static NaClCPUFeaturesX86 ncval_cpu_features; |
- |
-/* Define whether timing should be applied when running the validator. */ |
-static Bool NACL_FLAGS_print_timing = FALSE; |
- |
-/* Define what level of errors will be printed. |
- * Note: If multiple flags are true, the one with |
- * the highest severity will be selected. |
- */ |
-static Bool NACL_FLAGS_warnings = FALSE; |
-static Bool NACL_FLAGS_errors = FALSE; |
-static Bool NACL_FLAGS_fatal = FALSE; |
- |
-/* Define if special stubout tests should be run. Such |
- * tests apply stubout, and then print out the modified |
- * disassembled code. |
- */ |
-static Bool NACL_FLAGS_stubout_memory = FALSE; |
- |
-#if NACL_TARGET_SUBARCH == 64 |
-/* Flag that allows validator decoder to be used in place of full decoder. |
- */ |
-static Bool NACL_FLAGS_validator_decoder = FALSE; |
-#endif |
- |
-/* Generates NaClErrorMapping for error level suffix. */ |
-#define NaClError(s) { #s , LOG_## s} |
- |
-/************************************************** |
- * Driver to apply the validator to a code segment |
- *************************************************/ |
- |
-/* Reports if named module is safe. */ |
-static void NaClReportFileSafety(Bool success, const char *fname) { |
- if (NACL_FLAGS_stubout_memory) { |
- /* The validator has been run to test stubbing out. Stubbing out, |
- * in this tool, means replacing instructions (modeled using hex |
- * text) that are unsafe and rejected by the validator, and are |
- * replaced with HALT instructions. |
- */ |
- NaClLog(LOG_INFO, "STUBBED OUT as follows:\n"); |
- } else { |
-#ifndef NCVAL_TESTING |
- if (success) { |
- NaClLog(LOG_INFO, "*** %s is safe ***\n", fname); |
- } else { |
- NaClLog(LOG_INFO, "*** %s IS UNSAFE ***\n", fname); |
- } |
-#endif |
- } |
-} |
- |
-/* Reports if module is safe. */ |
-static void NaClReportSafety(Bool success, |
- const char* filename) { |
- if (0 != strcmp(NACL_FLAGS_hex_text, "")) { |
- /* Special hex text processing, rather than filename. */ |
- if (0 == strcmp(NACL_FLAGS_hex_text, "-")) { |
- NaClReportFileSafety(success, "<input>"); |
- return; |
- } |
- } |
- NaClReportFileSafety(success, filename); |
-} |
- |
-/* The model of data to be passed to the load/analyze steps. */ |
-typedef void* NaClRunValidatorData; |
- |
-/* The routine that loads the code segment(s) into memory (within |
- * the data arg). Returns true iff load was successful. |
- */ |
-typedef Bool (*NaClValidateLoad)(int argc, const char* argv[], |
- NaClRunValidatorData data); |
- |
-/* The actual validation analysis, applied to the data returned by |
- * ValidateLoad. Assume that this function also deallocates any memory |
- * in loaded_data. Returns true iff analysis doesn't find any problems. |
- */ |
-typedef Bool (*NaClValidateAnalyze)(NaClRunValidatorData data); |
- |
-/* Runs the validator using the given (command line) arguments. |
- * |
- * Parameters: |
- * data - The model of data to be passed to the load/analyze steps. |
- * Allows top-level call to pass control information |
- * to the load and analyze functions, and between these |
- * two functions. |
- * load - The function to load in the data needed to validate. |
- * analyze - The function to call to do validator analysis once |
- * the data has been read in. |
- */ |
-static Bool NaClRunValidator(int argc, const char* argv[], |
- NaClRunValidatorData data, |
- NaClValidateLoad load, |
- NaClValidateAnalyze analyze) { |
- clock_t clock_0; |
- clock_t clock_l; |
- clock_t clock_v; |
- Bool return_value; |
- |
- clock_0 = clock(); |
- return_value = load(argc, argv, data); |
- if (!return_value) { |
- NaClValidatorMessage(LOG_ERROR, NULL, "Unable to load code to validate\n"); |
- return FALSE; |
- } |
- clock_l = clock(); |
- return_value = analyze(data); |
- clock_v = clock(); |
- |
- if (NACL_FLAGS_print_timing) { |
- NaClValidatorMessage( |
- LOG_INFO, NULL, |
- "load time: %0.6f analysis time: %0.6f\n", |
- (double)(clock_l - clock_0) / (double)CLOCKS_PER_SEC, |
- (double)(clock_v - clock_l) / (double)CLOCKS_PER_SEC); |
- } |
- return return_value; |
-} |
- |
-/* Default loader that does nothing. Typically this is because |
- * the data argument already contains the bytes to validate. |
- */ |
-Bool NaClValidateNoLoad(int argc, const char* argv[], |
- NaClRunValidatorData data) { |
- return TRUE; |
-} |
- |
-/* Local file data for validator run. */ |
-typedef struct ValidateData { |
- /* The name of the elf file to validate. */ |
- const char *fname; |
- /* The elf file to validate. */ |
- ncfile *ncf; |
-} ValidateData; |
- |
-/* Load the elf file and return the loaded elf file. */ |
-static Bool ValidateElfLoad(int argc, const char *argv[], |
- ValidateData *data) { |
- if (argc != 2) { |
- NaClLog(LOG_ERROR, "expected: %s file\n", argv[0]); |
- usage(2); |
- } |
- data->fname = argv[1]; |
- |
- /* TODO(karl): Once we fix elf values put in by compiler, so that |
- * we no longer get load errors from ncfilutil.c, find a way to |
- * terminate early if errors occur during loading. |
- */ |
- data->ncf = nc_loadfile(data->fname); |
- if (data->ncf == NULL) { |
- NaClLog(LOG_ERROR, "nc_loadfile(%s): %s\n", data->fname, strerror(errno)); |
- usage(2); |
- } |
- return NULL != data->ncf; |
-} |
- |
-/*************************************************** |
- * Code to run SFI validator on hex text examples. * |
- ***************************************************/ |
- |
-/* Defines the maximum number of characters allowed on an input line |
- * of the input text defined by the commands command line option. |
- */ |
-#define NACL_MAX_INPUT_LINE 4096 |
- |
-typedef struct NaClValidatorByteArray { |
- uint8_t bytes[NACL_MAX_INPUT_LINE]; |
- NaClPcAddress base; |
- NaClMemorySize num_bytes; |
-} NaClValidatorByteArray; |
- |
-static void HexFatal(const char *format, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2); |
- |
-/* Print out given error message about the hex input file, and then exit. */ |
-static void HexFatal(const char *format, ...) { |
- va_list ap; |
- va_start(ap, format); |
- NaClLogV(LOG_ERROR, format, ap); |
- va_end(ap); |
- /* always succed, so that the testing framework works. */ |
- exit(0); |
-} |
- |
-/* Load the hex input file from the given command line arguments, |
- * and put it into the given data structure. |
- */ |
-static int ValidateHexLoad(int argc, const char *argv[], |
- NaClValidatorByteArray *data) { |
- if (argc != 1) { |
- HexFatal("expected: %s <options>\n", argv[0]); |
- } |
- if (0 == strcmp(NACL_FLAGS_hex_text, "-")) { |
- data->num_bytes = (NaClMemorySize) |
- NaClReadHexTextWithPc(stdin, &data->base, data->bytes, |
- NACL_MAX_INPUT_LINE); |
- } else { |
- FILE *input = fopen(NACL_FLAGS_hex_text, "r"); |
- if (NULL == input) { |
- HexFatal("Can't open hex text file: %s\n", NACL_FLAGS_hex_text); |
- } |
- data->num_bytes = (NaClMemorySize) |
- NaClReadHexTextWithPc(input, &data->base, data->bytes, |
- NACL_MAX_INPUT_LINE); |
- fclose(input); |
- --argc; |
- } |
- return argc; |
-} |
- |
-#if NACL_TARGET_SUBARCH == 32 |
-/*************************************** |
- * Code to run segment based validator.* |
- ***************************************/ |
- |
-int AnalyzeSegmentSections(ncfile *ncf, struct NCValidatorState *vstate) { |
- int badsections = 0; |
- int ii; |
- const Elf_Phdr *phdr = ncf->pheaders; |
- |
- for (ii = 0; ii < ncf->phnum; ii++) { |
- NaClLog(LOG_INFO, |
- "segment[%d] p_type %"NACL_PRIdElf_Word |
- " p_offset %"NACL_PRIxElf_Off" vaddr %"NACL_PRIxElf_Addr |
- " paddr %"NACL_PRIxElf_Addr" align %"NACL_PRIuElf_Xword"\n", |
- ii, phdr[ii].p_type, phdr[ii].p_offset, |
- phdr[ii].p_vaddr, phdr[ii].p_paddr, |
- phdr[ii].p_align); |
- |
- NaClLog(LOG_INFO, |
- " filesz %"NACL_PRIxElf_Xword" memsz %"NACL_PRIxElf_Xword |
- " flags %"NACL_PRIxElf_Word"\n", |
- phdr[ii].p_filesz, phdr[ii].p_memsz, phdr[ii].p_flags); |
- if ((PT_LOAD != phdr[ii].p_type) || |
- (0 == (phdr[ii].p_flags & PF_X))) |
- continue; |
- NaClLog(LOG_INFO, "parsing segment %d\n", ii); |
- NCValidateSegment(ncf->data + (phdr[ii].p_vaddr - ncf->vbase), |
- phdr[ii].p_vaddr, phdr[ii].p_memsz, vstate); |
- } |
- return -badsections; |
-} |
- |
-/* Initialize segment validator, using detailed (summary) error |
- * messages if selected. |
- */ |
-struct NCValidatorState* NCValInit(const NaClPcAddress vbase, |
- const NaClMemorySize codesize) { |
- return NACL_FLAGS_detailed_errors |
- ? NCValidateInitDetailed(vbase, codesize, &ncval_cpu_features) |
- : NCValidateInit(vbase, codesize, FALSE, &ncval_cpu_features); |
-} |
- |
- |
-static Bool AnalyzeSegmentCodeSegments(ncfile *ncf, const char *fname) { |
- NaClPcAddress vbase, vlimit; |
- struct NCValidatorState *vstate; |
- Bool result; |
- |
- GetVBaseAndLimit(ncf, &vbase, &vlimit); |
- vstate = NCValInit(vbase, vlimit - vbase); |
- if (vstate == NULL) return FALSE; |
- NCValidateSetErrorReporter(vstate, &kNCVerboseErrorReporter); |
- if (AnalyzeSegmentSections(ncf, vstate) < 0) { |
- NaClLog(LOG_INFO, "%s: text validate failed\n", fname); |
- } |
- result = (0 == NCValidateFinish(vstate)) ? TRUE : FALSE; |
- NaClReportSafety(result, fname); |
- if (NACL_FLAGS_stats_print) NCStatsPrint(vstate); |
- NCValidateFreeState(&vstate); |
- NaClLog(LOG_INFO, "Validated %s\n", fname); |
- return result; |
-} |
-#endif |
- |
-#if NACL_TARGET_SUBARCH == 64 |
-/****************************** |
- * Code to run SFI validator. * |
- ******************************/ |
- |
-/* Define what should be used as the base register for |
- * memory accesses. |
- */ |
-static NaClOpKind nacl_base_register = |
- (64 == NACL_TARGET_SUBARCH ? RegR15 : RegUnknown); |
- |
-/* Create validator state using detailed (summary) error messages |
- * if selected. |
- */ |
-struct NaClValidatorState* NaClValStateCreate( |
- const NaClPcAddress vbase, |
- const NaClMemorySize sz, |
- const NaClOpKind base_register) { |
- return |
- NACL_FLAGS_detailed_errors |
- ? NaClValidatorStateCreateDetailed(vbase, sz, base_register, |
- &ncval_cpu_features) |
- : NaClValidatorStateCreate(vbase, sz, base_register, FALSE, |
- &ncval_cpu_features); |
-} |
- |
-/* Returns the decoder tables to use. */ |
-static const NaClDecodeTables* NaClGetDecoderTables(void) { |
- return NACL_FLAGS_validator_decoder |
- ? kNaClValDecoderTables |
- : kNaClDecoderTables; |
-} |
- |
-/* Analyze each section in the given elf file, using the given validator |
- * state. |
- */ |
-static void AnalyzeSfiSections(ncfile *ncf, struct NaClValidatorState *vstate) { |
- int ii; |
- const Elf_Phdr *phdr = ncf->pheaders; |
- |
- for (ii = 0; ii < ncf->phnum; ii++) { |
- /* TODO(karl) fix types for this? */ |
- NaClValidatorMessage( |
- LOG_INFO, vstate, |
- "segment[%d] p_type %d p_offset %"NACL_PRIxElf_Off |
- " vaddr %"NACL_PRIxElf_Addr |
- " paddr %"NACL_PRIxElf_Addr |
- " align %"NACL_PRIuElf_Xword"\n", |
- ii, phdr[ii].p_type, phdr[ii].p_offset, |
- phdr[ii].p_vaddr, phdr[ii].p_paddr, |
- phdr[ii].p_align); |
- NaClValidatorMessage( |
- LOG_INFO, vstate, |
- " filesz %"NACL_PRIxElf_Xword |
- " memsz %"NACL_PRIxElf_Xword |
- " flags %"NACL_PRIxElf_Word"\n", |
- phdr[ii].p_filesz, phdr[ii].p_memsz, |
- phdr[ii].p_flags); |
- if ((PT_LOAD != phdr[ii].p_type) || |
- (0 == (phdr[ii].p_flags & PF_X))) |
- continue; |
- NaClValidatorMessage(LOG_INFO, vstate, "parsing segment %d\n", ii); |
- NaClValidateSegmentUsingTables(ncf->data + (phdr[ii].p_vaddr - ncf->vbase), |
- phdr[ii].p_vaddr, phdr[ii].p_memsz, vstate, |
- NaClGetDecoderTables()); |
- } |
-} |
- |
-static void AnalyzeSfiSegments(ncfile *ncf, NaClValidatorState *state) { |
- int ii; |
- const Elf_Shdr *shdr = ncf->sheaders; |
- |
- for (ii = 0; ii < ncf->shnum; ii++) { |
- NaClValidatorMessage( |
- LOG_INFO, state, |
- "section %d sh_addr %"NACL_PRIxElf_Addr" offset %"NACL_PRIxElf_Off |
- " flags %"NACL_PRIxElf_Xword"\n", |
- ii, shdr[ii].sh_addr, shdr[ii].sh_offset, shdr[ii].sh_flags); |
- if ((shdr[ii].sh_flags & SHF_EXECINSTR) != SHF_EXECINSTR) |
- continue; |
- NaClValidatorMessage(LOG_INFO, state, "parsing section %d\n", ii); |
- NaClValidateSegmentUsingTables(ncf->data + (shdr[ii].sh_addr - ncf->vbase), |
- shdr[ii].sh_addr, shdr[ii].sh_size, state, |
- NaClGetDecoderTables()); |
- } |
-} |
- |
-/* Analyze each code segment in the given elf file, stored in the |
- * file with the given path fname. |
- */ |
-static Bool AnalyzeSfiCodeSegments(ncfile *ncf, const char *fname) { |
- /* TODO(karl) convert these to be PcAddress and MemorySize */ |
- NaClPcAddress vbase, vlimit; |
- NaClValidatorState *vstate; |
- Bool return_value = TRUE; |
- |
- GetVBaseAndLimit(ncf, &vbase, &vlimit); |
- vstate = NaClValStateCreate(vbase, vlimit - vbase, nacl_base_register); |
- if (vstate == NULL) { |
- NaClValidatorMessage(LOG_ERROR, vstate, "Unable to create validator state"); |
- return FALSE; |
- } |
- NaClValidatorStateSetErrorReporter(vstate, &kNaClVerboseErrorReporter); |
- if (NACL_FLAGS_analyze_segments) { |
- AnalyzeSfiSegments(ncf, vstate); |
- } else { |
- AnalyzeSfiSections(ncf, vstate); |
- } |
- return_value = NaClValidatesOk(vstate); |
- NaClReportSafety(return_value, fname); |
- NaClValidatorStateDestroy(vstate); |
- return return_value; |
-} |
-#endif |
- |
-/*************************** |
- * Top-level driver code. * |
- **************************/ |
- |
-/* Analyze the code segments of the elf file in the validator date. */ |
-static Bool ValidateAnalyze(ValidateData *data) { |
- int i; |
- Bool results = TRUE; |
- for (i = 0; i < NACL_FLAGS_validate_attempts; ++i) { |
- Bool return_value = |
-#if NACL_TARGET_SUBARCH == 64 |
- AnalyzeSfiCodeSegments(data->ncf, data->fname); |
-#else |
- AnalyzeSegmentCodeSegments(data->ncf, data->fname); |
-#endif |
- if (!return_value) { |
- results = FALSE; |
- } |
- } |
- nc_freefile(data->ncf); |
- return results; |
-} |
- |
-/* Define a sequence of bytes to validate whose virtual address begins at the |
- * given base. |
- */ |
-typedef struct NaClValidateBytes { |
- /* The sequence of bytes to validate. */ |
- uint8_t* bytes; |
- /* The number of bytes in the sequence. */ |
- NaClMemorySize num_bytes; |
- /* The virtual base adddress associated with the first byte in the |
- * sequence. |
- */ |
- NaClPcAddress base; |
-} NaClValidateBytes; |
- |
-/* Apply the validator to the sequence of bytes in the given data. */ |
-static Bool NaClValidateAnalyzeBytes(NaClValidateBytes* data) { |
- Bool return_value = FALSE; |
-#if NACL_TARGET_SUBARCH == 64 |
- NaClValidatorState* state; |
- state = NaClValStateCreate(data->base, |
- data->num_bytes, |
- nacl_base_register); |
- if (NULL == state) { |
- NaClValidatorMessage(LOG_ERROR, NULL, "Unable to create validator state"); |
- return FALSE; |
- } |
- if (NACL_FLAGS_stubout_memory) { |
- NaClValidatorStateSetDoStubOut(state, TRUE); |
- } |
- NaClValidatorStateSetErrorReporter(state, &kNaClVerboseErrorReporter); |
- NaClValidateSegmentUsingTables(data->bytes, data->base, data->num_bytes, |
- state, NaClGetDecoderTables()); |
- return_value = NaClValidatesOk(state); |
- if (state->did_stub_out) { |
- /* Used for golden file testing. */ |
- printf("Some instructions were replaced with HLTs.\n"); |
- } |
- NaClValidatorStateDestroy(state); |
- NaClReportSafety(return_value, ""); |
-#else |
- struct NCValidatorState *vstate; |
- vstate = NCValInit(data->base, data->num_bytes); |
- if (vstate == NULL) { |
- printf("Unable to create validator state, quitting!\n"); |
- } else { |
- if (NACL_FLAGS_stubout_memory) { |
- NCValidateSetStubOutMode(vstate, 1); |
- } |
- NCValidateSetErrorReporter(vstate, &kNCVerboseErrorReporter); |
- NCValidateSegment(&data->bytes[0], data->base, data->num_bytes, vstate); |
- return_value = (0 == NCValidateFinish(vstate)) ? TRUE : FALSE; |
- if (vstate->stats.didstubout) { |
- /* Used for golden file testing. */ |
- printf("Some instructions were replaced with HLTs.\n"); |
- } |
- NaClReportSafety(return_value, ""); |
- if (NACL_FLAGS_stats_print) NCStatsPrint(vstate); |
- NCValidateFreeState(&vstate); |
- } |
-#endif |
- return return_value; |
-} |
- |
-/* Given the command line arguments in argc/argv, and the sequence of bytes |
- * in the given data, apply the validator to the given bytes. |
- */ |
-Bool NaClRunValidatorBytes(int argc, |
- const char* argv[], |
- uint8_t* bytes, |
- NaClMemorySize num_bytes, |
- NaClPcAddress base) { |
- NaClValidateBytes data; |
- int i; |
- Bool results = TRUE; |
- data.bytes = bytes; |
- data.num_bytes = num_bytes; |
- data.base = base; |
- for (i = 0; i < NACL_FLAGS_validate_attempts; ++i) { |
- if (!NaClRunValidator(argc, argv, &data, |
- (NaClValidateLoad) NaClValidateNoLoad, |
- (NaClValidateAnalyze) NaClValidateAnalyzeBytes)) { |
- results = FALSE; |
- } |
- } |
- return results; |
-} |
- |
- |
-static const char usage_str[] = |
- "usage: ncval [options] file\n" |
- "\n" |
- "\tValidates an x86-%d nexe file.\n" |
- "\n" |
- "Options are:\n" |
- "\n" |
-#ifdef NCVAL_TESTING |
- "--print_conditions\n" |
- "\tPrint all pre/post conditions, including NaCl illegal instructions.\n" |
-#endif |
- "--annotate\n" |
- "\tRun validator using annotations that will be understood\n" |
- "\tby ncval_annotate.py.\n" |
- "--attempts=N\n" |
- "\tRun the validator on the nexe file (after loading) N times.\n" |
- "\tNote: this flag should only be used for profiling.\n" |
- "--CLFLUSH\n" |
- "\tModel a CPU that supports the clflush instruction.\n" |
- "--CMOV\n" |
- "\tModel a CPU that supports the cmov instructions.\n" |
-#ifdef NCVAL_TESTING |
- "--conds\n" |
- "\tPrint out pre/post conditions associated with each instruction.\n" |
-#endif |
- "--cpuid-all\n" |
- "\tModel a CPU that supports all available features.\n" |
- "--cpuid-none\n" |
- "\tModel a CPU that supports no avaliable features.\n" |
- "--CX8\n" |
- "\tModel a CPU that supports the cmpxchg8b instruction.\n" |
- "--detailed\n" |
- "\tPrint out detailed error messages, rather than use performant\n" |
- "\tcode used by sel_ldr\n" |
- "--errors\n" |
- "\tPrint out error and fatal error messages, but not\n" |
- "\tinformative and warning messages\n" |
- "--fatal\n" |
- "\tOnly print out fatal error messages.\n" |
- "--FXSR\n" |
- "\tModel a CPU that supports the sfence instructions.\n" |
- "--help\n" |
- "\tPrint this message, and then exit.\n" |
- "--hex_text=<file>\n" |
- "\tRead text file of hex bytes, and use that\n" |
- "\tas the definition of the code segment. Note: -hex_text=- will\n" |
- "\tread from stdin instead of a file.\n" |
-#if NACL_TARGET_SUBARCH == 64 |
- "--histogram\n" |
- "\tPrint out a histogram of found opcodes.\n" |
- "--identity_mask\n" |
- "\tMask jumps using 0xFF instead of one matching\n" |
- "\tthe block alignment.\n" |
-#endif |
- "--local_cpuid\n" |
- "\tSet cpuid to values defined by local host this command is run on.\n" |
- "--LZCNT\n" |
- "\tModel a CPU that supports the lzcnt instruction.\n" |
-#if NACL_TARGET_SUBARCH == 64 |
- "--max_errors=N\n" |
- "\tPrint out at most N error messages. If N is zero,\n" |
- "\tno messages are printed. If N is < 0, all messages are printed.\n" |
-#endif |
- "--MMX\n" |
- "\tModel a CPU that supports MMX instructions.\n" |
- "--MOVBE\n" |
- "\tModel a CPU that supports the movbe instruction.\n" |
- "--POPCNT\n" |
- "\tModel a CPU that supports the popcnt instruction.\n" |
-#if NACL_TARGET_SUBARCH == 64 |
- "--readwrite_sfi\n" |
- "\tCheck for memory read and write software fault isolation.\n" |
- "--segments\n" |
- "\tAnalyze code in segments in elf file, instead of headers.\n" |
-#endif |
- "--SSE\n" |
- "\tModel a CPU that supports SSE instructions.\n" |
- "--SSE2\n" |
- "\tModel a CPU that supports SSE 2 instructions.\n" |
- "--SSE3\n" |
- "\tModel a CPU that supports SSE 3 instructions.\n" |
- "--SSSE3\n" |
- "\tModel a CPU that supports SSSE 3 instructions.\n" |
- "--SSE41\n" |
- "\tModel a CPU that supports SSE 4.1 instructions.\n" |
- "--SSE42\n" |
- "\tModel a CPU that supports SSE 4.2 instructions.\n" |
- "--SSE4A\n" |
- "\tModel a CPU that supports SSE 4A instructions.\n" |
-#if NACL_TARGET_SUBARCH == 32 |
- "--stats\n" |
- "\tPrint statistics collected by the validator.\n" |
-#endif |
- "--stubout\n" |
- "\tRun using stubout mode, replacing bad instructions with halts.\n" |
- "\tStubbed out disassembly will be printed after validator\n" |
- "\terror messages. Note: Only applied if --hex_text option is\n" |
- "\talso specified\n" |
- "-t\n" |
- "\tTime the validator and print out results.\n" |
- "--TSC\n" |
- "\tModel a CPU that supports the rdtsc instruction.\n" |
- "--x87\n" |
- "\tModel a CPU that supports x87 instructions.\n" |
-#if NACL_TARGET_SUBARCH == 64 |
- "--validator_decoder\n" |
- "\tUse validator (partial) decoder instead of full decoder.\n" |
-#endif |
- "--3DNOW\n" |
- "\tModel a CPU that supports 3DNOW instructions.\n" |
- "--E3DNOW\n" |
- "\tModel a CPU that supports E3DNOW instructions.\n" |
- "\n" |
- "--time\n" |
- "\tTime the validator and print out results. Same as option -t.\n" |
-#if NACL_TARGET_SUBARCH == 64 |
- "--trace_insts\n" |
- "\tTurn on validator trace of instructions, as processed..\n" |
- "--trace_verbose\n" |
- "\tTurn on all trace validator messages. Note: this\n" |
- "\tflag also implies --trace.\n" |
-#endif |
- "--warnings\n" |
- "\tPrint out warnings, errors, and fatal errors, but not\n" |
- "\tinformative messages.\n" |
-#if NACL_TARGET_SUBARCH == 64 |
- "--write_sfi\n" |
- "\tOnly check for memory write software fault isolation.\n" |
-#endif |
- "\n"; |
- |
-static void usage(int exit_code) { |
- printf(usage_str, NACL_TARGET_SUBARCH); |
- exit(exit_code); |
-} |
- |
-/* Checks if arg is one of the expected "Bool" flags, and if so, sets |
- * the corresponding flag and returns true. |
- */ |
-static Bool GrokABoolFlag(const char *arg) { |
- /* A set of boolean flags to be checked */ |
- static struct { |
- const char *flag_name; |
- Bool *flag_ptr; |
- } flags[] = { |
- { "--segments" , &NACL_FLAGS_analyze_segments }, |
-#ifdef NCVAL_TESTING |
- { "--print_all_conds", &NACL_FLAGS_report_conditions_on_all }, |
-#else |
- { "--detailed", &NACL_FLAGS_detailed_errors }, |
-#endif |
- { "--stubout", &NACL_FLAGS_stubout_memory }, |
-#if NACL_TARGET_SUBARCH == 64 |
- { "--trace_insts", &NACL_FLAGS_validator_trace_instructions }, |
-#endif |
- { "-t", &NACL_FLAGS_print_timing }, |
-#if NACL_TARGET_SUBARCH == 32 |
- { "--stats", &NACL_FLAGS_stats_print }, |
-#endif |
- { "--annotate", &NACL_FLAGS_ncval_annotate }, |
-#if NACL_TARGET_SUBARCH == 64 |
- { "--histogram", &NACL_FLAGS_opcode_histogram }, |
-#endif |
- { "--time" , &NACL_FLAGS_print_timing }, |
-#if NACL_TARGET_SUBARCH == 64 |
- { "--warnings", &NACL_FLAGS_warnings }, |
- { "--errors" , &NACL_FLAGS_errors }, |
- { "--fatal" , &NACL_FLAGS_fatal }, |
- { "--validator_decoder", &NACL_FLAGS_validator_decoder }, |
-#endif |
- { "--identity_mask", &NACL_FLAGS_identity_mask }, |
- }; |
- |
- /* A set of CPU features to check. */ |
- static struct { |
- const char *feature_name; |
- NaClCPUFeatureX86ID feature; |
- } features[] = { |
- { "--x87" , NaClCPUFeatureX86_x87 }, |
- { "--MMX" , NaClCPUFeatureX86_MMX }, |
- { "--SSE" , NaClCPUFeatureX86_SSE }, |
- { "--SSE2" , NaClCPUFeatureX86_SSE2 }, |
- { "--SSE3" , NaClCPUFeatureX86_SSE3 }, |
- { "--SSSE3" , NaClCPUFeatureX86_SSSE3 }, |
- { "--SSE41" , NaClCPUFeatureX86_SSE41 }, |
- { "--SSE42" , NaClCPUFeatureX86_SSE42 }, |
- { "--MOVBE" , NaClCPUFeatureX86_MOVBE }, |
- { "--POPCNT" , NaClCPUFeatureX86_POPCNT }, |
- { "--CX8" , NaClCPUFeatureX86_CX8 }, |
- { "--CX16" , NaClCPUFeatureX86_CX16 }, |
- { "--CMOV" , NaClCPUFeatureX86_CMOV }, |
- { "--MON" , NaClCPUFeatureX86_MON }, |
- { "--FXSR" , NaClCPUFeatureX86_FXSR }, |
- { "--CLFLUSH", NaClCPUFeatureX86_CLFLUSH }, |
- { "--TSC" , NaClCPUFeatureX86_TSC }, |
- { "--3DNOW" , NaClCPUFeatureX86_3DNOW }, |
- { "--EMMX" , NaClCPUFeatureX86_EMMX }, |
- { "--E3DNOW" , NaClCPUFeatureX86_E3DNOW }, |
- { "--LZCNT" , NaClCPUFeatureX86_LZCNT }, |
- { "--SSE4A" , NaClCPUFeatureX86_SSE4A }, |
- { "--LM" , NaClCPUFeatureX86_LM }, |
- }; |
- |
- int i; |
- Bool flag_state; |
- for (i = 0; i < NACL_ARRAY_SIZE(flags); ++i) { |
- if (GrokBoolFlag(flags[i].flag_name, arg, flags[i].flag_ptr)) { |
- return TRUE; |
- } |
- } |
- for (i = 0; i < NACL_ARRAY_SIZE(features); ++i) { |
- if (GrokBoolFlag(features[i].feature_name, arg, &flag_state)) { |
- NaClSetCPUFeatureX86(&ncval_cpu_features, features[i].feature, |
- flag_state); |
- return TRUE; |
- } |
- } |
- |
- return FALSE; |
-} |
- |
-/* Checks if arg is one of the expected "int" flags, and if so, sets |
- * the corresponding flag and returns true. |
- */ |
-static Bool GrokAnIntFlag(const char *arg) { |
- /* A set of boolean flags to be checked */ |
- static struct { |
- const char *flag_name; |
- int *flag_ptr; |
- } flags[] = { |
- { "--max_errors", &NACL_FLAGS_max_reported_errors}, |
- { "--attempts" , &NACL_FLAGS_validate_attempts }, |
- }; |
- int i; |
- for (i = 0; i < NACL_ARRAY_SIZE(flags); ++i) { |
- if (GrokIntFlag(flags[i].flag_name, arg, flags[i].flag_ptr)) { |
- return TRUE; |
- } |
- } |
- return FALSE; |
-} |
- |
-static int GrokFlags(int argc, const char *argv[]) { |
- int i; |
- int new_argc; |
- Bool help = FALSE; |
-#if NACL_TARGET_SUBARCH == 64 |
- Bool only_write_sandbox; |
-#endif |
- if (argc == 0) return 0; |
- new_argc = 1; |
- for (i = 1; i < argc; ++i) { |
- Bool flag; |
- const char *arg = argv[i]; |
- if (GrokABoolFlag(arg) || |
- GrokAnIntFlag(arg) || |
- GrokCstringFlag("--hex_text", arg, &NACL_FLAGS_hex_text)) { |
- /* Valid processed flag, continue to next flag. */ |
- } else if (GrokBoolFlag("--help", arg, &help)) { |
- usage(0); |
- } |
-#if NACL_TARGET_SUBARCH == 64 |
- else if (0 == strcmp("--trace_verbose", arg)) { |
- NaClValidatorFlagsSetTraceVerbose(); |
- } else if (GrokBoolFlag("--write_sfi", arg, &only_write_sandbox)) { |
- NACL_FLAGS_read_sandbox = !only_write_sandbox; |
- } else if (GrokBoolFlag("--readwrite_sfi", arg, |
- &NACL_FLAGS_read_sandbox)) { |
- } |
-#endif |
- else if (0 == strcmp("--cpuid-all", arg)) { |
- NaClSetAllCPUFeaturesX86((NaClCPUFeatures *) &ncval_cpu_features); |
- } else if (0 == strcmp("--cpuid-none", arg)) { |
- NaClClearCPUFeaturesX86(&ncval_cpu_features); |
- } else if (GrokBoolFlag("--local_cpuid", arg, &flag)) { |
- NaClGetCurrentCPUFeaturesX86((NaClCPUFeatures *) &ncval_cpu_features); |
- } else { |
- argv[new_argc++] = argv[i]; |
- } |
- } |
- |
- /* Before returning, update internals to match command line |
- * values found. |
- */ |
- if (NACL_FLAGS_warnings) { |
- NaClLogSetVerbosity(LOG_WARNING); |
- } |
- if (NACL_FLAGS_errors) { |
- NaClLogSetVerbosity(LOG_ERROR); |
- } |
- if (NACL_FLAGS_fatal) { |
- NaClLogSetVerbosity(LOG_FATAL); |
- } |
- NCValidatorSetMaxDiagnostics(NACL_FLAGS_max_reported_errors); |
- if (NACL_FLAGS_stubout_memory && (NACL_FLAGS_validate_attempts != 1)) { |
- fprintf(stderr, "Can't specify --stubout when --attempts!=1\n"); |
- } |
- |
- return new_argc; |
-} |
- |
-/* Decode and print out code segment if stubout memory is specified |
- * command line. |
- */ |
-static void NaClMaybeDecodeDataSegment( |
- uint8_t *mbase, NaClPcAddress vbase, NaClMemorySize size) { |
- if (NACL_FLAGS_stubout_memory) { |
- /* Disassemble data segment to see how halts were inserted. |
- * Note: We use the full decoder (rather than the validator decoder) |
- * because the validator decoders are partial decodings, and can be |
- * confusing to the reader. |
- */ |
- NaClDisassembleSegment(mbase, vbase, size, |
- NACL_DISASSEMBLE_FLAG(NaClDisassembleFull)); |
- } |
-} |
- |
-int main(int argc, const char *argv[]) { |
- int result = 0; |
- struct GioFile gio_out_stream; |
- struct Gio *gout = (struct Gio*) &gio_out_stream; |
- |
- if (argc < 2) { |
- fprintf(stderr, "expected: %s file\n", argv[0]); |
- usage(1); |
- } |
- |
- /* Set up logging. */ |
- if (!GioFileRefCtor(&gio_out_stream, stdout)) { |
- fprintf(stderr, "Unable to create gio file for stdout!\n"); |
- return 1; |
- } |
- NaClLogModuleInitExtended(LOG_INFO, gout); |
- NaClLogDisableTimestamp(); |
- |
- /* By default, assume no local cpu features are available. */ |
- NaClClearCPUFeaturesX86(&ncval_cpu_features); |
- |
- /* Validate the specified input. */ |
- argc = GrokFlags(argc, argv); |
- if (0 == strcmp(NACL_FLAGS_hex_text, "")) { |
- /* Run validator on elf file. */ |
- ValidateData data; |
- Bool success = NaClRunValidator( |
- argc, argv, &data, |
- (NaClValidateLoad) ValidateElfLoad, |
- (NaClValidateAnalyze) ValidateAnalyze); |
- NaClReportSafety(success, argv[1]); |
- result = (success ? 0 : 1); |
- } else { |
- /* Run validator on hex text file. */ |
- NaClValidatorByteArray data; |
- argc = ValidateHexLoad(argc, argv, &data); |
- NaClRunValidatorBytes( |
- argc, argv, (uint8_t*) &data.bytes, |
- data.num_bytes, data.base); |
- NaClMaybeDecodeDataSegment(&data.bytes[0], data.base, data.num_bytes); |
- /* always succeed, so that the testing framework works. */ |
- result = 0; |
- } |
- |
- NaClLogModuleFini(); |
- GioFileDtor(gout); |
- return result; |
-} |