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 void *main_addr = symtab->getByName("main")->getAddress();
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