LCOV - code coverage report
Current view: directory - src/tools/validator_tools - ncstubout.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 77 52 67.5 %
Date: 2012-02-16 Functions: 0 0 -

       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                 :  * This tool rewrites ELF files to replace instructions that will be
       9                 :  * rejected by the validator with safe HLT instructions.  This is
      10                 :  * useful if you have a large library in which many functions do not
      11                 :  * validate but are not immediately required to work.  Replacing the
      12                 :  * forbidden instructions with HLTs makes it easier to find the
      13                 :  * instructions that are needed first, and fix and test them.
      14                 :  */
      15                 : 
      16                 : #include <assert.h>
      17                 : #include <stdio.h>
      18                 : #include <string.h>
      19                 : 
      20                 : #include "native_client/src/include/elf.h"
      21                 : #include "native_client/src/shared/gio/gio.h"
      22                 : #include "native_client/src/shared/platform/nacl_check.h"
      23                 : #include "native_client/src/shared/utils/types.h"
      24                 : #include "native_client/src/trusted/validator/cpufeatures.h"
      25                 : #include "native_client/src/trusted/validator/ncvalidate.h"
      26                 : 
      27                 : static Bool FixUpSection(uintptr_t load_address,
      28                 :                          unsigned char *code,
      29               3 :                          size_t code_size) {
      30               3 :   int bundle_size = 32;
      31               3 :   enum NaClSBKind sb_kind = NACL_SB_DEFAULT;
      32                 :   NaClValidationStatus status;
      33                 :   NaClCPUFeatures cpu_features;
      34                 :   /* Pretend that the CPU supports every feature so that we will only stub out
      35                 :    * instructions that NaCl will never allow under any condition.
      36                 :    */
      37               3 :   NaClSetAllCPUFeatures(&cpu_features);
      38                 : 
      39               3 :   status = NACL_SUBARCH_NAME(ApplyValidator,
      40                 :                              NACL_TARGET_ARCH,
      41                 :                              NACL_TARGET_SUBARCH)
      42                 :       (sb_kind, NaClApplyValidationDoStubout, load_address, code,
      43                 :        code_size,  bundle_size, &cpu_features);
      44               3 :   if (status == NaClValidationSucceeded) {
      45                 :     /* Now run the validator again, so that we report any errors
      46                 :      * that were not fixed by stubbing out. This is done so that
      47                 :      * the user knows that stubout doesn't fix all errors.
      48                 :      */
      49               3 :     status = NACL_SUBARCH_NAME(ApplyValidatorVerbosely,
      50                 :                                NACL_TARGET_ARCH,
      51                 :                                NACL_TARGET_SUBARCH)
      52                 :         (sb_kind, NaClApplyCodeValidation, load_address, code, code_size,
      53                 :          bundle_size, &cpu_features);
      54                 :   }
      55                 : 
      56               3 :   switch (status) {
      57                 :     case NaClValidationSucceeded:
      58               3 :       return TRUE;
      59                 :     default:
      60                 :     case NaClValidationFailed:
      61               0 :       fprintf(stderr, "Errors still exist after attempting to stubout code\n");
      62               0 :       return FALSE;
      63                 :     case NaClValidationFailedOutOfMemory:
      64               0 :       fprintf(stderr, "Unable to stubout code, not enough memory\n");
      65               0 :       return FALSE;
      66                 :     case NaClValidationFailedNotImplemented:
      67               0 :       fprintf(stderr, "Unable to stubout code, not implemented\n");
      68               0 :       return FALSE;
      69                 :     case NaClValidationFailedCpuNotSupported:
      70                 :       /* This shouldn't happen, but if it does, report the problem. */
      71               0 :       fprintf(stderr, "Unable to stubout code, cpu not supported\n");
      72               0 :       return FALSE;
      73                 :     case NaClValidationFailedSegmentationIssue:
      74               0 :       fprintf(stderr, "Unable to stubout code, segmentation issues found\n");
      75               0 :       return FALSE;
      76                 :   }
      77                 : }
      78                 : 
      79                 : static void CheckBounds(unsigned char *data, size_t data_size,
      80              30 :                         void *ptr, size_t inside_size) {
      81              30 :   CHECK(data <= (unsigned char *) ptr);
      82              30 :   CHECK((unsigned char *) ptr + inside_size <= data + data_size);
      83              30 : }
      84                 : 
      85               1 : static Bool FixUpELF32(unsigned char *data, size_t data_size) {
      86                 :   Elf32_Ehdr *header;
      87                 :   int index;
      88               1 :   Bool fixed = TRUE;  /* until proven otherwise. */
      89                 : 
      90               1 :   header = (Elf32_Ehdr *) data;
      91               1 :   CheckBounds(data, data_size, header, sizeof(*header));
      92               1 :   CHECK(memcmp(header->e_ident, ELFMAG, strlen(ELFMAG)) == 0);
      93                 : 
      94              27 :   for (index = 0; index < header->e_shnum; index++) {
      95                 :     Elf32_Shdr *section = (Elf32_Shdr *) (data + header->e_shoff +
      96              26 :                                           header->e_shentsize * index);
      97              26 :     CheckBounds(data, data_size, section, sizeof(*section));
      98                 : 
      99              26 :     if ((section->sh_flags & SHF_EXECINSTR) != 0) {
     100               3 :       CheckBounds(data, data_size,
     101                 :                   data + section->sh_offset, section->sh_size);
     102               3 :       if (!FixUpSection(section->sh_addr,
     103                 :                         data + section->sh_offset, section->sh_size)) {
     104               0 :         fixed = FALSE;
     105                 :       }
     106                 :     }
     107                 :   }
     108               1 :   return fixed;
     109                 : }
     110                 : 
     111                 : #if NACL_TARGET_SUBARCH == 64
     112                 : static Bool FixUpELF64(unsigned char *data, size_t data_size) {
     113                 :   Elf64_Ehdr *header;
     114                 :   int index;
     115                 :   Bool fixed = TRUE;  /* until proven otherwise. */
     116                 : 
     117                 :   header = (Elf64_Ehdr *) data;
     118                 :   CheckBounds(data, data_size, header, sizeof(*header));
     119                 :   CHECK(memcmp(header->e_ident, ELFMAG, strlen(ELFMAG)) == 0);
     120                 : 
     121                 :   for (index = 0; index < header->e_shnum; index++) {
     122                 :     Elf64_Shdr *section = (Elf64_Shdr *) (data + header->e_shoff +
     123                 :                                           header->e_shentsize * index);
     124                 :     CheckBounds(data, data_size, section, sizeof(*section));
     125                 : 
     126                 :     if ((section->sh_flags & SHF_EXECINSTR) != 0) {
     127                 :       CheckBounds(data, data_size,
     128                 :                   data + section->sh_offset, section->sh_size);
     129                 :       if (!FixUpSection(section->sh_addr,
     130                 :                         data + section->sh_offset, section->sh_size)) {
     131                 :         fixed = FALSE;
     132                 :       }
     133                 :     }
     134                 :   }
     135                 :   return fixed;
     136                 : }
     137                 : #endif
     138                 : 
     139               1 : static Bool FixUpELF(unsigned char *data, size_t data_size) {
     140                 : #if NACL_TARGET_SUBARCH == 64
     141                 :   if (data_size > EI_CLASS && data[EI_CLASS] == ELFCLASS64)
     142                 :     return FixUpELF64(data, data_size);
     143                 : #endif
     144               1 :   return FixUpELF32(data, data_size);
     145                 : }
     146                 : 
     147               1 : static Bool FixUpELFFile(const char *input_file, const char *output_file) {
     148                 :   FILE *fp;
     149                 :   size_t file_size;
     150                 :   unsigned char *data;
     151                 :   size_t got;
     152                 :   size_t written;
     153                 : 
     154                 :   /* Read whole ELF file and write it back with modifications. */
     155               1 :   fp = fopen(input_file, "rb");
     156               1 :   if (fp == NULL) {
     157               0 :     fprintf(stderr, "Failed to open input file: %s\n", input_file);
     158               0 :     return FALSE;
     159                 :   }
     160                 :   /* Find the file size. */
     161               1 :   fseek(fp, 0, SEEK_END);
     162               1 :   file_size = ftell(fp);
     163               1 :   data = malloc(file_size);
     164               1 :   if (data == NULL) {
     165               0 :     fprintf(stderr, "Unable to create memory imate of input file: %s\n",
     166                 :             input_file);
     167               0 :     return FALSE;
     168                 :   }
     169               1 :   fseek(fp, 0, SEEK_SET);
     170               1 :   got = fread(data, 1, file_size, fp);
     171               1 :   if (got != file_size) {
     172               0 :     fprintf(stderr, "Unable to read data from input file: %s\n",
     173                 :             input_file);
     174               0 :     return FALSE;
     175                 :   }
     176               1 :   fclose(fp);
     177                 : 
     178               1 :   if (!FixUpELF(data, file_size)) return FALSE;
     179                 : 
     180               1 :   fp = fopen(output_file, "wb");
     181               1 :   if (fp == NULL) {
     182               0 :     fprintf(stderr, "Failed to open output file: %s\n", output_file);
     183               0 :     return FALSE;
     184                 :   }
     185               1 :   written = fwrite(data, 1, file_size, fp);
     186               1 :   if (written != file_size) {
     187               0 :     fprintf(stderr, "Unable to write data to output file: %s\n",
     188                 :             output_file);
     189               0 :     return FALSE;
     190                 :   }
     191               1 :   fclose(fp);
     192               1 :   return TRUE;
     193                 : }
     194                 : 
     195               1 : int main(int argc, const char *argv[]) {
     196                 :   /* Be sure to redirect validator error messages to stderr. */
     197                 :   struct GioFile err;
     198               1 :   GioFileRefCtor(&err, stderr);
     199               1 :   NaClLogPreInitSetGio((struct Gio*) &err);
     200               1 :   NaClLogModuleInit();
     201               1 :   if (argc != 4 || strcmp(argv[2], "-o") != 0) {
     202               0 :     fprintf(stderr, "Usage: %s <input-file> -o <output-file>\n\n", argv[0]);
     203               0 :     fprintf(stderr,
     204                 :             "This tool rewrites ELF objects to replace instructions that are\n"
     205                 :             "rejected by the NaCl validator with safe HLT instructions.\n");
     206               0 :     GioFileDtor((struct Gio*) &err);
     207               0 :     return 1;
     208                 :   }
     209               1 :   GioFileDtor((struct Gio*) &err);
     210               1 :   return FixUpELFFile(argv[1], argv[3]) ? 0 : 1;
     211                 : }

Generated by: LCOV version 1.7