Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2011-2012, 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 "librsloader.h" |
| 18 | |
| 19 | #include "ELFObject.h" |
| 20 | #include "ELFSectionSymTab.h" |
| 21 | #include "ELFSymbol.h" |
| 22 | |
| 23 | #include "utils/serialize.h" |
| 24 | |
| 25 | #define LOG_TAG "bcc" |
| 26 | #include "cutils/log.h" |
| 27 | |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 28 | #include <llvm/Support/ELF.h> |
| 29 | |
Logan Chien | 8d50174 | 2014-05-26 23:07:47 +0800 | [diff] [blame] | 30 | #if defined(__LP64__) || defined(__x86_64__) |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 31 | static inline RSExecRef wrap(ELFObject<64> *object) { |
| 32 | return reinterpret_cast<RSExecRef>(object); |
| 33 | } |
| 34 | #else |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 35 | static inline RSExecRef wrap(ELFObject<32> *object) { |
| 36 | return reinterpret_cast<RSExecRef>(object); |
| 37 | } |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 38 | #endif |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 39 | |
Logan Chien | 8d50174 | 2014-05-26 23:07:47 +0800 | [diff] [blame] | 40 | #if defined(__LP64__) || defined(__x86_64__) |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 41 | static inline ELFObject<64> *unwrap(RSExecRef object) { |
| 42 | return reinterpret_cast<ELFObject<64> *>(object); |
| 43 | } |
| 44 | #else |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 45 | static inline ELFObject<32> *unwrap(RSExecRef object) { |
| 46 | return reinterpret_cast<ELFObject<32> *>(object); |
| 47 | } |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 48 | #endif |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 49 | |
| 50 | extern "C" RSExecRef rsloaderCreateExec(unsigned char const *buf, |
| 51 | size_t buf_size, |
| 52 | RSFindSymbolFn find_symbol, |
| 53 | void *find_symbol_context) { |
| 54 | RSExecRef object = rsloaderLoadExecutable(buf, buf_size); |
| 55 | if (!object) { |
| 56 | return NULL; |
| 57 | } |
| 58 | |
| 59 | if (!rsloaderRelocateExecutable(object, find_symbol, find_symbol_context)) { |
| 60 | rsloaderDisposeExec(object); |
| 61 | return NULL; |
| 62 | } |
| 63 | |
| 64 | return object; |
| 65 | } |
| 66 | |
| 67 | extern "C" RSExecRef rsloaderLoadExecutable(unsigned char const *buf, |
| 68 | size_t buf_size) { |
| 69 | ArchiveReaderLE AR(buf, buf_size); |
| 70 | |
Logan Chien | 8d50174 | 2014-05-26 23:07:47 +0800 | [diff] [blame] | 71 | #if defined(__LP64__) || defined(__x86_64__) |
Stephen Hines | c29686a | 2014-07-17 01:41:24 -0700 | [diff] [blame] | 72 | std::unique_ptr<ELFObject<64> > object(ELFObject<64>::read(AR)); |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 73 | #else |
Stephen Hines | c29686a | 2014-07-17 01:41:24 -0700 | [diff] [blame] | 74 | std::unique_ptr<ELFObject<32> > object(ELFObject<32>::read(AR)); |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 75 | #endif |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 76 | if (!object) { |
| 77 | ALOGE("Unable to load the ELF object."); |
| 78 | return NULL; |
| 79 | } |
| 80 | |
Stephen Hines | c29686a | 2014-07-17 01:41:24 -0700 | [diff] [blame] | 81 | return wrap(object.release()); |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 82 | } |
| 83 | |
| 84 | extern "C" int rsloaderRelocateExecutable(RSExecRef object_, |
| 85 | RSFindSymbolFn find_symbol, |
| 86 | void *find_symbol_context) { |
Logan Chien | 8d50174 | 2014-05-26 23:07:47 +0800 | [diff] [blame] | 87 | #if defined(__LP64__) || defined(__x86_64__) |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 88 | ELFObject<64>* object = unwrap(object_); |
| 89 | #else |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 90 | ELFObject<32>* object = unwrap(object_); |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 91 | #endif |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 92 | object->relocate(find_symbol, find_symbol_context); |
| 93 | return (object->getMissingSymbols() == 0); |
| 94 | } |
| 95 | |
| 96 | extern "C" void rsloaderUpdateSectionHeaders(RSExecRef object_, |
| 97 | unsigned char *buf) { |
Logan Chien | 8d50174 | 2014-05-26 23:07:47 +0800 | [diff] [blame] | 98 | #if defined(__LP64__) || defined(__x86_64__) |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 99 | ELFObject<64> *object = unwrap(object_); |
| 100 | #else |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 101 | ELFObject<32> *object = unwrap(object_); |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 102 | #endif |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 103 | |
| 104 | // Remap the section header addresses to match the loaded code |
Logan Chien | 8d50174 | 2014-05-26 23:07:47 +0800 | [diff] [blame] | 105 | #if defined(__LP64__) || defined(__x86_64__) |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 106 | llvm::ELF::Elf64_Ehdr* header = reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(buf); |
| 107 | #else |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 108 | llvm::ELF::Elf32_Ehdr* header = reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(buf); |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 109 | #endif |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 110 | |
Logan Chien | 8d50174 | 2014-05-26 23:07:47 +0800 | [diff] [blame] | 111 | #if defined(__LP64__) || defined(__x86_64__) |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 112 | llvm::ELF::Elf64_Shdr* shtab = |
| 113 | reinterpret_cast<llvm::ELF::Elf64_Shdr*>(buf + header->e_shoff); |
| 114 | #else |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 115 | llvm::ELF::Elf32_Shdr* shtab = |
| 116 | reinterpret_cast<llvm::ELF::Elf32_Shdr*>(buf + header->e_shoff); |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 117 | #endif |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 118 | |
| 119 | for (int i = 0; i < header->e_shnum; i++) { |
| 120 | if (shtab[i].sh_flags & SHF_ALLOC) { |
Logan Chien | 8d50174 | 2014-05-26 23:07:47 +0800 | [diff] [blame] | 121 | #if defined(__LP64__) || defined(__x86_64__) |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 122 | ELFSectionBits<64>* bits = |
| 123 | static_cast<ELFSectionBits<64>*>(object->getSectionByIndex(i)); |
| 124 | #else |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 125 | ELFSectionBits<32>* bits = |
| 126 | static_cast<ELFSectionBits<32>*>(object->getSectionByIndex(i)); |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 127 | #endif |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 128 | if (bits) { |
| 129 | const unsigned char* addr = bits->getBuffer(); |
Logan Chien | 8d50174 | 2014-05-26 23:07:47 +0800 | [diff] [blame] | 130 | #if defined(__LP64__) || defined(__x86_64__) |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 131 | shtab[i].sh_addr = reinterpret_cast<llvm::ELF::Elf64_Addr>(addr); |
Ian Rogers | f8852d0 | 2014-01-29 15:35:17 -0800 | [diff] [blame] | 132 | #else |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 133 | shtab[i].sh_addr = reinterpret_cast<llvm::ELF::Elf32_Addr>(addr); |
Ian Rogers | f8852d0 | 2014-01-29 15:35:17 -0800 | [diff] [blame] | 134 | #endif |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 135 | } |
| 136 | } |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | extern "C" void rsloaderDisposeExec(RSExecRef object) { |
| 141 | delete unwrap(object); |
| 142 | } |
| 143 | |
| 144 | extern "C" void *rsloaderGetSymbolAddress(RSExecRef object_, |
| 145 | char const *name) { |
Logan Chien | 8d50174 | 2014-05-26 23:07:47 +0800 | [diff] [blame] | 146 | #if defined(__LP64__) || defined(__x86_64__) |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 147 | ELFObject<64> *object = unwrap(object_); |
| 148 | |
| 149 | ELFSectionSymTab<64> *symtab = |
| 150 | static_cast<ELFSectionSymTab<64> *>(object->getSectionByName(".symtab")); |
| 151 | #else |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 152 | ELFObject<32> *object = unwrap(object_); |
| 153 | |
| 154 | ELFSectionSymTab<32> *symtab = |
| 155 | static_cast<ELFSectionSymTab<32> *>(object->getSectionByName(".symtab")); |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 156 | #endif |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 157 | |
| 158 | if (!symtab) { |
| 159 | return NULL; |
| 160 | } |
| 161 | |
Logan Chien | 8d50174 | 2014-05-26 23:07:47 +0800 | [diff] [blame] | 162 | #if defined(__LP64__) || defined(__x86_64__) |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 163 | ELFSymbol<64> *symbol = symtab->getByName(name); |
| 164 | #else |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 165 | ELFSymbol<32> *symbol = symtab->getByName(name); |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 166 | #endif |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 167 | |
| 168 | if (!symbol) { |
| 169 | ALOGV("Symbol not found: %s\n", name); |
| 170 | return NULL; |
| 171 | } |
| 172 | |
| 173 | int machine = object->getHeader()->getMachine(); |
| 174 | |
| 175 | return symbol->getAddress(machine, false); |
| 176 | } |
| 177 | |
| 178 | extern "C" size_t rsloaderGetSymbolSize(RSExecRef object_, char const *name) { |
Logan Chien | 8d50174 | 2014-05-26 23:07:47 +0800 | [diff] [blame] | 179 | #if defined(__LP64__) || defined(__x86_64__) |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 180 | ELFObject<64> *object = unwrap(object_); |
| 181 | |
| 182 | ELFSectionSymTab<64> *symtab = |
| 183 | static_cast<ELFSectionSymTab<64> *>(object->getSectionByName(".symtab")); |
| 184 | #else |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 185 | ELFObject<32> *object = unwrap(object_); |
| 186 | |
| 187 | ELFSectionSymTab<32> *symtab = |
| 188 | static_cast<ELFSectionSymTab<32> *>(object->getSectionByName(".symtab")); |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 189 | #endif |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 190 | if (!symtab) { |
| 191 | return 0; |
| 192 | } |
| 193 | |
Logan Chien | 8d50174 | 2014-05-26 23:07:47 +0800 | [diff] [blame] | 194 | #if defined(__LP64__) || defined(__x86_64__) |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 195 | ELFSymbol<64> *symbol = symtab->getByName(name); |
| 196 | #else |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 197 | ELFSymbol<32> *symbol = symtab->getByName(name); |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 198 | #endif |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 199 | |
| 200 | if (!symbol) { |
| 201 | ALOGV("Symbol not found: %s\n", name); |
| 202 | return 0; |
| 203 | } |
| 204 | |
| 205 | return (size_t)symbol->getSize(); |
| 206 | } |
| 207 | |
| 208 | extern "C" size_t rsloaderGetFuncCount(RSExecRef object) { |
Logan Chien | 8d50174 | 2014-05-26 23:07:47 +0800 | [diff] [blame] | 209 | #if defined(__LP64__) || defined(__x86_64__) |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 210 | ELFSectionSymTab<64> *symtab = static_cast<ELFSectionSymTab<64> *>( |
| 211 | #else |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 212 | ELFSectionSymTab<32> *symtab = static_cast<ELFSectionSymTab<32> *>( |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 213 | #endif |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 214 | unwrap(object)->getSectionByName(".symtab")); |
| 215 | |
| 216 | if (!symtab) { |
| 217 | return 0; |
| 218 | } |
| 219 | |
| 220 | return symtab->getFuncCount(); |
| 221 | } |
| 222 | |
| 223 | extern "C" void rsloaderGetFuncNameList(RSExecRef object, |
| 224 | size_t size, |
| 225 | char const **list) { |
Logan Chien | 8d50174 | 2014-05-26 23:07:47 +0800 | [diff] [blame] | 226 | #if defined(__LP64__) || defined(__x86_64__) |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 227 | ELFSectionSymTab<64> *symtab = static_cast<ELFSectionSymTab<64> *>( |
| 228 | #else |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 229 | ELFSectionSymTab<32> *symtab = static_cast<ELFSectionSymTab<32> *>( |
WeiTang | db2ffd2 | 2014-04-04 23:26:44 +0800 | [diff] [blame] | 230 | #endif |
Stephen Hines | b53c8a5 | 2013-04-05 22:17:36 -0700 | [diff] [blame] | 231 | unwrap(object)->getSectionByName(".symtab")); |
| 232 | |
| 233 | if (symtab) { |
| 234 | symtab->getFuncNameList(size, list); |
| 235 | } |
| 236 | } |