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 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 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 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 95 void stub_srand(unsigned int seed) { 96 srand(seed); 97 } 98 99 int stub_rand() { 100 return rand(); 101 } 102 103 time_t stub_time(time_t *output) { 104 return time(output); 105 } 106 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> 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> 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 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 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 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