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