Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / native_client / src / tools / validator_tools / ncstubout.c
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/ncvalidate.h"
25
26 static Bool FixUpSectionCheckStatus(NaClValidationStatus status) {
27   switch (status) {
28     case NaClValidationSucceeded:
29       return TRUE;
30     default:
31     case NaClValidationFailed:
32       fprintf(stderr, "Errors still exist after attempting to stubout code\n");
33       return FALSE;
34     case NaClValidationFailedOutOfMemory:
35       fprintf(stderr, "Unable to stubout code, not enough memory\n");
36       return FALSE;
37     case NaClValidationFailedNotImplemented:
38       fprintf(stderr, "Unable to stubout code, not implemented\n");
39       return FALSE;
40     case NaClValidationFailedCpuNotSupported:
41       /* This shouldn't happen, but if it does, report the problem. */
42       fprintf(stderr, "Unable to stubout code, cpu not supported\n");
43       return FALSE;
44     case NaClValidationFailedSegmentationIssue:
45       fprintf(stderr, "Unable to stubout code, segmentation issues found\n");
46       return FALSE;
47   }
48   return FALSE;
49 }
50
51 static Bool FixUpSection(const struct NaClValidatorInterface *validator,
52                          uintptr_t load_address,
53                          unsigned char *code,
54                          size_t code_size) {
55   Bool result;
56   NaClValidationStatus status;
57   NaClCPUFeatures *cpu_features = malloc(validator->CPUFeatureSize);
58   if (cpu_features == NULL) {
59     fprintf(stderr, "Unable to create memory for CPU features\n");
60     return FALSE;
61   }
62   /* Pretend that the CPU supports every feature so that we will only stub out
63    * instructions that NaCl will never allow under any condition.
64    */
65   validator->SetAllCPUFeatures(cpu_features);
66
67   status = validator->Validate(
68       load_address, code, code_size,
69       /* stubout_mode= */ TRUE,
70       /* readonly_text= */ FALSE,
71       cpu_features,
72       /* metadata= */ NULL,
73       /* cache= */ NULL);
74   if (status == NaClValidationSucceeded) {
75     /* Now run the validator again, so that we report any errors
76      * that were not fixed by stubbing out. This is done so that
77      * the user knows that stubout doesn't fix all errors.
78      */
79     status = NACL_SUBARCH_NAME(ApplyValidatorVerbosely,
80                                NACL_TARGET_ARCH,
81                                NACL_TARGET_SUBARCH)
82         (load_address, code, code_size, cpu_features);
83   }
84
85   result = FixUpSectionCheckStatus(status);
86   free(cpu_features);
87   return result;
88 }
89
90 static void CheckBounds(unsigned char *data, size_t data_size,
91                         void *ptr, size_t inside_size) {
92   CHECK(data <= (unsigned char *) ptr);
93   CHECK((unsigned char *) ptr + inside_size <= data + data_size);
94 }
95
96 static Bool FixUpELF32(const struct NaClValidatorInterface *validator,
97                        unsigned char *data,
98                        size_t data_size) {
99   Elf32_Ehdr *header;
100   int index;
101   Bool fixed = TRUE;  /* until proven otherwise. */
102
103   header = (Elf32_Ehdr *) data;
104   CheckBounds(data, data_size, header, sizeof(*header));
105   CHECK(memcmp(header->e_ident, ELFMAG, strlen(ELFMAG)) == 0);
106
107   for (index = 0; index < header->e_shnum; index++) {
108     Elf32_Shdr *section = (Elf32_Shdr *) (data + header->e_shoff +
109                                           header->e_shentsize * index);
110     CheckBounds(data, data_size, section, sizeof(*section));
111
112     if ((section->sh_flags & SHF_EXECINSTR) != 0) {
113       CheckBounds(data, data_size,
114                   data + section->sh_offset, section->sh_size);
115       if (!FixUpSection(validator,
116                         section->sh_addr,
117                         data + section->sh_offset,
118                         section->sh_size)) {
119         fixed = FALSE;
120       }
121     }
122   }
123   return fixed;
124 }
125
126 #if NACL_TARGET_SUBARCH == 64
127 static Bool FixUpELF64(const struct NaClValidatorInterface *validator,
128                        unsigned char *data,
129                        size_t data_size) {
130   Elf64_Ehdr *header;
131   int index;
132   Bool fixed = TRUE;  /* until proven otherwise. */
133
134   header = (Elf64_Ehdr *) data;
135   CheckBounds(data, data_size, header, sizeof(*header));
136   CHECK(memcmp(header->e_ident, ELFMAG, strlen(ELFMAG)) == 0);
137
138   for (index = 0; index < header->e_shnum; index++) {
139     Elf64_Shdr *section = (Elf64_Shdr *) (data + header->e_shoff +
140                                           header->e_shentsize * index);
141     CheckBounds(data, data_size, section, sizeof(*section));
142
143     if ((section->sh_flags & SHF_EXECINSTR) != 0) {
144       CheckBounds(data, data_size,
145                   data + section->sh_offset, section->sh_size);
146       if (!FixUpSection(validator,
147                         section->sh_addr,
148                         data + section->sh_offset,
149                         section->sh_size)) {
150         fixed = FALSE;
151       }
152     }
153   }
154   return fixed;
155 }
156 #endif
157
158 static Bool FixUpELF(const struct NaClValidatorInterface *validator,
159                      unsigned char *data,
160                      size_t data_size) {
161 #if NACL_TARGET_SUBARCH == 64
162   if (data_size > EI_CLASS && data[EI_CLASS] == ELFCLASS64)
163     return FixUpELF64(validator, data, data_size);
164 #endif
165   return FixUpELF32(validator, data, data_size);
166 }
167
168 static Bool FixUpELFFile(const struct NaClValidatorInterface *validator,
169                          const char *input_file,
170                          const char *output_file) {
171   FILE *fp;
172   size_t file_size;
173   unsigned char *data;
174   size_t got;
175   size_t written;
176
177   /* Read whole ELF file and write it back with modifications. */
178   fp = fopen(input_file, "rb");
179   if (fp == NULL) {
180     fprintf(stderr, "Failed to open input file: %s\n", input_file);
181     return FALSE;
182   }
183   /* Find the file size. */
184   fseek(fp, 0, SEEK_END);
185   file_size = ftell(fp);
186   data = malloc(file_size);
187   if (data == NULL) {
188     fprintf(stderr, "Unable to create memory imate of input file: %s\n",
189             input_file);
190     return FALSE;
191   }
192   fseek(fp, 0, SEEK_SET);
193   got = fread(data, 1, file_size, fp);
194   if (got != file_size) {
195     fprintf(stderr, "Unable to read data from input file: %s\n",
196             input_file);
197     return FALSE;
198   }
199   fclose(fp);
200
201   if (!FixUpELF(validator, data, file_size)) return FALSE;
202
203   fp = fopen(output_file, "wb");
204   if (fp == NULL) {
205     fprintf(stderr, "Failed to open output file: %s\n", output_file);
206     return FALSE;
207   }
208   written = fwrite(data, 1, file_size, fp);
209   if (written != file_size) {
210     fprintf(stderr, "Unable to write data to output file: %s\n",
211             output_file);
212     return FALSE;
213   }
214   fclose(fp);
215   return TRUE;
216 }
217
218 int main(int argc, const char *argv[]) {
219   /* Be sure to redirect validator error messages to stderr. */
220   const struct NaClValidatorInterface *validator;
221   NaClLogModuleInit();
222   validator = NaClCreateValidator();
223   if (!validator->stubout_mode_implemented) {
224     fprintf(stderr,
225             "This platform does not support stubout mode.");
226     return 1;
227   }
228   if (argc != 4 || strcmp(argv[2], "-o") != 0) {
229     fprintf(stderr, "Usage: %s <input-file> -o <output-file>\n\n", argv[0]);
230     fprintf(stderr,
231             "This tool rewrites ELF objects to replace instructions that are\n"
232             "rejected by the NaCl validator with safe HLT instructions.\n");
233     return 1;
234   }
235   return FixUpELFFile(validator, argv[1], argv[3]) ? 0 : 1;
236 }