2 * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
8 * ncval.c - command line validator for NaCl.
13 #ifndef NACL_TRUSTED_BUT_NOT_TCB
14 #error("This file is not meant for use in the TCB")
17 #include "native_client/src/include/portability.h"
24 #include <sys/timeb.h>
26 #include "native_client/src/include/nacl_macros.h"
27 #include "native_client/src/shared/gio/gio.h"
28 #include "native_client/src/shared/platform/nacl_log.h"
29 #include "native_client/src/shared/utils/flags.h"
30 #include "native_client/src/trusted/validator/ncfileutil.h"
31 #include "native_client/src/trusted/cpu_features/arch/x86/cpu_x86.h"
32 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter.h"
33 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter_internal.h"
34 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter_detailed.h"
35 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_jumps.h"
36 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_opcode_histogram.h"
37 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_memory_protect.h"
38 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.h"
39 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode_verbose.h"
40 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate.h"
41 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate_detailed.h"
42 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate_internaltypes.h"
43 #include "native_client/src/trusted/validator_x86/nc_read_segment.h"
44 #include "native_client/src/trusted/validator_x86/ncdis_segments.h"
46 #if NACL_TARGET_SUBARCH == 64
47 #include "native_client/src/trusted/validator/x86/decoder/nc_decode_tables.h"
48 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncval_decode_tables.h"
49 #include "native_client/src/trusted/validator_x86/ncdis_decode_tables.h"
52 /* To turn on debugging of instruction decoding, change value of
57 #include "native_client/src/shared/utils/debugging.h"
59 /* Forward declarations. */
60 static void usage(int exit_code);
62 #if NACL_TARGET_SUBARCH == 32
63 /* Flag defining if statistics should be printed for callback validator
66 static Bool NACL_FLAGS_stats_print = FALSE;
69 /* Flag defining if detailed error messages should be generated. When
70 * false, runs performance model as used by sel_ldr.
72 static Bool NACL_FLAGS_detailed_errors = TRUE;
74 /* Flag defining the name of a hex text to be used as the code segment.
76 static char *NACL_FLAGS_hex_text = "";
78 /* Define if we should process segments (rather than sections) when applying SFI
81 static Bool NACL_FLAGS_analyze_segments = FALSE;
83 /* Define how many times we will analyze the code segment.
84 * Note: Values, other than 1, is only used for profiling.
86 static int NACL_FLAGS_validate_attempts = 1;
88 /* Define the set of CPU features to use while validating. */
89 static NaClCPUFeaturesX86 ncval_cpu_features;
91 /* Define whether timing should be applied when running the validator. */
92 static Bool NACL_FLAGS_print_timing = FALSE;
94 /* Define what level of errors will be printed.
95 * Note: If multiple flags are true, the one with
96 * the highest severity will be selected.
98 static Bool NACL_FLAGS_warnings = FALSE;
99 static Bool NACL_FLAGS_errors = FALSE;
100 static Bool NACL_FLAGS_fatal = FALSE;
102 /* Define if special stubout tests should be run. Such
103 * tests apply stubout, and then print out the modified
106 static Bool NACL_FLAGS_stubout_memory = FALSE;
108 #if NACL_TARGET_SUBARCH == 64
109 /* Flag that allows validator decoder to be used in place of full decoder.
111 static Bool NACL_FLAGS_validator_decoder = FALSE;
114 /* Generates NaClErrorMapping for error level suffix. */
115 #define NaClError(s) { #s , LOG_## s}
117 /**************************************************
118 * Driver to apply the validator to a code segment
119 *************************************************/
121 /* Reports if named module is safe. */
122 static void NaClReportFileSafety(Bool success, const char *fname) {
123 if (NACL_FLAGS_stubout_memory) {
124 /* The validator has been run to test stubbing out. Stubbing out,
125 * in this tool, means replacing instructions (modeled using hex
126 * text) that are unsafe and rejected by the validator, and are
127 * replaced with HALT instructions.
129 NaClLog(LOG_INFO, "STUBBED OUT as follows:\n");
131 #ifndef NCVAL_TESTING
133 NaClLog(LOG_INFO, "*** %s is safe ***\n", fname);
135 NaClLog(LOG_INFO, "*** %s IS UNSAFE ***\n", fname);
141 /* Reports if module is safe. */
142 static void NaClReportSafety(Bool success,
143 const char* filename) {
144 if (0 != strcmp(NACL_FLAGS_hex_text, "")) {
145 /* Special hex text processing, rather than filename. */
146 if (0 == strcmp(NACL_FLAGS_hex_text, "-")) {
147 NaClReportFileSafety(success, "<input>");
151 NaClReportFileSafety(success, filename);
154 /* The model of data to be passed to the load/analyze steps. */
155 typedef void* NaClRunValidatorData;
157 /* The routine that loads the code segment(s) into memory (within
158 * the data arg). Returns true iff load was successful.
160 typedef Bool (*NaClValidateLoad)(int argc, const char* argv[],
161 NaClRunValidatorData data);
163 /* The actual validation analysis, applied to the data returned by
164 * ValidateLoad. Assume that this function also deallocates any memory
165 * in loaded_data. Returns true iff analysis doesn't find any problems.
167 typedef Bool (*NaClValidateAnalyze)(NaClRunValidatorData data);
169 /* Runs the validator using the given (command line) arguments.
172 * data - The model of data to be passed to the load/analyze steps.
173 * Allows top-level call to pass control information
174 * to the load and analyze functions, and between these
176 * load - The function to load in the data needed to validate.
177 * analyze - The function to call to do validator analysis once
178 * the data has been read in.
180 static Bool NaClRunValidator(int argc, const char* argv[],
181 NaClRunValidatorData data,
182 NaClValidateLoad load,
183 NaClValidateAnalyze analyze) {
190 return_value = load(argc, argv, data);
192 NaClValidatorMessage(LOG_ERROR, NULL, "Unable to load code to validate\n");
196 return_value = analyze(data);
199 if (NACL_FLAGS_print_timing) {
200 NaClValidatorMessage(
202 "load time: %0.6f analysis time: %0.6f\n",
203 (double)(clock_l - clock_0) / (double)CLOCKS_PER_SEC,
204 (double)(clock_v - clock_l) / (double)CLOCKS_PER_SEC);
209 /* Default loader that does nothing. Typically this is because
210 * the data argument already contains the bytes to validate.
212 Bool NaClValidateNoLoad(int argc, const char* argv[],
213 NaClRunValidatorData data) {
217 /* Local file data for validator run. */
218 typedef struct ValidateData {
219 /* The name of the elf file to validate. */
221 /* The elf file to validate. */
225 /* Load the elf file and return the loaded elf file. */
226 static Bool ValidateElfLoad(int argc, const char *argv[],
227 ValidateData *data) {
229 NaClLog(LOG_ERROR, "expected: %s file\n", argv[0]);
232 data->fname = argv[1];
234 /* TODO(karl): Once we fix elf values put in by compiler, so that
235 * we no longer get load errors from ncfilutil.c, find a way to
236 * terminate early if errors occur during loading.
238 data->ncf = nc_loadfile(data->fname);
239 if (data->ncf == NULL) {
240 NaClLog(LOG_ERROR, "nc_loadfile(%s): %s\n", data->fname, strerror(errno));
243 return NULL != data->ncf;
246 /***************************************************
247 * Code to run SFI validator on hex text examples. *
248 ***************************************************/
250 /* Defines the maximum number of characters allowed on an input line
251 * of the input text defined by the commands command line option.
253 #define NACL_MAX_INPUT_LINE 4096
255 typedef struct NaClValidatorByteArray {
256 uint8_t bytes[NACL_MAX_INPUT_LINE];
258 NaClMemorySize num_bytes;
259 } NaClValidatorByteArray;
261 static void HexFatal(const char *format, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
263 /* Print out given error message about the hex input file, and then exit. */
264 static void HexFatal(const char *format, ...) {
266 va_start(ap, format);
267 NaClLogV(LOG_ERROR, format, ap);
269 /* always succed, so that the testing framework works. */
273 /* Load the hex input file from the given command line arguments,
274 * and put it into the given data structure.
276 static int ValidateHexLoad(int argc, const char *argv[],
277 NaClValidatorByteArray *data) {
279 HexFatal("expected: %s <options>\n", argv[0]);
281 if (0 == strcmp(NACL_FLAGS_hex_text, "-")) {
282 data->num_bytes = (NaClMemorySize)
283 NaClReadHexTextWithPc(stdin, &data->base, data->bytes,
284 NACL_MAX_INPUT_LINE);
286 FILE *input = fopen(NACL_FLAGS_hex_text, "r");
288 HexFatal("Can't open hex text file: %s\n", NACL_FLAGS_hex_text);
290 data->num_bytes = (NaClMemorySize)
291 NaClReadHexTextWithPc(input, &data->base, data->bytes,
292 NACL_MAX_INPUT_LINE);
299 #if NACL_TARGET_SUBARCH == 32
300 /***************************************
301 * Code to run segment based validator.*
302 ***************************************/
304 int AnalyzeSegmentSections(ncfile *ncf, struct NCValidatorState *vstate) {
307 const Elf_Phdr *phdr = ncf->pheaders;
309 for (ii = 0; ii < ncf->phnum; ii++) {
311 "segment[%d] p_type %"NACL_PRIdElf_Word
312 " p_offset %"NACL_PRIxElf_Off" vaddr %"NACL_PRIxElf_Addr
313 " paddr %"NACL_PRIxElf_Addr" align %"NACL_PRIuElf_Xword"\n",
314 ii, phdr[ii].p_type, phdr[ii].p_offset,
315 phdr[ii].p_vaddr, phdr[ii].p_paddr,
319 " filesz %"NACL_PRIxElf_Xword" memsz %"NACL_PRIxElf_Xword
320 " flags %"NACL_PRIxElf_Word"\n",
321 phdr[ii].p_filesz, phdr[ii].p_memsz, phdr[ii].p_flags);
322 if ((PT_LOAD != phdr[ii].p_type) ||
323 (0 == (phdr[ii].p_flags & PF_X)))
325 NaClLog(LOG_INFO, "parsing segment %d\n", ii);
326 NCValidateSegment(ncf->data + (phdr[ii].p_vaddr - ncf->vbase),
327 phdr[ii].p_vaddr, phdr[ii].p_memsz, vstate);
332 /* Initialize segment validator, using detailed (summary) error
333 * messages if selected.
335 struct NCValidatorState* NCValInit(const NaClPcAddress vbase,
336 const NaClMemorySize codesize) {
337 return NACL_FLAGS_detailed_errors
338 ? NCValidateInitDetailed(vbase, codesize, &ncval_cpu_features)
339 : NCValidateInit(vbase, codesize, FALSE, &ncval_cpu_features);
343 static Bool AnalyzeSegmentCodeSegments(ncfile *ncf, const char *fname) {
344 NaClPcAddress vbase, vlimit;
345 struct NCValidatorState *vstate;
348 GetVBaseAndLimit(ncf, &vbase, &vlimit);
349 vstate = NCValInit(vbase, vlimit - vbase);
350 if (vstate == NULL) return FALSE;
351 NCValidateSetErrorReporter(vstate, &kNCVerboseErrorReporter);
352 if (AnalyzeSegmentSections(ncf, vstate) < 0) {
353 NaClLog(LOG_INFO, "%s: text validate failed\n", fname);
355 result = (0 == NCValidateFinish(vstate)) ? TRUE : FALSE;
356 NaClReportSafety(result, fname);
357 if (NACL_FLAGS_stats_print) NCStatsPrint(vstate);
358 NCValidateFreeState(&vstate);
359 NaClLog(LOG_INFO, "Validated %s\n", fname);
364 #if NACL_TARGET_SUBARCH == 64
365 /******************************
366 * Code to run SFI validator. *
367 ******************************/
369 /* Define what should be used as the base register for
372 static NaClOpKind nacl_base_register =
373 (64 == NACL_TARGET_SUBARCH ? RegR15 : RegUnknown);
375 /* Create validator state using detailed (summary) error messages
378 struct NaClValidatorState* NaClValStateCreate(
379 const NaClPcAddress vbase,
380 const NaClMemorySize sz,
381 const NaClOpKind base_register) {
383 NACL_FLAGS_detailed_errors
384 ? NaClValidatorStateCreateDetailed(vbase, sz, base_register,
386 : NaClValidatorStateCreate(vbase, sz, base_register, FALSE,
387 &ncval_cpu_features);
390 /* Returns the decoder tables to use. */
391 static const NaClDecodeTables* NaClGetDecoderTables(void) {
392 return NACL_FLAGS_validator_decoder
393 ? kNaClValDecoderTables
394 : kNaClDecoderTables;
397 /* Analyze each section in the given elf file, using the given validator
400 static void AnalyzeSfiSections(ncfile *ncf, struct NaClValidatorState *vstate) {
402 const Elf_Phdr *phdr = ncf->pheaders;
404 for (ii = 0; ii < ncf->phnum; ii++) {
405 /* TODO(karl) fix types for this? */
406 NaClValidatorMessage(
408 "segment[%d] p_type %d p_offset %"NACL_PRIxElf_Off
409 " vaddr %"NACL_PRIxElf_Addr
410 " paddr %"NACL_PRIxElf_Addr
411 " align %"NACL_PRIuElf_Xword"\n",
412 ii, phdr[ii].p_type, phdr[ii].p_offset,
413 phdr[ii].p_vaddr, phdr[ii].p_paddr,
415 NaClValidatorMessage(
417 " filesz %"NACL_PRIxElf_Xword
418 " memsz %"NACL_PRIxElf_Xword
419 " flags %"NACL_PRIxElf_Word"\n",
420 phdr[ii].p_filesz, phdr[ii].p_memsz,
422 if ((PT_LOAD != phdr[ii].p_type) ||
423 (0 == (phdr[ii].p_flags & PF_X)))
425 NaClValidatorMessage(LOG_INFO, vstate, "parsing segment %d\n", ii);
426 NaClValidateSegmentUsingTables(ncf->data + (phdr[ii].p_vaddr - ncf->vbase),
427 phdr[ii].p_vaddr, phdr[ii].p_memsz, vstate,
428 NaClGetDecoderTables());
432 static void AnalyzeSfiSegments(ncfile *ncf, NaClValidatorState *state) {
434 const Elf_Shdr *shdr = ncf->sheaders;
436 for (ii = 0; ii < ncf->shnum; ii++) {
437 NaClValidatorMessage(
439 "section %d sh_addr %"NACL_PRIxElf_Addr" offset %"NACL_PRIxElf_Off
440 " flags %"NACL_PRIxElf_Xword"\n",
441 ii, shdr[ii].sh_addr, shdr[ii].sh_offset, shdr[ii].sh_flags);
442 if ((shdr[ii].sh_flags & SHF_EXECINSTR) != SHF_EXECINSTR)
444 NaClValidatorMessage(LOG_INFO, state, "parsing section %d\n", ii);
445 NaClValidateSegmentUsingTables(ncf->data + (shdr[ii].sh_addr - ncf->vbase),
446 shdr[ii].sh_addr, shdr[ii].sh_size, state,
447 NaClGetDecoderTables());
451 /* Analyze each code segment in the given elf file, stored in the
452 * file with the given path fname.
454 static Bool AnalyzeSfiCodeSegments(ncfile *ncf, const char *fname) {
455 /* TODO(karl) convert these to be PcAddress and MemorySize */
456 NaClPcAddress vbase, vlimit;
457 NaClValidatorState *vstate;
458 Bool return_value = TRUE;
460 GetVBaseAndLimit(ncf, &vbase, &vlimit);
461 vstate = NaClValStateCreate(vbase, vlimit - vbase, nacl_base_register);
462 if (vstate == NULL) {
463 NaClValidatorMessage(LOG_ERROR, vstate, "Unable to create validator state");
466 NaClValidatorStateSetErrorReporter(vstate, &kNaClVerboseErrorReporter);
467 if (NACL_FLAGS_analyze_segments) {
468 AnalyzeSfiSegments(ncf, vstate);
470 AnalyzeSfiSections(ncf, vstate);
472 return_value = NaClValidatesOk(vstate);
473 NaClReportSafety(return_value, fname);
474 NaClValidatorStateDestroy(vstate);
479 /***************************
480 * Top-level driver code. *
481 **************************/
483 /* Analyze the code segments of the elf file in the validator date. */
484 static Bool ValidateAnalyze(ValidateData *data) {
487 for (i = 0; i < NACL_FLAGS_validate_attempts; ++i) {
489 #if NACL_TARGET_SUBARCH == 64
490 AnalyzeSfiCodeSegments(data->ncf, data->fname);
492 AnalyzeSegmentCodeSegments(data->ncf, data->fname);
498 nc_freefile(data->ncf);
502 /* Define a sequence of bytes to validate whose virtual address begins at the
505 typedef struct NaClValidateBytes {
506 /* The sequence of bytes to validate. */
508 /* The number of bytes in the sequence. */
509 NaClMemorySize num_bytes;
510 /* The virtual base adddress associated with the first byte in the
516 /* Apply the validator to the sequence of bytes in the given data. */
517 static Bool NaClValidateAnalyzeBytes(NaClValidateBytes* data) {
518 Bool return_value = FALSE;
519 #if NACL_TARGET_SUBARCH == 64
520 NaClValidatorState* state;
521 state = NaClValStateCreate(data->base,
525 NaClValidatorMessage(LOG_ERROR, NULL, "Unable to create validator state");
528 if (NACL_FLAGS_stubout_memory) {
529 NaClValidatorStateSetDoStubOut(state, TRUE);
531 NaClValidatorStateSetErrorReporter(state, &kNaClVerboseErrorReporter);
532 NaClValidateSegmentUsingTables(data->bytes, data->base, data->num_bytes,
533 state, NaClGetDecoderTables());
534 return_value = NaClValidatesOk(state);
535 if (state->did_stub_out) {
536 /* Used for golden file testing. */
537 printf("Some instructions were replaced with HLTs.\n");
539 NaClValidatorStateDestroy(state);
540 NaClReportSafety(return_value, "");
542 struct NCValidatorState *vstate;
543 vstate = NCValInit(data->base, data->num_bytes);
544 if (vstate == NULL) {
545 printf("Unable to create validator state, quitting!\n");
547 if (NACL_FLAGS_stubout_memory) {
548 NCValidateSetStubOutMode(vstate, 1);
550 NCValidateSetErrorReporter(vstate, &kNCVerboseErrorReporter);
551 NCValidateSegment(&data->bytes[0], data->base, data->num_bytes, vstate);
552 return_value = (0 == NCValidateFinish(vstate)) ? TRUE : FALSE;
553 if (vstate->stats.didstubout) {
554 /* Used for golden file testing. */
555 printf("Some instructions were replaced with HLTs.\n");
557 NaClReportSafety(return_value, "");
558 if (NACL_FLAGS_stats_print) NCStatsPrint(vstate);
559 NCValidateFreeState(&vstate);
565 /* Given the command line arguments in argc/argv, and the sequence of bytes
566 * in the given data, apply the validator to the given bytes.
568 Bool NaClRunValidatorBytes(int argc,
571 NaClMemorySize num_bytes,
572 NaClPcAddress base) {
573 NaClValidateBytes data;
577 data.num_bytes = num_bytes;
579 for (i = 0; i < NACL_FLAGS_validate_attempts; ++i) {
580 if (!NaClRunValidator(argc, argv, &data,
581 (NaClValidateLoad) NaClValidateNoLoad,
582 (NaClValidateAnalyze) NaClValidateAnalyzeBytes)) {
590 static const char usage_str[] =
591 "usage: ncval [options] file\n"
593 "\tValidates an x86-%d nexe file.\n"
598 "--print_conditions\n"
599 "\tPrint all pre/post conditions, including NaCl illegal instructions.\n"
602 "\tRun validator using annotations that will be understood\n"
603 "\tby ncval_annotate.py.\n"
605 "\tRun the validator on the nexe file (after loading) N times.\n"
606 "\tNote: this flag should only be used for profiling.\n"
608 "\tModel a CPU that supports the clflush instruction.\n"
610 "\tModel a CPU that supports the cmov instructions.\n"
613 "\tPrint out pre/post conditions associated with each instruction.\n"
616 "\tModel a CPU that supports all available features.\n"
618 "\tModel a CPU that supports no avaliable features.\n"
620 "\tModel a CPU that supports the cmpxchg8b instruction.\n"
622 "\tPrint out detailed error messages, rather than use performant\n"
623 "\tcode used by sel_ldr\n"
625 "\tPrint out error and fatal error messages, but not\n"
626 "\tinformative and warning messages\n"
628 "\tOnly print out fatal error messages.\n"
630 "\tModel a CPU that supports the sfence instructions.\n"
632 "\tPrint this message, and then exit.\n"
633 "--hex_text=<file>\n"
634 "\tRead text file of hex bytes, and use that\n"
635 "\tas the definition of the code segment. Note: -hex_text=- will\n"
636 "\tread from stdin instead of a file.\n"
637 #if NACL_TARGET_SUBARCH == 64
639 "\tPrint out a histogram of found opcodes.\n"
641 "\tMask jumps using 0xFF instead of one matching\n"
642 "\tthe block alignment.\n"
645 "\tSet cpuid to values defined by local host this command is run on.\n"
647 "\tModel a CPU that supports the lzcnt instruction.\n"
648 #if NACL_TARGET_SUBARCH == 64
650 "\tPrint out at most N error messages. If N is zero,\n"
651 "\tno messages are printed. If N is < 0, all messages are printed.\n"
654 "\tModel a CPU that supports MMX instructions.\n"
656 "\tModel a CPU that supports the movbe instruction.\n"
658 "\tModel a CPU that supports the popcnt instruction.\n"
659 #if NACL_TARGET_SUBARCH == 64
661 "\tCheck for memory read and write software fault isolation.\n"
663 "\tAnalyze code in segments in elf file, instead of headers.\n"
666 "\tModel a CPU that supports SSE instructions.\n"
668 "\tModel a CPU that supports SSE 2 instructions.\n"
670 "\tModel a CPU that supports SSE 3 instructions.\n"
672 "\tModel a CPU that supports SSSE 3 instructions.\n"
674 "\tModel a CPU that supports SSE 4.1 instructions.\n"
676 "\tModel a CPU that supports SSE 4.2 instructions.\n"
678 "\tModel a CPU that supports SSE 4A instructions.\n"
679 #if NACL_TARGET_SUBARCH == 32
681 "\tPrint statistics collected by the validator.\n"
684 "\tRun using stubout mode, replacing bad instructions with halts.\n"
685 "\tStubbed out disassembly will be printed after validator\n"
686 "\terror messages. Note: Only applied if --hex_text option is\n"
689 "\tTime the validator and print out results.\n"
691 "\tModel a CPU that supports the rdtsc instruction.\n"
693 "\tModel a CPU that supports x87 instructions.\n"
694 #if NACL_TARGET_SUBARCH == 64
695 "--validator_decoder\n"
696 "\tUse validator (partial) decoder instead of full decoder.\n"
699 "\tModel a CPU that supports 3DNOW instructions.\n"
701 "\tModel a CPU that supports E3DNOW instructions.\n"
704 "\tTime the validator and print out results. Same as option -t.\n"
705 #if NACL_TARGET_SUBARCH == 64
707 "\tTurn on validator trace of instructions, as processed..\n"
709 "\tTurn on all trace validator messages. Note: this\n"
710 "\tflag also implies --trace.\n"
713 "\tPrint out warnings, errors, and fatal errors, but not\n"
714 "\tinformative messages.\n"
715 #if NACL_TARGET_SUBARCH == 64
717 "\tOnly check for memory write software fault isolation.\n"
721 static void usage(int exit_code) {
722 printf(usage_str, NACL_TARGET_SUBARCH);
726 /* Checks if arg is one of the expected "Bool" flags, and if so, sets
727 * the corresponding flag and returns true.
729 static Bool GrokABoolFlag(const char *arg) {
730 /* A set of boolean flags to be checked */
732 const char *flag_name;
735 { "--segments" , &NACL_FLAGS_analyze_segments },
737 { "--print_all_conds", &NACL_FLAGS_report_conditions_on_all },
739 { "--detailed", &NACL_FLAGS_detailed_errors },
741 { "--stubout", &NACL_FLAGS_stubout_memory },
742 #if NACL_TARGET_SUBARCH == 64
743 { "--trace_insts", &NACL_FLAGS_validator_trace_instructions },
745 { "-t", &NACL_FLAGS_print_timing },
746 #if NACL_TARGET_SUBARCH == 32
747 { "--stats", &NACL_FLAGS_stats_print },
749 { "--annotate", &NACL_FLAGS_ncval_annotate },
750 #if NACL_TARGET_SUBARCH == 64
751 { "--histogram", &NACL_FLAGS_opcode_histogram },
753 { "--time" , &NACL_FLAGS_print_timing },
754 #if NACL_TARGET_SUBARCH == 64
755 { "--warnings", &NACL_FLAGS_warnings },
756 { "--errors" , &NACL_FLAGS_errors },
757 { "--fatal" , &NACL_FLAGS_fatal },
758 { "--validator_decoder", &NACL_FLAGS_validator_decoder },
760 { "--identity_mask", &NACL_FLAGS_identity_mask },
763 /* A set of CPU features to check. */
765 const char *feature_name;
766 NaClCPUFeatureX86ID feature;
768 { "--x87" , NaClCPUFeatureX86_x87 },
769 { "--MMX" , NaClCPUFeatureX86_MMX },
770 { "--SSE" , NaClCPUFeatureX86_SSE },
771 { "--SSE2" , NaClCPUFeatureX86_SSE2 },
772 { "--SSE3" , NaClCPUFeatureX86_SSE3 },
773 { "--SSSE3" , NaClCPUFeatureX86_SSSE3 },
774 { "--SSE41" , NaClCPUFeatureX86_SSE41 },
775 { "--SSE42" , NaClCPUFeatureX86_SSE42 },
776 { "--MOVBE" , NaClCPUFeatureX86_MOVBE },
777 { "--POPCNT" , NaClCPUFeatureX86_POPCNT },
778 { "--CX8" , NaClCPUFeatureX86_CX8 },
779 { "--CX16" , NaClCPUFeatureX86_CX16 },
780 { "--CMOV" , NaClCPUFeatureX86_CMOV },
781 { "--MON" , NaClCPUFeatureX86_MON },
782 { "--FXSR" , NaClCPUFeatureX86_FXSR },
783 { "--CLFLUSH", NaClCPUFeatureX86_CLFLUSH },
784 { "--TSC" , NaClCPUFeatureX86_TSC },
785 { "--3DNOW" , NaClCPUFeatureX86_3DNOW },
786 { "--EMMX" , NaClCPUFeatureX86_EMMX },
787 { "--E3DNOW" , NaClCPUFeatureX86_E3DNOW },
788 { "--LZCNT" , NaClCPUFeatureX86_LZCNT },
789 { "--SSE4A" , NaClCPUFeatureX86_SSE4A },
790 { "--LM" , NaClCPUFeatureX86_LM },
795 for (i = 0; i < NACL_ARRAY_SIZE(flags); ++i) {
796 if (GrokBoolFlag(flags[i].flag_name, arg, flags[i].flag_ptr)) {
800 for (i = 0; i < NACL_ARRAY_SIZE(features); ++i) {
801 if (GrokBoolFlag(features[i].feature_name, arg, &flag_state)) {
802 NaClSetCPUFeatureX86(&ncval_cpu_features, features[i].feature,
811 /* Checks if arg is one of the expected "int" flags, and if so, sets
812 * the corresponding flag and returns true.
814 static Bool GrokAnIntFlag(const char *arg) {
815 /* A set of boolean flags to be checked */
817 const char *flag_name;
820 { "--max_errors", &NACL_FLAGS_max_reported_errors},
821 { "--attempts" , &NACL_FLAGS_validate_attempts },
824 for (i = 0; i < NACL_ARRAY_SIZE(flags); ++i) {
825 if (GrokIntFlag(flags[i].flag_name, arg, flags[i].flag_ptr)) {
832 static int GrokFlags(int argc, const char *argv[]) {
836 #if NACL_TARGET_SUBARCH == 64
837 Bool only_write_sandbox;
839 if (argc == 0) return 0;
841 for (i = 1; i < argc; ++i) {
843 const char *arg = argv[i];
844 if (GrokABoolFlag(arg) ||
845 GrokAnIntFlag(arg) ||
846 GrokCstringFlag("--hex_text", arg, &NACL_FLAGS_hex_text)) {
847 /* Valid processed flag, continue to next flag. */
848 } else if (GrokBoolFlag("--help", arg, &help)) {
851 #if NACL_TARGET_SUBARCH == 64
852 else if (0 == strcmp("--trace_verbose", arg)) {
853 NaClValidatorFlagsSetTraceVerbose();
854 } else if (GrokBoolFlag("--write_sfi", arg, &only_write_sandbox)) {
855 NACL_FLAGS_read_sandbox = !only_write_sandbox;
856 } else if (GrokBoolFlag("--readwrite_sfi", arg,
857 &NACL_FLAGS_read_sandbox)) {
860 else if (0 == strcmp("--cpuid-all", arg)) {
861 NaClSetAllCPUFeaturesX86((NaClCPUFeatures *) &ncval_cpu_features);
862 } else if (0 == strcmp("--cpuid-none", arg)) {
863 NaClClearCPUFeaturesX86(&ncval_cpu_features);
864 } else if (GrokBoolFlag("--local_cpuid", arg, &flag)) {
865 NaClGetCurrentCPUFeaturesX86((NaClCPUFeatures *) &ncval_cpu_features);
867 argv[new_argc++] = argv[i];
871 /* Before returning, update internals to match command line
874 if (NACL_FLAGS_warnings) {
875 NaClLogSetVerbosity(LOG_WARNING);
877 if (NACL_FLAGS_errors) {
878 NaClLogSetVerbosity(LOG_ERROR);
880 if (NACL_FLAGS_fatal) {
881 NaClLogSetVerbosity(LOG_FATAL);
883 NCValidatorSetMaxDiagnostics(NACL_FLAGS_max_reported_errors);
884 if (NACL_FLAGS_stubout_memory && (NACL_FLAGS_validate_attempts != 1)) {
885 fprintf(stderr, "Can't specify --stubout when --attempts!=1\n");
891 /* Decode and print out code segment if stubout memory is specified
894 static void NaClMaybeDecodeDataSegment(
895 uint8_t *mbase, NaClPcAddress vbase, NaClMemorySize size) {
896 if (NACL_FLAGS_stubout_memory) {
897 /* Disassemble data segment to see how halts were inserted.
898 * Note: We use the full decoder (rather than the validator decoder)
899 * because the validator decoders are partial decodings, and can be
900 * confusing to the reader.
902 NaClDisassembleSegment(mbase, vbase, size,
903 NACL_DISASSEMBLE_FLAG(NaClDisassembleFull));
907 int main(int argc, const char *argv[]) {
909 struct GioFile gio_out_stream;
910 struct Gio *gout = (struct Gio*) &gio_out_stream;
913 fprintf(stderr, "expected: %s file\n", argv[0]);
917 /* Set up logging. */
918 if (!GioFileRefCtor(&gio_out_stream, stdout)) {
919 fprintf(stderr, "Unable to create gio file for stdout!\n");
922 NaClLogModuleInitExtended(LOG_INFO, gout);
923 NaClLogDisableTimestamp();
925 /* By default, assume no local cpu features are available. */
926 NaClClearCPUFeaturesX86(&ncval_cpu_features);
928 /* Validate the specified input. */
929 argc = GrokFlags(argc, argv);
930 if (0 == strcmp(NACL_FLAGS_hex_text, "")) {
931 /* Run validator on elf file. */
933 Bool success = NaClRunValidator(
935 (NaClValidateLoad) ValidateElfLoad,
936 (NaClValidateAnalyze) ValidateAnalyze);
937 NaClReportSafety(success, argv[1]);
938 result = (success ? 0 : 1);
940 /* Run validator on hex text file. */
941 NaClValidatorByteArray data;
942 argc = ValidateHexLoad(argc, argv, &data);
943 NaClRunValidatorBytes(
944 argc, argv, (uint8_t*) &data.bytes,
945 data.num_bytes, data.base);
946 NaClMaybeDecodeDataSegment(&data.bytes[0], data.base, data.num_bytes);
947 /* always succeed, so that the testing framework works. */