Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2014 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 "elf_patcher.h" |
| 18 | |
| 19 | #include <vector> |
| 20 | #include <set> |
| 21 | |
Andreas Gampe | 53c913b | 2014-08-12 23:19:23 -0700 | [diff] [blame] | 22 | #include "class_linker.h" |
Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 23 | #include "elf_file.h" |
| 24 | #include "elf_utils.h" |
| 25 | #include "mirror/art_field-inl.h" |
| 26 | #include "mirror/art_method-inl.h" |
| 27 | #include "mirror/array-inl.h" |
| 28 | #include "mirror/class-inl.h" |
| 29 | #include "mirror/class_loader.h" |
| 30 | #include "mirror/dex_cache-inl.h" |
| 31 | #include "mirror/object-inl.h" |
| 32 | #include "mirror/object_array-inl.h" |
| 33 | #include "mirror/string-inl.h" |
| 34 | #include "oat.h" |
| 35 | #include "os.h" |
| 36 | #include "utils.h" |
| 37 | |
| 38 | namespace art { |
| 39 | |
| 40 | bool ElfPatcher::Patch(const CompilerDriver* driver, ElfFile* elf_file, |
| 41 | const std::string& oat_location, |
| 42 | ImageAddressCallback cb, void* cb_data, |
| 43 | std::string* error_msg) { |
| 44 | ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); |
| 45 | const OatFile* oat_file = class_linker->FindOpenedOatFileFromOatLocation(oat_location); |
| 46 | if (oat_file == nullptr) { |
| 47 | CHECK(Runtime::Current()->IsCompiler()); |
| 48 | oat_file = OatFile::Open(oat_location, oat_location, NULL, false, error_msg); |
| 49 | if (oat_file == nullptr) { |
| 50 | *error_msg = StringPrintf("Unable to find or open oat file at '%s': %s", oat_location.c_str(), |
| 51 | error_msg->c_str()); |
| 52 | return false; |
| 53 | } |
| 54 | CHECK_EQ(class_linker->RegisterOatFile(oat_file), oat_file); |
| 55 | } |
| 56 | return ElfPatcher::Patch(driver, elf_file, oat_file, |
| 57 | reinterpret_cast<uintptr_t>(oat_file->Begin()), cb, cb_data, error_msg); |
| 58 | } |
| 59 | |
| 60 | bool ElfPatcher::Patch(const CompilerDriver* driver, ElfFile* elf, const OatFile* oat_file, |
| 61 | uintptr_t oat_data_start, ImageAddressCallback cb, void* cb_data, |
| 62 | std::string* error_msg) { |
| 63 | Elf32_Shdr* data_sec = elf->FindSectionByName(".rodata"); |
| 64 | if (data_sec == nullptr) { |
| 65 | *error_msg = "Unable to find .rodata section and oat header"; |
| 66 | return false; |
| 67 | } |
| 68 | OatHeader* oat_header = reinterpret_cast<OatHeader*>(elf->Begin() + data_sec->sh_offset); |
| 69 | if (!oat_header->IsValid()) { |
| 70 | *error_msg = "Oat header was not valid"; |
| 71 | return false; |
| 72 | } |
| 73 | |
| 74 | ElfPatcher p(driver, elf, oat_file, oat_header, oat_data_start, cb, cb_data, error_msg); |
| 75 | return p.PatchElf(); |
| 76 | } |
| 77 | |
| 78 | mirror::ArtMethod* ElfPatcher::GetTargetMethod(const CompilerDriver::CallPatchInformation* patch) { |
| 79 | ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); |
| 80 | StackHandleScope<1> hs(Thread::Current()); |
| 81 | Handle<mirror::DexCache> dex_cache( |
| 82 | hs.NewHandle(class_linker->FindDexCache(*patch->GetTargetDexFile()))); |
| 83 | mirror::ArtMethod* method = class_linker->ResolveMethod(*patch->GetTargetDexFile(), |
| 84 | patch->GetTargetMethodIdx(), |
| 85 | dex_cache, |
| 86 | NullHandle<mirror::ClassLoader>(), |
| 87 | NullHandle<mirror::ArtMethod>(), |
| 88 | patch->GetTargetInvokeType()); |
| 89 | CHECK(method != NULL) |
| 90 | << patch->GetTargetDexFile()->GetLocation() << " " << patch->GetTargetMethodIdx(); |
| 91 | CHECK(!method->IsRuntimeMethod()) |
| 92 | << patch->GetTargetDexFile()->GetLocation() << " " << patch->GetTargetMethodIdx(); |
| 93 | CHECK(dex_cache->GetResolvedMethods()->Get(patch->GetTargetMethodIdx()) == method) |
| 94 | << patch->GetTargetDexFile()->GetLocation() << " " << patch->GetReferrerMethodIdx() << " " |
| 95 | << PrettyMethod(dex_cache->GetResolvedMethods()->Get(patch->GetTargetMethodIdx())) << " " |
| 96 | << PrettyMethod(method); |
| 97 | return method; |
| 98 | } |
| 99 | |
| 100 | mirror::Class* ElfPatcher::GetTargetType(const CompilerDriver::TypePatchInformation* patch) { |
| 101 | ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); |
| 102 | StackHandleScope<2> hs(Thread::Current()); |
Fred Shih | e7f82e2 | 2014-08-06 10:46:37 -0700 | [diff] [blame] | 103 | Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache( |
| 104 | patch->GetTargetTypeDexFile()))); |
| 105 | mirror::Class* klass = class_linker->ResolveType(patch->GetTargetTypeDexFile(), |
| 106 | patch->GetTargetTypeIdx(), |
Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 107 | dex_cache, NullHandle<mirror::ClassLoader>()); |
| 108 | CHECK(klass != NULL) |
Fred Shih | e7f82e2 | 2014-08-06 10:46:37 -0700 | [diff] [blame] | 109 | << patch->GetTargetTypeDexFile().GetLocation() << " " << patch->GetTargetTypeIdx(); |
Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 110 | CHECK(dex_cache->GetResolvedTypes()->Get(patch->GetTargetTypeIdx()) == klass) |
| 111 | << patch->GetDexFile().GetLocation() << " " << patch->GetReferrerMethodIdx() << " " |
| 112 | << PrettyClass(dex_cache->GetResolvedTypes()->Get(patch->GetTargetTypeIdx())) << " " |
| 113 | << PrettyClass(klass); |
| 114 | return klass; |
| 115 | } |
| 116 | |
| 117 | void ElfPatcher::AddPatch(uintptr_t p) { |
| 118 | if (write_patches_ && patches_set_.find(p) == patches_set_.end()) { |
| 119 | patches_set_.insert(p); |
| 120 | patches_.push_back(p); |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | uint32_t* ElfPatcher::GetPatchLocation(uintptr_t patch_ptr) { |
| 125 | CHECK_GE(patch_ptr, reinterpret_cast<uintptr_t>(oat_file_->Begin())); |
Alex Light | 6e183f2 | 2014-07-18 14:57:04 -0700 | [diff] [blame] | 126 | CHECK_LE(patch_ptr, reinterpret_cast<uintptr_t>(oat_file_->End())); |
Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 127 | uintptr_t off = patch_ptr - reinterpret_cast<uintptr_t>(oat_file_->Begin()); |
| 128 | uintptr_t ret = reinterpret_cast<uintptr_t>(oat_header_) + off; |
| 129 | |
| 130 | CHECK_GE(ret, reinterpret_cast<uintptr_t>(elf_file_->Begin())); |
| 131 | CHECK_LT(ret, reinterpret_cast<uintptr_t>(elf_file_->End())); |
| 132 | return reinterpret_cast<uint32_t*>(ret); |
| 133 | } |
| 134 | |
| 135 | void ElfPatcher::SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value) { |
| 136 | ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); |
| 137 | const void* quick_oat_code = class_linker->GetQuickOatCodeFor(patch->GetDexFile(), |
| 138 | patch->GetReferrerClassDefIdx(), |
| 139 | patch->GetReferrerMethodIdx()); |
| 140 | // TODO: make this Thumb2 specific |
| 141 | uint8_t* base = reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(quick_oat_code) & ~0x1); |
| 142 | uintptr_t patch_ptr = reinterpret_cast<uintptr_t>(base + patch->GetLiteralOffset()); |
| 143 | uint32_t* patch_location = GetPatchLocation(patch_ptr); |
| 144 | if (kIsDebugBuild) { |
| 145 | if (patch->IsCall()) { |
| 146 | const CompilerDriver::CallPatchInformation* cpatch = patch->AsCall(); |
| 147 | const DexFile::MethodId& id = |
| 148 | cpatch->GetTargetDexFile()->GetMethodId(cpatch->GetTargetMethodIdx()); |
| 149 | uint32_t expected = reinterpret_cast<uintptr_t>(&id) & 0xFFFFFFFF; |
| 150 | uint32_t actual = *patch_location; |
Alex Light | 6e183f2 | 2014-07-18 14:57:04 -0700 | [diff] [blame] | 151 | CHECK(actual == expected || actual == value) << "Patching call failed: " << std::hex |
| 152 | << " actual=" << actual |
| 153 | << " expected=" << expected |
| 154 | << " value=" << value; |
Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 155 | } |
| 156 | if (patch->IsType()) { |
| 157 | const CompilerDriver::TypePatchInformation* tpatch = patch->AsType(); |
Fred Shih | e7f82e2 | 2014-08-06 10:46:37 -0700 | [diff] [blame] | 158 | const DexFile::TypeId& id = tpatch->GetTargetTypeDexFile().GetTypeId(tpatch->GetTargetTypeIdx()); |
Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 159 | uint32_t expected = reinterpret_cast<uintptr_t>(&id) & 0xFFFFFFFF; |
| 160 | uint32_t actual = *patch_location; |
Alex Light | 6e183f2 | 2014-07-18 14:57:04 -0700 | [diff] [blame] | 161 | CHECK(actual == expected || actual == value) << "Patching type failed: " << std::hex |
| 162 | << " actual=" << actual |
| 163 | << " expected=" << expected |
| 164 | << " value=" << value; |
Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 165 | } |
| 166 | } |
| 167 | *patch_location = value; |
| 168 | oat_header_->UpdateChecksum(patch_location, sizeof(value)); |
| 169 | |
| 170 | if (patch->IsCall() && patch->AsCall()->IsRelative()) { |
| 171 | // We never record relative patches. |
| 172 | return; |
| 173 | } |
| 174 | uintptr_t loc = patch_ptr - (reinterpret_cast<uintptr_t>(oat_file_->Begin()) + |
| 175 | oat_header_->GetExecutableOffset()); |
| 176 | CHECK_GT(patch_ptr, reinterpret_cast<uintptr_t>(oat_file_->Begin()) + |
| 177 | oat_header_->GetExecutableOffset()); |
| 178 | CHECK_LT(loc, oat_file_->Size() - oat_header_->GetExecutableOffset()); |
| 179 | AddPatch(loc); |
| 180 | } |
| 181 | |
| 182 | bool ElfPatcher::PatchElf() { |
| 183 | // TODO if we are adding patches the resulting ELF file might have a |
| 184 | // potentially rather large amount of free space where patches might have been |
| 185 | // placed. We should adjust the ELF file to get rid of this excess space. |
| 186 | if (write_patches_) { |
| 187 | patches_.reserve(compiler_driver_->GetCodeToPatch().size() + |
| 188 | compiler_driver_->GetMethodsToPatch().size() + |
| 189 | compiler_driver_->GetClassesToPatch().size()); |
| 190 | } |
| 191 | Thread* self = Thread::Current(); |
| 192 | ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); |
| 193 | const char* old_cause = self->StartAssertNoThreadSuspension("ElfPatcher"); |
| 194 | |
| 195 | typedef std::vector<const CompilerDriver::CallPatchInformation*> CallPatches; |
| 196 | const CallPatches& code_to_patch = compiler_driver_->GetCodeToPatch(); |
| 197 | for (size_t i = 0; i < code_to_patch.size(); i++) { |
| 198 | const CompilerDriver::CallPatchInformation* patch = code_to_patch[i]; |
| 199 | |
| 200 | mirror::ArtMethod* target = GetTargetMethod(patch); |
| 201 | uintptr_t quick_code = reinterpret_cast<uintptr_t>(class_linker->GetQuickOatCodeFor(target)); |
| 202 | DCHECK_NE(quick_code, 0U) << PrettyMethod(target); |
Vladimir Marko | aa4497d | 2014-09-05 14:01:17 +0100 | [diff] [blame] | 203 | const OatFile* target_oat = |
| 204 | class_linker->FindOpenedOatDexFileForDexFile(*patch->GetTargetDexFile())->GetOatFile(); |
Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 205 | // Get where the data actually starts. if target is this oat_file_ it is oat_data_start_, |
| 206 | // otherwise it is wherever target_oat is loaded. |
| 207 | uintptr_t oat_data_addr = GetBaseAddressFor(target_oat); |
| 208 | uintptr_t code_base = reinterpret_cast<uintptr_t>(target_oat->Begin()); |
| 209 | uintptr_t code_offset = quick_code - code_base; |
| 210 | bool is_quick_offset = false; |
| 211 | if (quick_code == reinterpret_cast<uintptr_t>(GetQuickToInterpreterBridge())) { |
| 212 | is_quick_offset = true; |
| 213 | code_offset = oat_header_->GetQuickToInterpreterBridgeOffset(); |
| 214 | } else if (quick_code == |
| 215 | reinterpret_cast<uintptr_t>(class_linker->GetQuickGenericJniTrampoline())) { |
| 216 | CHECK(target->IsNative()); |
| 217 | is_quick_offset = true; |
| 218 | code_offset = oat_header_->GetQuickGenericJniTrampolineOffset(); |
| 219 | } |
| 220 | uintptr_t value; |
| 221 | if (patch->IsRelative()) { |
| 222 | // value to patch is relative to the location being patched |
| 223 | const void* quick_oat_code = |
| 224 | class_linker->GetQuickOatCodeFor(patch->GetDexFile(), |
| 225 | patch->GetReferrerClassDefIdx(), |
| 226 | patch->GetReferrerMethodIdx()); |
| 227 | if (is_quick_offset) { |
| 228 | // If its a quick offset it means that we are doing a relative patch from the class linker |
| 229 | // oat_file to the elf_patcher oat_file so we need to adjust the quick oat code to be the |
| 230 | // one in the output oat_file (ie where it is actually going to be loaded). |
| 231 | quick_code = PointerToLowMemUInt32(reinterpret_cast<void*>(oat_data_addr + code_offset)); |
| 232 | quick_oat_code = |
| 233 | reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(quick_oat_code) + |
| 234 | oat_data_addr - code_base); |
| 235 | } |
| 236 | uintptr_t base = reinterpret_cast<uintptr_t>(quick_oat_code); |
| 237 | uintptr_t patch_location = base + patch->GetLiteralOffset(); |
| 238 | value = quick_code - patch_location + patch->RelativeOffset(); |
| 239 | } else if (code_offset != 0) { |
| 240 | value = PointerToLowMemUInt32(reinterpret_cast<void*>(oat_data_addr + code_offset)); |
| 241 | } else { |
| 242 | value = 0; |
| 243 | } |
| 244 | SetPatchLocation(patch, value); |
| 245 | } |
| 246 | |
| 247 | const CallPatches& methods_to_patch = compiler_driver_->GetMethodsToPatch(); |
| 248 | for (size_t i = 0; i < methods_to_patch.size(); i++) { |
| 249 | const CompilerDriver::CallPatchInformation* patch = methods_to_patch[i]; |
| 250 | mirror::ArtMethod* target = GetTargetMethod(patch); |
| 251 | SetPatchLocation(patch, PointerToLowMemUInt32(get_image_address_(cb_data_, target))); |
| 252 | } |
| 253 | |
| 254 | const std::vector<const CompilerDriver::TypePatchInformation*>& classes_to_patch = |
| 255 | compiler_driver_->GetClassesToPatch(); |
| 256 | for (size_t i = 0; i < classes_to_patch.size(); i++) { |
| 257 | const CompilerDriver::TypePatchInformation* patch = classes_to_patch[i]; |
| 258 | mirror::Class* target = GetTargetType(patch); |
| 259 | SetPatchLocation(patch, PointerToLowMemUInt32(get_image_address_(cb_data_, target))); |
| 260 | } |
| 261 | |
| 262 | self->EndAssertNoThreadSuspension(old_cause); |
| 263 | |
| 264 | if (write_patches_) { |
| 265 | return WriteOutPatchData(); |
| 266 | } |
| 267 | return true; |
| 268 | } |
| 269 | |
| 270 | bool ElfPatcher::WriteOutPatchData() { |
| 271 | Elf32_Shdr* shdr = elf_file_->FindSectionByName(".oat_patches"); |
| 272 | if (shdr != nullptr) { |
| 273 | CHECK_EQ(shdr, elf_file_->FindSectionByType(SHT_OAT_PATCH)) |
| 274 | << "Incorrect type for .oat_patches section"; |
| 275 | CHECK_LE(patches_.size() * sizeof(uintptr_t), shdr->sh_size) |
| 276 | << "We got more patches than anticipated"; |
| 277 | CHECK_LE(reinterpret_cast<uintptr_t>(elf_file_->Begin()) + shdr->sh_offset + shdr->sh_size, |
| 278 | reinterpret_cast<uintptr_t>(elf_file_->End())) << "section is too large"; |
Andreas Gampe | daab38c | 2014-09-12 18:38:24 -0700 | [diff] [blame] | 279 | CHECK(shdr == elf_file_->GetSectionHeader(elf_file_->GetSectionHeaderNum() - 1) || |
Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 280 | shdr->sh_offset + shdr->sh_size <= (shdr + 1)->sh_offset) |
| 281 | << "Section overlaps onto next section"; |
| 282 | // It's mmap'd so we can just memcpy. |
| 283 | memcpy(elf_file_->Begin() + shdr->sh_offset, patches_.data(), |
| 284 | patches_.size() * sizeof(uintptr_t)); |
| 285 | // TODO We should fill in the newly empty space between the last patch and |
| 286 | // the start of the next section by moving the following sections down if |
| 287 | // possible. |
| 288 | shdr->sh_size = patches_.size() * sizeof(uintptr_t); |
| 289 | return true; |
| 290 | } else { |
| 291 | LOG(ERROR) << "Unable to find section header for SHT_OAT_PATCH"; |
| 292 | *error_msg_ = "Unable to find section to write patch information to in "; |
| 293 | *error_msg_ += elf_file_->GetFile().GetPath(); |
| 294 | return false; |
| 295 | } |
| 296 | } |
| 297 | |
| 298 | } // namespace art |