Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 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 | |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 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 | |
| 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; |
Chris Wailes | 44bef6f | 2014-08-12 13:51:10 -0700 | [diff] [blame^] | 57 | unsigned char const *image = nullptr; |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 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 | |
| 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 | |
| 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 | |
| 93 | void stub_srand(unsigned int seed) { |
| 94 | srand(seed); |
| 95 | } |
| 96 | |
| 97 | int stub_rand() { |
| 98 | return rand(); |
| 99 | } |
| 100 | |
| 101 | time_t stub_time(time_t *output) { |
| 102 | return time(output); |
| 103 | } |
| 104 | |
| 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."); |
Chris Wailes | 44bef6f | 2014-08-12 13:51:10 -0700 | [diff] [blame^] | 138 | return nullptr; |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 139 | } |
| 140 | |
| 141 | template <unsigned Bitwidth, typename Archiver> |
| 142 | void dump_and_run_object(Archiver &AR, int argc, char **argv) { |
Stephen Hines | c29686a | 2014-07-17 01:41:24 -0700 | [diff] [blame] | 143 | std::unique_ptr<ELFObject<Bitwidth> > object(ELFObject<Bitwidth>::read(AR)); |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 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> |
| 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 | |
| 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 | |
| 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 | |
| 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 | } |