• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "ELFObject.h"
18 
19 #include "utils/serialize.h"
20 #include "ELF.h"
21 
22 #include <fcntl.h>
23 #include <stdlib.h>
24 #include <sys/mman.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <map>
28 #include <stdio.h>
29 #include <stdarg.h>
30 
31 using namespace std;
32 
33 bool open_mmap_file(char const *filename,
34                     int &fd,
35                     unsigned char const *&image,
36                     size_t &size);
37 
38 void close_mmap_file(int fd,
39                      unsigned char const *image,
40                      size_t size);
41 
42 void dump_and_run_file(unsigned char const *image, size_t size,
43                        int argc, char **argv);
44 
main(int argc,char ** argv)45 int main(int argc, char **argv) {
46   // Check arguments
47   if (argc < 2) {
48     llvm::errs() << "USAGE: " << argv[0] << " [ELFObjectFile] [ARGS]\n";
49     exit(EXIT_FAILURE);
50   }
51 
52   // Filename from argument
53   char const *filename = argv[1];
54 
55   // Open the file
56   int fd = -1;
57   unsigned char const *image = NULL;
58   size_t image_size = 0;
59 
60   if (!open_mmap_file(filename, fd, image, image_size)) {
61     exit(EXIT_FAILURE);
62   }
63 
64   // Dump and run the file
65   dump_and_run_file(image, image_size, argc - 1, argv + 1);
66 
67   // Close the file
68   close_mmap_file(fd, image, image_size);
69 
70   return EXIT_SUCCESS;
71 }
72 
73 // FIXME: I don't like these stub as well.  However, before we implement
74 // x86 64bit far jump stub, we have to ensure find_sym only returns
75 // near address.
76 
stub_printf(char const * fmt,...)77 int stub_printf(char const *fmt, ...) {
78   va_list ap;
79   va_start(ap, fmt);
80   int result = vprintf(fmt, ap);
81   va_end(ap);
82   return result;
83 }
84 
stub_scanf(char const * fmt,...)85 int stub_scanf(char const *fmt, ...) {
86   va_list ap;
87   va_start(ap, fmt);
88   int result = vscanf(fmt, ap);
89   va_end(ap);
90   return result;
91 }
92 
stub_srand(unsigned int seed)93 void stub_srand(unsigned int seed) {
94   srand(seed);
95 }
96 
stub_rand()97 int stub_rand() {
98   return rand();
99 }
100 
stub_time(time_t * output)101 time_t stub_time(time_t *output) {
102   return time(output);
103 }
104 
find_sym(void * context,char const * name)105 void *find_sym(void *context, char const *name) {
106   struct func_entry_t {
107     char const *name;
108     size_t name_len;
109     void *addr;
110   };
111 
112   static func_entry_t const tab[] = {
113 #define DEF(NAME, ADDR) \
114     { NAME, sizeof(NAME) - 1, (void *)(ADDR) },
115 
116     DEF("printf", stub_printf)
117     DEF("scanf", stub_scanf)
118     DEF("__isoc99_scanf", stub_scanf)
119     DEF("rand", stub_rand)
120     DEF("time", stub_time)
121     DEF("srand", stub_srand)
122 #undef DEF
123   };
124 
125   static size_t const tab_size = sizeof(tab) / sizeof(func_entry_t);
126 
127   // Note: Since our table is small, we are using trivial O(n) searching
128   // function.  For bigger table, it will be better to use binary
129   // search or hash function.
130   size_t name_len = strlen(name);
131   for (size_t i = 0; i < tab_size; ++i) {
132     if (name_len == tab[i].name_len && strcmp(name, tab[i].name) == 0) {
133       return tab[i].addr;
134     }
135   }
136 
137   assert(0 && "Can't find symbol.");
138   return 0;
139 }
140 
141 template <unsigned Bitwidth, typename Archiver>
dump_and_run_object(Archiver & AR,int argc,char ** argv)142 void dump_and_run_object(Archiver &AR, int argc, char **argv) {
143   std::unique_ptr<ELFObject<Bitwidth> > object(ELFObject<Bitwidth>::read(AR));
144 
145   if (!object) {
146     llvm::errs() << "ERROR: Unable to load object\n";
147   }
148 
149   object->print();
150   out().flush();
151 
152   ELFSectionSymTab<Bitwidth> *symtab =
153     static_cast<ELFSectionSymTab<Bitwidth> *>(
154         object->getSectionByName(".symtab"));
155 
156   object->relocate(find_sym, 0);
157   out() << "relocate finished!\n";
158   out().flush();
159 
160   int machine = object->getHeader()->getMachine();
161 
162   void *main_addr = symtab->getByName("main")->getAddress(machine);
163   out() << "main address: " << main_addr << "\n";
164   out().flush();
165 
166   ((int (*)(int, char **))main_addr)(argc, argv);
167   fflush(stdout);
168 }
169 
170 template <typename Archiver>
dump_and_run_file_from_archive(bool is32bit,Archiver & AR,int argc,char ** argv)171 void dump_and_run_file_from_archive(bool is32bit, Archiver &AR,
172                                     int argc, char **argv) {
173   if (is32bit) {
174     dump_and_run_object<32>(AR, argc, argv);
175   } else {
176     dump_and_run_object<64>(AR, argc, argv);
177   }
178 }
179 
dump_and_run_file(unsigned char const * image,size_t size,int argc,char ** argv)180 void dump_and_run_file(unsigned char const *image, size_t size,
181                        int argc, char **argv) {
182   if (size < EI_NIDENT) {
183     llvm::errs() << "ERROR: ELF identification corrupted.\n";
184     return;
185   }
186 
187   if (image[EI_DATA] != ELFDATA2LSB && image[EI_DATA] != ELFDATA2MSB) {
188     llvm::errs() << "ERROR: Unknown endianness.\n";
189     return;
190   }
191 
192   if (image[EI_CLASS] != ELFCLASS32 && image[EI_CLASS] != ELFCLASS64) {
193     llvm::errs() << "ERROR: Unknown machine class.\n";
194     return;
195   }
196 
197   bool isLittleEndian = (image[EI_DATA] == ELFDATA2LSB);
198   bool is32bit = (image[EI_CLASS] == ELFCLASS32);
199 
200   if (isLittleEndian) {
201     ArchiveReaderLE AR(image, size);
202     dump_and_run_file_from_archive(is32bit, AR, argc, argv);
203   } else {
204     ArchiveReaderBE AR(image, size);
205     dump_and_run_file_from_archive(is32bit, AR, argc, argv);
206   }
207 }
208 
open_mmap_file(char const * filename,int & fd,unsigned char const * & image,size_t & size)209 bool open_mmap_file(char const *filename,
210                     int &fd,
211                     unsigned char const *&image,
212                     size_t &size) {
213   // Query the file status
214   struct stat sb;
215   if (stat(filename, &sb) != 0) {
216     llvm::errs() << "ERROR: " << filename << " not found.\n";
217     return false;
218   }
219 
220   if (!S_ISREG(sb.st_mode)) {
221     llvm::errs() << "ERROR: " << filename << " is not a regular file.\n";
222     return false;
223   }
224 
225   size = (size_t)sb.st_size;
226 
227   // Open the file in readonly mode
228   fd = open(filename, O_RDONLY);
229   if (fd < 0) {
230     llvm::errs() << "ERROR: Unable to open " << filename << "\n";
231     return false;
232   }
233 
234   // Map the file image
235   image = static_cast<unsigned char const *>(
236     mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0));
237 
238   if (image == MAP_FAILED) {
239     llvm::errs() << "ERROR: Unable to map " << filename << " to memory.\n";
240     close(fd);
241     return false;
242   }
243 
244   return true;
245 }
246 
close_mmap_file(int fd,unsigned char const * image,size_t size)247 void close_mmap_file(int fd,
248                      unsigned char const *image,
249                      size_t size) {
250   if (image) {
251     munmap((void *)image, size);
252   }
253 
254   if (fd >= 0) {
255     close(fd);
256   }
257 }
258