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

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

Issue 625923004: Delete old x86 validator. (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 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.
5 */
6
7 /*
8 * ncval.c - command line validator for NaCl.
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 "native_client/src/include/portability.h"
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdarg.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <sys/timeb.h>
25 #include <time.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_histog ram.h"
37 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_memory_protec t.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_detai led.h"
42 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate_inter naltypes.h"
43 #include "native_client/src/trusted/validator_x86/nc_read_segment.h"
44 #include "native_client/src/trusted/validator_x86/ncdis_segments.h"
45
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_tab les.h"
49 #include "native_client/src/trusted/validator_x86/ncdis_decode_tables.h"
50 #endif
51
52 /* To turn on debugging of instruction decoding, change value of
53 * DEBUGGING to 1.
54 */
55 #define DEBUGGING 0
56
57 #include "native_client/src/shared/utils/debugging.h"
58
59 /* Forward declarations. */
60 static void usage(int exit_code);
61
62 #if NACL_TARGET_SUBARCH == 32
63 /* Flag defining if statistics should be printed for callback validator
64 * model.
65 */
66 static Bool NACL_FLAGS_stats_print = FALSE;
67 #endif
68
69 /* Flag defining if detailed error messages should be generated. When
70 * false, runs performance model as used by sel_ldr.
71 */
72 static Bool NACL_FLAGS_detailed_errors = TRUE;
73
74 /* Flag defining the name of a hex text to be used as the code segment.
75 */
76 static char *NACL_FLAGS_hex_text = "";
77
78 /* Define if we should process segments (rather than sections) when applying SFI
79 * validator.
80 */
81 static Bool NACL_FLAGS_analyze_segments = FALSE;
82
83 /* Define how many times we will analyze the code segment.
84 * Note: Values, other than 1, is only used for profiling.
85 */
86 static int NACL_FLAGS_validate_attempts = 1;
87
88 /* Define the set of CPU features to use while validating. */
89 static NaClCPUFeaturesX86 ncval_cpu_features;
90
91 /* Define whether timing should be applied when running the validator. */
92 static Bool NACL_FLAGS_print_timing = FALSE;
93
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.
97 */
98 static Bool NACL_FLAGS_warnings = FALSE;
99 static Bool NACL_FLAGS_errors = FALSE;
100 static Bool NACL_FLAGS_fatal = FALSE;
101
102 /* Define if special stubout tests should be run. Such
103 * tests apply stubout, and then print out the modified
104 * disassembled code.
105 */
106 static Bool NACL_FLAGS_stubout_memory = FALSE;
107
108 #if NACL_TARGET_SUBARCH == 64
109 /* Flag that allows validator decoder to be used in place of full decoder.
110 */
111 static Bool NACL_FLAGS_validator_decoder = FALSE;
112 #endif
113
114 /* Generates NaClErrorMapping for error level suffix. */
115 #define NaClError(s) { #s , LOG_## s}
116
117 /**************************************************
118 * Driver to apply the validator to a code segment
119 *************************************************/
120
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.
128 */
129 NaClLog(LOG_INFO, "STUBBED OUT as follows:\n");
130 } else {
131 #ifndef NCVAL_TESTING
132 if (success) {
133 NaClLog(LOG_INFO, "*** %s is safe ***\n", fname);
134 } else {
135 NaClLog(LOG_INFO, "*** %s IS UNSAFE ***\n", fname);
136 }
137 #endif
138 }
139 }
140
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>");
148 return;
149 }
150 }
151 NaClReportFileSafety(success, filename);
152 }
153
154 /* The model of data to be passed to the load/analyze steps. */
155 typedef void* NaClRunValidatorData;
156
157 /* The routine that loads the code segment(s) into memory (within
158 * the data arg). Returns true iff load was successful.
159 */
160 typedef Bool (*NaClValidateLoad)(int argc, const char* argv[],
161 NaClRunValidatorData data);
162
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.
166 */
167 typedef Bool (*NaClValidateAnalyze)(NaClRunValidatorData data);
168
169 /* Runs the validator using the given (command line) arguments.
170 *
171 * Parameters:
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
175 * two functions.
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.
179 */
180 static Bool NaClRunValidator(int argc, const char* argv[],
181 NaClRunValidatorData data,
182 NaClValidateLoad load,
183 NaClValidateAnalyze analyze) {
184 clock_t clock_0;
185 clock_t clock_l;
186 clock_t clock_v;
187 Bool return_value;
188
189 clock_0 = clock();
190 return_value = load(argc, argv, data);
191 if (!return_value) {
192 NaClValidatorMessage(LOG_ERROR, NULL, "Unable to load code to validate\n");
193 return FALSE;
194 }
195 clock_l = clock();
196 return_value = analyze(data);
197 clock_v = clock();
198
199 if (NACL_FLAGS_print_timing) {
200 NaClValidatorMessage(
201 LOG_INFO, NULL,
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);
205 }
206 return return_value;
207 }
208
209 /* Default loader that does nothing. Typically this is because
210 * the data argument already contains the bytes to validate.
211 */
212 Bool NaClValidateNoLoad(int argc, const char* argv[],
213 NaClRunValidatorData data) {
214 return TRUE;
215 }
216
217 /* Local file data for validator run. */
218 typedef struct ValidateData {
219 /* The name of the elf file to validate. */
220 const char *fname;
221 /* The elf file to validate. */
222 ncfile *ncf;
223 } ValidateData;
224
225 /* Load the elf file and return the loaded elf file. */
226 static Bool ValidateElfLoad(int argc, const char *argv[],
227 ValidateData *data) {
228 if (argc != 2) {
229 NaClLog(LOG_ERROR, "expected: %s file\n", argv[0]);
230 usage(2);
231 }
232 data->fname = argv[1];
233
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.
237 */
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));
241 usage(2);
242 }
243 return NULL != data->ncf;
244 }
245
246 /***************************************************
247 * Code to run SFI validator on hex text examples. *
248 ***************************************************/
249
250 /* Defines the maximum number of characters allowed on an input line
251 * of the input text defined by the commands command line option.
252 */
253 #define NACL_MAX_INPUT_LINE 4096
254
255 typedef struct NaClValidatorByteArray {
256 uint8_t bytes[NACL_MAX_INPUT_LINE];
257 NaClPcAddress base;
258 NaClMemorySize num_bytes;
259 } NaClValidatorByteArray;
260
261 static void HexFatal(const char *format, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
262
263 /* Print out given error message about the hex input file, and then exit. */
264 static void HexFatal(const char *format, ...) {
265 va_list ap;
266 va_start(ap, format);
267 NaClLogV(LOG_ERROR, format, ap);
268 va_end(ap);
269 /* always succed, so that the testing framework works. */
270 exit(0);
271 }
272
273 /* Load the hex input file from the given command line arguments,
274 * and put it into the given data structure.
275 */
276 static int ValidateHexLoad(int argc, const char *argv[],
277 NaClValidatorByteArray *data) {
278 if (argc != 1) {
279 HexFatal("expected: %s <options>\n", argv[0]);
280 }
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);
285 } else {
286 FILE *input = fopen(NACL_FLAGS_hex_text, "r");
287 if (NULL == input) {
288 HexFatal("Can't open hex text file: %s\n", NACL_FLAGS_hex_text);
289 }
290 data->num_bytes = (NaClMemorySize)
291 NaClReadHexTextWithPc(input, &data->base, data->bytes,
292 NACL_MAX_INPUT_LINE);
293 fclose(input);
294 --argc;
295 }
296 return argc;
297 }
298
299 #if NACL_TARGET_SUBARCH == 32
300 /***************************************
301 * Code to run segment based validator.*
302 ***************************************/
303
304 int AnalyzeSegmentSections(ncfile *ncf, struct NCValidatorState *vstate) {
305 int badsections = 0;
306 int ii;
307 const Elf_Phdr *phdr = ncf->pheaders;
308
309 for (ii = 0; ii < ncf->phnum; ii++) {
310 NaClLog(LOG_INFO,
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,
316 phdr[ii].p_align);
317
318 NaClLog(LOG_INFO,
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)))
324 continue;
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);
328 }
329 return -badsections;
330 }
331
332 /* Initialize segment validator, using detailed (summary) error
333 * messages if selected.
334 */
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);
340 }
341
342
343 static Bool AnalyzeSegmentCodeSegments(ncfile *ncf, const char *fname) {
344 NaClPcAddress vbase, vlimit;
345 struct NCValidatorState *vstate;
346 Bool result;
347
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);
354 }
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);
360 return result;
361 }
362 #endif
363
364 #if NACL_TARGET_SUBARCH == 64
365 /******************************
366 * Code to run SFI validator. *
367 ******************************/
368
369 /* Define what should be used as the base register for
370 * memory accesses.
371 */
372 static NaClOpKind nacl_base_register =
373 (64 == NACL_TARGET_SUBARCH ? RegR15 : RegUnknown);
374
375 /* Create validator state using detailed (summary) error messages
376 * if selected.
377 */
378 struct NaClValidatorState* NaClValStateCreate(
379 const NaClPcAddress vbase,
380 const NaClMemorySize sz,
381 const NaClOpKind base_register) {
382 return
383 NACL_FLAGS_detailed_errors
384 ? NaClValidatorStateCreateDetailed(vbase, sz, base_register,
385 &ncval_cpu_features)
386 : NaClValidatorStateCreate(vbase, sz, base_register, FALSE,
387 &ncval_cpu_features);
388 }
389
390 /* Returns the decoder tables to use. */
391 static const NaClDecodeTables* NaClGetDecoderTables(void) {
392 return NACL_FLAGS_validator_decoder
393 ? kNaClValDecoderTables
394 : kNaClDecoderTables;
395 }
396
397 /* Analyze each section in the given elf file, using the given validator
398 * state.
399 */
400 static void AnalyzeSfiSections(ncfile *ncf, struct NaClValidatorState *vstate) {
401 int ii;
402 const Elf_Phdr *phdr = ncf->pheaders;
403
404 for (ii = 0; ii < ncf->phnum; ii++) {
405 /* TODO(karl) fix types for this? */
406 NaClValidatorMessage(
407 LOG_INFO, vstate,
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,
414 phdr[ii].p_align);
415 NaClValidatorMessage(
416 LOG_INFO, vstate,
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,
421 phdr[ii].p_flags);
422 if ((PT_LOAD != phdr[ii].p_type) ||
423 (0 == (phdr[ii].p_flags & PF_X)))
424 continue;
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());
429 }
430 }
431
432 static void AnalyzeSfiSegments(ncfile *ncf, NaClValidatorState *state) {
433 int ii;
434 const Elf_Shdr *shdr = ncf->sheaders;
435
436 for (ii = 0; ii < ncf->shnum; ii++) {
437 NaClValidatorMessage(
438 LOG_INFO, state,
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)
443 continue;
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());
448 }
449 }
450
451 /* Analyze each code segment in the given elf file, stored in the
452 * file with the given path fname.
453 */
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;
459
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");
464 return FALSE;
465 }
466 NaClValidatorStateSetErrorReporter(vstate, &kNaClVerboseErrorReporter);
467 if (NACL_FLAGS_analyze_segments) {
468 AnalyzeSfiSegments(ncf, vstate);
469 } else {
470 AnalyzeSfiSections(ncf, vstate);
471 }
472 return_value = NaClValidatesOk(vstate);
473 NaClReportSafety(return_value, fname);
474 NaClValidatorStateDestroy(vstate);
475 return return_value;
476 }
477 #endif
478
479 /***************************
480 * Top-level driver code. *
481 **************************/
482
483 /* Analyze the code segments of the elf file in the validator date. */
484 static Bool ValidateAnalyze(ValidateData *data) {
485 int i;
486 Bool results = TRUE;
487 for (i = 0; i < NACL_FLAGS_validate_attempts; ++i) {
488 Bool return_value =
489 #if NACL_TARGET_SUBARCH == 64
490 AnalyzeSfiCodeSegments(data->ncf, data->fname);
491 #else
492 AnalyzeSegmentCodeSegments(data->ncf, data->fname);
493 #endif
494 if (!return_value) {
495 results = FALSE;
496 }
497 }
498 nc_freefile(data->ncf);
499 return results;
500 }
501
502 /* Define a sequence of bytes to validate whose virtual address begins at the
503 * given base.
504 */
505 typedef struct NaClValidateBytes {
506 /* The sequence of bytes to validate. */
507 uint8_t* bytes;
508 /* The number of bytes in the sequence. */
509 NaClMemorySize num_bytes;
510 /* The virtual base adddress associated with the first byte in the
511 * sequence.
512 */
513 NaClPcAddress base;
514 } NaClValidateBytes;
515
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,
522 data->num_bytes,
523 nacl_base_register);
524 if (NULL == state) {
525 NaClValidatorMessage(LOG_ERROR, NULL, "Unable to create validator state");
526 return FALSE;
527 }
528 if (NACL_FLAGS_stubout_memory) {
529 NaClValidatorStateSetDoStubOut(state, TRUE);
530 }
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");
538 }
539 NaClValidatorStateDestroy(state);
540 NaClReportSafety(return_value, "");
541 #else
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");
546 } else {
547 if (NACL_FLAGS_stubout_memory) {
548 NCValidateSetStubOutMode(vstate, 1);
549 }
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");
556 }
557 NaClReportSafety(return_value, "");
558 if (NACL_FLAGS_stats_print) NCStatsPrint(vstate);
559 NCValidateFreeState(&vstate);
560 }
561 #endif
562 return return_value;
563 }
564
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.
567 */
568 Bool NaClRunValidatorBytes(int argc,
569 const char* argv[],
570 uint8_t* bytes,
571 NaClMemorySize num_bytes,
572 NaClPcAddress base) {
573 NaClValidateBytes data;
574 int i;
575 Bool results = TRUE;
576 data.bytes = bytes;
577 data.num_bytes = num_bytes;
578 data.base = base;
579 for (i = 0; i < NACL_FLAGS_validate_attempts; ++i) {
580 if (!NaClRunValidator(argc, argv, &data,
581 (NaClValidateLoad) NaClValidateNoLoad,
582 (NaClValidateAnalyze) NaClValidateAnalyzeBytes)) {
583 results = FALSE;
584 }
585 }
586 return results;
587 }
588
589
590 static const char usage_str[] =
591 "usage: ncval [options] file\n"
592 "\n"
593 "\tValidates an x86-%d nexe file.\n"
594 "\n"
595 "Options are:\n"
596 "\n"
597 #ifdef NCVAL_TESTING
598 "--print_conditions\n"
599 "\tPrint all pre/post conditions, including NaCl illegal instructions.\n"
600 #endif
601 "--annotate\n"
602 "\tRun validator using annotations that will be understood\n"
603 "\tby ncval_annotate.py.\n"
604 "--attempts=N\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"
607 "--CLFLUSH\n"
608 "\tModel a CPU that supports the clflush instruction.\n"
609 "--CMOV\n"
610 "\tModel a CPU that supports the cmov instructions.\n"
611 #ifdef NCVAL_TESTING
612 "--conds\n"
613 "\tPrint out pre/post conditions associated with each instruction.\n"
614 #endif
615 "--cpuid-all\n"
616 "\tModel a CPU that supports all available features.\n"
617 "--cpuid-none\n"
618 "\tModel a CPU that supports no avaliable features.\n"
619 "--CX8\n"
620 "\tModel a CPU that supports the cmpxchg8b instruction.\n"
621 "--detailed\n"
622 "\tPrint out detailed error messages, rather than use performant\n"
623 "\tcode used by sel_ldr\n"
624 "--errors\n"
625 "\tPrint out error and fatal error messages, but not\n"
626 "\tinformative and warning messages\n"
627 "--fatal\n"
628 "\tOnly print out fatal error messages.\n"
629 "--FXSR\n"
630 "\tModel a CPU that supports the sfence instructions.\n"
631 "--help\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
638 "--histogram\n"
639 "\tPrint out a histogram of found opcodes.\n"
640 "--identity_mask\n"
641 "\tMask jumps using 0xFF instead of one matching\n"
642 "\tthe block alignment.\n"
643 #endif
644 "--local_cpuid\n"
645 "\tSet cpuid to values defined by local host this command is run on.\n"
646 "--LZCNT\n"
647 "\tModel a CPU that supports the lzcnt instruction.\n"
648 #if NACL_TARGET_SUBARCH == 64
649 "--max_errors=N\n"
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"
652 #endif
653 "--MMX\n"
654 "\tModel a CPU that supports MMX instructions.\n"
655 "--MOVBE\n"
656 "\tModel a CPU that supports the movbe instruction.\n"
657 "--POPCNT\n"
658 "\tModel a CPU that supports the popcnt instruction.\n"
659 #if NACL_TARGET_SUBARCH == 64
660 "--readwrite_sfi\n"
661 "\tCheck for memory read and write software fault isolation.\n"
662 "--segments\n"
663 "\tAnalyze code in segments in elf file, instead of headers.\n"
664 #endif
665 "--SSE\n"
666 "\tModel a CPU that supports SSE instructions.\n"
667 "--SSE2\n"
668 "\tModel a CPU that supports SSE 2 instructions.\n"
669 "--SSE3\n"
670 "\tModel a CPU that supports SSE 3 instructions.\n"
671 "--SSSE3\n"
672 "\tModel a CPU that supports SSSE 3 instructions.\n"
673 "--SSE41\n"
674 "\tModel a CPU that supports SSE 4.1 instructions.\n"
675 "--SSE42\n"
676 "\tModel a CPU that supports SSE 4.2 instructions.\n"
677 "--SSE4A\n"
678 "\tModel a CPU that supports SSE 4A instructions.\n"
679 #if NACL_TARGET_SUBARCH == 32
680 "--stats\n"
681 "\tPrint statistics collected by the validator.\n"
682 #endif
683 "--stubout\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"
687 "\talso specified\n"
688 "-t\n"
689 "\tTime the validator and print out results.\n"
690 "--TSC\n"
691 "\tModel a CPU that supports the rdtsc instruction.\n"
692 "--x87\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"
697 #endif
698 "--3DNOW\n"
699 "\tModel a CPU that supports 3DNOW instructions.\n"
700 "--E3DNOW\n"
701 "\tModel a CPU that supports E3DNOW instructions.\n"
702 "\n"
703 "--time\n"
704 "\tTime the validator and print out results. Same as option -t.\n"
705 #if NACL_TARGET_SUBARCH == 64
706 "--trace_insts\n"
707 "\tTurn on validator trace of instructions, as processed..\n"
708 "--trace_verbose\n"
709 "\tTurn on all trace validator messages. Note: this\n"
710 "\tflag also implies --trace.\n"
711 #endif
712 "--warnings\n"
713 "\tPrint out warnings, errors, and fatal errors, but not\n"
714 "\tinformative messages.\n"
715 #if NACL_TARGET_SUBARCH == 64
716 "--write_sfi\n"
717 "\tOnly check for memory write software fault isolation.\n"
718 #endif
719 "\n";
720
721 static void usage(int exit_code) {
722 printf(usage_str, NACL_TARGET_SUBARCH);
723 exit(exit_code);
724 }
725
726 /* Checks if arg is one of the expected "Bool" flags, and if so, sets
727 * the corresponding flag and returns true.
728 */
729 static Bool GrokABoolFlag(const char *arg) {
730 /* A set of boolean flags to be checked */
731 static struct {
732 const char *flag_name;
733 Bool *flag_ptr;
734 } flags[] = {
735 { "--segments" , &NACL_FLAGS_analyze_segments },
736 #ifdef NCVAL_TESTING
737 { "--print_all_conds", &NACL_FLAGS_report_conditions_on_all },
738 #else
739 { "--detailed", &NACL_FLAGS_detailed_errors },
740 #endif
741 { "--stubout", &NACL_FLAGS_stubout_memory },
742 #if NACL_TARGET_SUBARCH == 64
743 { "--trace_insts", &NACL_FLAGS_validator_trace_instructions },
744 #endif
745 { "-t", &NACL_FLAGS_print_timing },
746 #if NACL_TARGET_SUBARCH == 32
747 { "--stats", &NACL_FLAGS_stats_print },
748 #endif
749 { "--annotate", &NACL_FLAGS_ncval_annotate },
750 #if NACL_TARGET_SUBARCH == 64
751 { "--histogram", &NACL_FLAGS_opcode_histogram },
752 #endif
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 },
759 #endif
760 { "--identity_mask", &NACL_FLAGS_identity_mask },
761 };
762
763 /* A set of CPU features to check. */
764 static struct {
765 const char *feature_name;
766 NaClCPUFeatureX86ID feature;
767 } features[] = {
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 },
791 };
792
793 int i;
794 Bool flag_state;
795 for (i = 0; i < NACL_ARRAY_SIZE(flags); ++i) {
796 if (GrokBoolFlag(flags[i].flag_name, arg, flags[i].flag_ptr)) {
797 return TRUE;
798 }
799 }
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,
803 flag_state);
804 return TRUE;
805 }
806 }
807
808 return FALSE;
809 }
810
811 /* Checks if arg is one of the expected "int" flags, and if so, sets
812 * the corresponding flag and returns true.
813 */
814 static Bool GrokAnIntFlag(const char *arg) {
815 /* A set of boolean flags to be checked */
816 static struct {
817 const char *flag_name;
818 int *flag_ptr;
819 } flags[] = {
820 { "--max_errors", &NACL_FLAGS_max_reported_errors},
821 { "--attempts" , &NACL_FLAGS_validate_attempts },
822 };
823 int i;
824 for (i = 0; i < NACL_ARRAY_SIZE(flags); ++i) {
825 if (GrokIntFlag(flags[i].flag_name, arg, flags[i].flag_ptr)) {
826 return TRUE;
827 }
828 }
829 return FALSE;
830 }
831
832 static int GrokFlags(int argc, const char *argv[]) {
833 int i;
834 int new_argc;
835 Bool help = FALSE;
836 #if NACL_TARGET_SUBARCH == 64
837 Bool only_write_sandbox;
838 #endif
839 if (argc == 0) return 0;
840 new_argc = 1;
841 for (i = 1; i < argc; ++i) {
842 Bool flag;
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)) {
849 usage(0);
850 }
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)) {
858 }
859 #endif
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);
866 } else {
867 argv[new_argc++] = argv[i];
868 }
869 }
870
871 /* Before returning, update internals to match command line
872 * values found.
873 */
874 if (NACL_FLAGS_warnings) {
875 NaClLogSetVerbosity(LOG_WARNING);
876 }
877 if (NACL_FLAGS_errors) {
878 NaClLogSetVerbosity(LOG_ERROR);
879 }
880 if (NACL_FLAGS_fatal) {
881 NaClLogSetVerbosity(LOG_FATAL);
882 }
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");
886 }
887
888 return new_argc;
889 }
890
891 /* Decode and print out code segment if stubout memory is specified
892 * command line.
893 */
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.
901 */
902 NaClDisassembleSegment(mbase, vbase, size,
903 NACL_DISASSEMBLE_FLAG(NaClDisassembleFull));
904 }
905 }
906
907 int main(int argc, const char *argv[]) {
908 int result = 0;
909 struct GioFile gio_out_stream;
910 struct Gio *gout = (struct Gio*) &gio_out_stream;
911
912 if (argc < 2) {
913 fprintf(stderr, "expected: %s file\n", argv[0]);
914 usage(1);
915 }
916
917 /* Set up logging. */
918 if (!GioFileRefCtor(&gio_out_stream, stdout)) {
919 fprintf(stderr, "Unable to create gio file for stdout!\n");
920 return 1;
921 }
922 NaClLogModuleInitExtended(LOG_INFO, gout);
923 NaClLogDisableTimestamp();
924
925 /* By default, assume no local cpu features are available. */
926 NaClClearCPUFeaturesX86(&ncval_cpu_features);
927
928 /* Validate the specified input. */
929 argc = GrokFlags(argc, argv);
930 if (0 == strcmp(NACL_FLAGS_hex_text, "")) {
931 /* Run validator on elf file. */
932 ValidateData data;
933 Bool success = NaClRunValidator(
934 argc, argv, &data,
935 (NaClValidateLoad) ValidateElfLoad,
936 (NaClValidateAnalyze) ValidateAnalyze);
937 NaClReportSafety(success, argv[1]);
938 result = (success ? 0 : 1);
939 } else {
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. */
948 result = 0;
949 }
950
951 NaClLogModuleFini();
952 GioFileDtor(gout);
953 return result;
954 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698