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 31using namespace std; 32 33bool open_mmap_file(char const *filename, 34 int &fd, 35 unsigned char const *&image, 36 size_t &size); 37 38void close_mmap_file(int fd, 39 unsigned char const *image, 40 size_t size); 41 42void dump_and_run_file(unsigned char const *image, size_t size, 43 int argc, char **argv); 44 45int 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 77int 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 85int 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 93void stub_srand(unsigned int seed) { 94 srand(seed); 95} 96 97int stub_rand() { 98 return rand(); 99} 100 101time_t stub_time(time_t *output) { 102 return time(output); 103} 104 105void *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 141template <unsigned Bitwidth, typename Archiver> 142void 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 170template <typename Archiver> 171void 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 180void 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 209bool 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 247void 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