patchoat.cc revision c6ea7d00ad069a2736f603daa3d8eaa9a1f8ea11
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#include "patchoat.h" 17 18#include <stdio.h> 19#include <stdlib.h> 20#include <sys/file.h> 21#include <sys/stat.h> 22#include <unistd.h> 23 24#include <string> 25#include <vector> 26 27#include "android-base/stringprintf.h" 28#include "android-base/strings.h" 29 30#include "art_field-inl.h" 31#include "art_method-inl.h" 32#include "base/dumpable.h" 33#include "base/scoped_flock.h" 34#include "base/stringpiece.h" 35#include "base/unix_file/fd_file.h" 36#include "base/unix_file/random_access_file_utils.h" 37#include "elf_utils.h" 38#include "elf_file.h" 39#include "elf_file_impl.h" 40#include "gc/space/image_space.h" 41#include "image-inl.h" 42#include "mirror/dex_cache.h" 43#include "mirror/executable.h" 44#include "mirror/object-inl.h" 45#include "mirror/object-refvisitor-inl.h" 46#include "mirror/method.h" 47#include "mirror/reference.h" 48#include "noop_compiler_callbacks.h" 49#include "offsets.h" 50#include "os.h" 51#include "runtime.h" 52#include "scoped_thread_state_change-inl.h" 53#include "thread.h" 54#include "utils.h" 55 56namespace art { 57 58static const OatHeader* GetOatHeader(const ElfFile* elf_file) { 59 uint64_t off = 0; 60 if (!elf_file->GetSectionOffsetAndSize(".rodata", &off, nullptr)) { 61 return nullptr; 62 } 63 64 OatHeader* oat_header = reinterpret_cast<OatHeader*>(elf_file->Begin() + off); 65 return oat_header; 66} 67 68static File* CreateOrOpen(const char* name) { 69 if (OS::FileExists(name)) { 70 return OS::OpenFileReadWrite(name); 71 } else { 72 std::unique_ptr<File> f(OS::CreateEmptyFile(name)); 73 if (f.get() != nullptr) { 74 if (fchmod(f->Fd(), 0644) != 0) { 75 PLOG(ERROR) << "Unable to make " << name << " world readable"; 76 unlink(name); 77 return nullptr; 78 } 79 } 80 return f.release(); 81 } 82} 83 84// Either try to close the file (close=true), or erase it. 85static bool FinishFile(File* file, bool close) { 86 if (close) { 87 if (file->FlushCloseOrErase() != 0) { 88 PLOG(ERROR) << "Failed to flush and close file."; 89 return false; 90 } 91 return true; 92 } else { 93 file->Erase(); 94 return false; 95 } 96} 97 98static bool SymlinkFile(const std::string& input_filename, const std::string& output_filename) { 99 if (input_filename == output_filename) { 100 // Input and output are the same, nothing to do. 101 return true; 102 } 103 104 // Unlink the original filename, since we are overwriting it. 105 unlink(output_filename.c_str()); 106 107 // Create a symlink from the source file to the target path. 108 if (symlink(input_filename.c_str(), output_filename.c_str()) < 0) { 109 PLOG(ERROR) << "Failed to create symlink " << output_filename << " -> " << input_filename; 110 return false; 111 } 112 113 if (kIsDebugBuild) { 114 LOG(INFO) << "Created symlink " << output_filename << " -> " << input_filename; 115 } 116 117 return true; 118} 119 120bool PatchOat::Patch(const std::string& image_location, 121 off_t delta, 122 const std::string& output_directory, 123 InstructionSet isa, 124 TimingLogger* timings) { 125 CHECK(Runtime::Current() == nullptr); 126 CHECK(!image_location.empty()) << "image file must have a filename."; 127 128 TimingLogger::ScopedTiming t("Runtime Setup", timings); 129 130 CHECK_NE(isa, kNone); 131 const char* isa_name = GetInstructionSetString(isa); 132 133 // Set up the runtime 134 RuntimeOptions options; 135 NoopCompilerCallbacks callbacks; 136 options.push_back(std::make_pair("compilercallbacks", &callbacks)); 137 std::string img = "-Ximage:" + image_location; 138 options.push_back(std::make_pair(img.c_str(), nullptr)); 139 options.push_back(std::make_pair("imageinstructionset", reinterpret_cast<const void*>(isa_name))); 140 options.push_back(std::make_pair("-Xno-sig-chain", nullptr)); 141 if (!Runtime::Create(options, false)) { 142 LOG(ERROR) << "Unable to initialize runtime"; 143 return false; 144 } 145 // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start, 146 // give it away now and then switch to a more manageable ScopedObjectAccess. 147 Thread::Current()->TransitionFromRunnableToSuspended(kNative); 148 ScopedObjectAccess soa(Thread::Current()); 149 150 t.NewTiming("Image Patching setup"); 151 std::vector<gc::space::ImageSpace*> spaces = Runtime::Current()->GetHeap()->GetBootImageSpaces(); 152 std::map<gc::space::ImageSpace*, std::unique_ptr<File>> space_to_file_map; 153 std::map<gc::space::ImageSpace*, std::unique_ptr<MemMap>> space_to_memmap_map; 154 std::map<gc::space::ImageSpace*, PatchOat> space_to_patchoat_map; 155 156 for (size_t i = 0; i < spaces.size(); ++i) { 157 gc::space::ImageSpace* space = spaces[i]; 158 std::string input_image_filename = space->GetImageFilename(); 159 std::unique_ptr<File> input_image(OS::OpenFileForReading(input_image_filename.c_str())); 160 if (input_image.get() == nullptr) { 161 LOG(ERROR) << "Unable to open input image file at " << input_image_filename; 162 return false; 163 } 164 165 int64_t image_len = input_image->GetLength(); 166 if (image_len < 0) { 167 LOG(ERROR) << "Error while getting image length"; 168 return false; 169 } 170 ImageHeader image_header; 171 if (sizeof(image_header) != input_image->Read(reinterpret_cast<char*>(&image_header), 172 sizeof(image_header), 0)) { 173 LOG(ERROR) << "Unable to read image header from image file " << input_image->GetPath(); 174 } 175 176 /*bool is_image_pic = */IsImagePic(image_header, input_image->GetPath()); 177 // Nothing special to do right now since the image always needs to get patched. 178 // Perhaps in some far-off future we may have images with relative addresses that are true-PIC. 179 180 // Create the map where we will write the image patches to. 181 std::string error_msg; 182 std::unique_ptr<MemMap> image(MemMap::MapFile(image_len, 183 PROT_READ | PROT_WRITE, 184 MAP_PRIVATE, 185 input_image->Fd(), 186 0, 187 /*low_4gb*/false, 188 input_image->GetPath().c_str(), 189 &error_msg)); 190 if (image.get() == nullptr) { 191 LOG(ERROR) << "Unable to map image file " << input_image->GetPath() << " : " << error_msg; 192 return false; 193 } 194 space_to_file_map.emplace(space, std::move(input_image)); 195 space_to_memmap_map.emplace(space, std::move(image)); 196 } 197 198 // Symlink PIC oat and vdex files and patch the image spaces in memory. 199 for (size_t i = 0; i < spaces.size(); ++i) { 200 gc::space::ImageSpace* space = spaces[i]; 201 std::string input_image_filename = space->GetImageFilename(); 202 std::string input_vdex_filename = 203 ImageHeader::GetVdexLocationFromImageLocation(input_image_filename); 204 std::string input_oat_filename = 205 ImageHeader::GetOatLocationFromImageLocation(input_image_filename); 206 std::unique_ptr<File> input_oat_file(OS::OpenFileForReading(input_oat_filename.c_str())); 207 if (input_oat_file.get() == nullptr) { 208 LOG(ERROR) << "Unable to open input oat file at " << input_oat_filename; 209 return false; 210 } 211 std::string error_msg; 212 std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat_file.get(), 213 PROT_READ | PROT_WRITE, MAP_PRIVATE, &error_msg)); 214 if (elf.get() == nullptr) { 215 LOG(ERROR) << "Unable to open oat file " << input_oat_file->GetPath() << " : " << error_msg; 216 return false; 217 } 218 219 MaybePic is_oat_pic = IsOatPic(elf.get()); 220 if (is_oat_pic >= ERROR_FIRST) { 221 // Error logged by IsOatPic 222 return false; 223 } else if (is_oat_pic == NOT_PIC) { 224 LOG(ERROR) << "patchoat cannot be used on non-PIC oat file: " << input_oat_file->GetPath(); 225 return false; 226 } else { 227 CHECK(is_oat_pic == PIC); 228 229 // Create a symlink. 230 std::string converted_image_filename = space->GetImageLocation(); 231 std::replace(converted_image_filename.begin() + 1, converted_image_filename.end(), '/', '@'); 232 std::string output_image_filename = output_directory + 233 (android::base::StartsWith(converted_image_filename, "/") ? "" : "/") + 234 converted_image_filename; 235 std::string output_vdex_filename = 236 ImageHeader::GetVdexLocationFromImageLocation(output_image_filename); 237 std::string output_oat_filename = 238 ImageHeader::GetOatLocationFromImageLocation(output_image_filename); 239 240 if (!ReplaceOatFileWithSymlink(input_oat_file->GetPath(), 241 output_oat_filename) || 242 !SymlinkFile(input_vdex_filename, output_vdex_filename)) { 243 // Errors already logged by above call. 244 return false; 245 } 246 } 247 248 PatchOat& p = space_to_patchoat_map.emplace(space, 249 PatchOat( 250 isa, 251 space_to_memmap_map.find(space)->second.get(), 252 space->GetLiveBitmap(), 253 space->GetMemMap(), 254 delta, 255 &space_to_memmap_map, 256 timings)).first->second; 257 258 t.NewTiming("Patching image"); 259 if (!p.PatchImage(i == 0)) { 260 LOG(ERROR) << "Failed to patch image file " << input_image_filename; 261 return false; 262 } 263 } 264 265 // Write the patched image spaces. 266 for (size_t i = 0; i < spaces.size(); ++i) { 267 gc::space::ImageSpace* space = spaces[i]; 268 269 t.NewTiming("Writing image"); 270 std::string converted_image_filename = space->GetImageLocation(); 271 std::replace(converted_image_filename.begin() + 1, converted_image_filename.end(), '/', '@'); 272 std::string output_image_filename = output_directory + 273 (android::base::StartsWith(converted_image_filename, "/") ? "" : "/") + 274 converted_image_filename; 275 std::unique_ptr<File> output_image_file(CreateOrOpen(output_image_filename.c_str())); 276 if (output_image_file.get() == nullptr) { 277 LOG(ERROR) << "Failed to open output image file at " << output_image_filename; 278 return false; 279 } 280 281 PatchOat& p = space_to_patchoat_map.find(space)->second; 282 283 bool success = p.WriteImage(output_image_file.get()); 284 success = FinishFile(output_image_file.get(), success); 285 if (!success) { 286 return false; 287 } 288 } 289 return true; 290} 291 292bool PatchOat::WriteImage(File* out) { 293 TimingLogger::ScopedTiming t("Writing image File", timings_); 294 std::string error_msg; 295 296 ScopedFlock img_flock; 297 img_flock.Init(out, &error_msg); 298 299 CHECK(image_ != nullptr); 300 CHECK(out != nullptr); 301 size_t expect = image_->Size(); 302 if (out->WriteFully(reinterpret_cast<char*>(image_->Begin()), expect) && 303 out->SetLength(expect) == 0) { 304 return true; 305 } else { 306 LOG(ERROR) << "Writing to image file " << out->GetPath() << " failed."; 307 return false; 308 } 309} 310 311bool PatchOat::IsImagePic(const ImageHeader& image_header, const std::string& image_path) { 312 if (!image_header.CompilePic()) { 313 if (kIsDebugBuild) { 314 LOG(INFO) << "image at location " << image_path << " was *not* compiled pic"; 315 } 316 return false; 317 } 318 319 if (kIsDebugBuild) { 320 LOG(INFO) << "image at location " << image_path << " was compiled PIC"; 321 } 322 323 return true; 324} 325 326PatchOat::MaybePic PatchOat::IsOatPic(const ElfFile* oat_in) { 327 if (oat_in == nullptr) { 328 LOG(ERROR) << "No ELF input oat fie available"; 329 return ERROR_OAT_FILE; 330 } 331 332 const std::string& file_path = oat_in->GetFilePath(); 333 334 const OatHeader* oat_header = GetOatHeader(oat_in); 335 if (oat_header == nullptr) { 336 LOG(ERROR) << "Failed to find oat header in oat file " << file_path; 337 return ERROR_OAT_FILE; 338 } 339 340 if (!oat_header->IsValid()) { 341 LOG(ERROR) << "Elf file " << file_path << " has an invalid oat header"; 342 return ERROR_OAT_FILE; 343 } 344 345 bool is_pic = oat_header->IsPic(); 346 if (kIsDebugBuild) { 347 LOG(INFO) << "Oat file at " << file_path << " is " << (is_pic ? "PIC" : "not pic"); 348 } 349 350 return is_pic ? PIC : NOT_PIC; 351} 352 353bool PatchOat::ReplaceOatFileWithSymlink(const std::string& input_oat_filename, 354 const std::string& output_oat_filename) { 355 // Delete the original file, since we won't need it. 356 unlink(output_oat_filename.c_str()); 357 358 // Create a symlink from the old oat to the new oat 359 if (symlink(input_oat_filename.c_str(), output_oat_filename.c_str()) < 0) { 360 int err = errno; 361 LOG(ERROR) << "Failed to create symlink at " << output_oat_filename 362 << " error(" << err << "): " << strerror(err); 363 return false; 364 } 365 366 if (kIsDebugBuild) { 367 LOG(INFO) << "Created symlink " << output_oat_filename << " -> " << input_oat_filename; 368 } 369 370 return true; 371} 372 373class PatchOat::PatchOatArtFieldVisitor : public ArtFieldVisitor { 374 public: 375 explicit PatchOatArtFieldVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {} 376 377 void Visit(ArtField* field) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { 378 ArtField* const dest = patch_oat_->RelocatedCopyOf(field); 379 dest->SetDeclaringClass( 380 patch_oat_->RelocatedAddressOfPointer(field->GetDeclaringClass().Ptr())); 381 } 382 383 private: 384 PatchOat* const patch_oat_; 385}; 386 387void PatchOat::PatchArtFields(const ImageHeader* image_header) { 388 PatchOatArtFieldVisitor visitor(this); 389 image_header->VisitPackedArtFields(&visitor, heap_->Begin()); 390} 391 392class PatchOat::PatchOatArtMethodVisitor : public ArtMethodVisitor { 393 public: 394 explicit PatchOatArtMethodVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {} 395 396 void Visit(ArtMethod* method) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { 397 ArtMethod* const dest = patch_oat_->RelocatedCopyOf(method); 398 patch_oat_->FixupMethod(method, dest); 399 } 400 401 private: 402 PatchOat* const patch_oat_; 403}; 404 405void PatchOat::PatchArtMethods(const ImageHeader* image_header) { 406 const PointerSize pointer_size = InstructionSetPointerSize(isa_); 407 PatchOatArtMethodVisitor visitor(this); 408 image_header->VisitPackedArtMethods(&visitor, heap_->Begin(), pointer_size); 409} 410 411void PatchOat::PatchImTables(const ImageHeader* image_header) { 412 const PointerSize pointer_size = InstructionSetPointerSize(isa_); 413 // We can safely walk target image since the conflict tables are independent. 414 image_header->VisitPackedImTables( 415 [this](ArtMethod* method) { 416 return RelocatedAddressOfPointer(method); 417 }, 418 image_->Begin(), 419 pointer_size); 420} 421 422void PatchOat::PatchImtConflictTables(const ImageHeader* image_header) { 423 const PointerSize pointer_size = InstructionSetPointerSize(isa_); 424 // We can safely walk target image since the conflict tables are independent. 425 image_header->VisitPackedImtConflictTables( 426 [this](ArtMethod* method) { 427 return RelocatedAddressOfPointer(method); 428 }, 429 image_->Begin(), 430 pointer_size); 431} 432 433class PatchOat::FixupRootVisitor : public RootVisitor { 434 public: 435 explicit FixupRootVisitor(const PatchOat* patch_oat) : patch_oat_(patch_oat) { 436 } 437 438 void VisitRoots(mirror::Object*** roots, size_t count, const RootInfo& info ATTRIBUTE_UNUSED) 439 OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { 440 for (size_t i = 0; i < count; ++i) { 441 *roots[i] = patch_oat_->RelocatedAddressOfPointer(*roots[i]); 442 } 443 } 444 445 void VisitRoots(mirror::CompressedReference<mirror::Object>** roots, size_t count, 446 const RootInfo& info ATTRIBUTE_UNUSED) 447 OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { 448 for (size_t i = 0; i < count; ++i) { 449 roots[i]->Assign(patch_oat_->RelocatedAddressOfPointer(roots[i]->AsMirrorPtr())); 450 } 451 } 452 453 private: 454 const PatchOat* const patch_oat_; 455}; 456 457void PatchOat::PatchInternedStrings(const ImageHeader* image_header) { 458 const auto& section = image_header->GetImageSection(ImageHeader::kSectionInternedStrings); 459 InternTable temp_table; 460 // Note that we require that ReadFromMemory does not make an internal copy of the elements. 461 // This also relies on visit roots not doing any verification which could fail after we update 462 // the roots to be the image addresses. 463 temp_table.AddTableFromMemory(image_->Begin() + section.Offset()); 464 FixupRootVisitor visitor(this); 465 temp_table.VisitRoots(&visitor, kVisitRootFlagAllRoots); 466} 467 468void PatchOat::PatchClassTable(const ImageHeader* image_header) { 469 const auto& section = image_header->GetImageSection(ImageHeader::kSectionClassTable); 470 if (section.Size() == 0) { 471 return; 472 } 473 // Note that we require that ReadFromMemory does not make an internal copy of the elements. 474 // This also relies on visit roots not doing any verification which could fail after we update 475 // the roots to be the image addresses. 476 WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); 477 ClassTable temp_table; 478 temp_table.ReadFromMemory(image_->Begin() + section.Offset()); 479 FixupRootVisitor visitor(this); 480 temp_table.VisitRoots(UnbufferedRootVisitor(&visitor, RootInfo(kRootUnknown))); 481} 482 483 484class PatchOat::RelocatedPointerVisitor { 485 public: 486 explicit RelocatedPointerVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {} 487 488 template <typename T> 489 T* operator()(T* ptr, void** dest_addr ATTRIBUTE_UNUSED = 0) const { 490 return patch_oat_->RelocatedAddressOfPointer(ptr); 491 } 492 493 private: 494 PatchOat* const patch_oat_; 495}; 496 497void PatchOat::PatchDexFileArrays(mirror::ObjectArray<mirror::Object>* img_roots) { 498 auto* dex_caches = down_cast<mirror::ObjectArray<mirror::DexCache>*>( 499 img_roots->Get(ImageHeader::kDexCaches)); 500 const PointerSize pointer_size = InstructionSetPointerSize(isa_); 501 for (size_t i = 0, count = dex_caches->GetLength(); i < count; ++i) { 502 auto* orig_dex_cache = dex_caches->GetWithoutChecks(i); 503 auto* copy_dex_cache = RelocatedCopyOf(orig_dex_cache); 504 // Though the DexCache array fields are usually treated as native pointers, we set the full 505 // 64-bit values here, clearing the top 32 bits for 32-bit targets. The zero-extension is 506 // done by casting to the unsigned type uintptr_t before casting to int64_t, i.e. 507 // static_cast<int64_t>(reinterpret_cast<uintptr_t>(image_begin_ + offset))). 508 mirror::StringDexCacheType* orig_strings = orig_dex_cache->GetStrings(); 509 mirror::StringDexCacheType* relocated_strings = RelocatedAddressOfPointer(orig_strings); 510 copy_dex_cache->SetField64<false>( 511 mirror::DexCache::StringsOffset(), 512 static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_strings))); 513 if (orig_strings != nullptr) { 514 orig_dex_cache->FixupStrings(RelocatedCopyOf(orig_strings), RelocatedPointerVisitor(this)); 515 } 516 mirror::TypeDexCacheType* orig_types = orig_dex_cache->GetResolvedTypes(); 517 mirror::TypeDexCacheType* relocated_types = RelocatedAddressOfPointer(orig_types); 518 copy_dex_cache->SetField64<false>( 519 mirror::DexCache::ResolvedTypesOffset(), 520 static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_types))); 521 if (orig_types != nullptr) { 522 orig_dex_cache->FixupResolvedTypes(RelocatedCopyOf(orig_types), 523 RelocatedPointerVisitor(this)); 524 } 525 ArtMethod** orig_methods = orig_dex_cache->GetResolvedMethods(); 526 ArtMethod** relocated_methods = RelocatedAddressOfPointer(orig_methods); 527 copy_dex_cache->SetField64<false>( 528 mirror::DexCache::ResolvedMethodsOffset(), 529 static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_methods))); 530 if (orig_methods != nullptr) { 531 ArtMethod** copy_methods = RelocatedCopyOf(orig_methods); 532 for (size_t j = 0, num = orig_dex_cache->NumResolvedMethods(); j != num; ++j) { 533 ArtMethod* orig = mirror::DexCache::GetElementPtrSize(orig_methods, j, pointer_size); 534 ArtMethod* copy = RelocatedAddressOfPointer(orig); 535 mirror::DexCache::SetElementPtrSize(copy_methods, j, copy, pointer_size); 536 } 537 } 538 mirror::FieldDexCacheType* orig_fields = orig_dex_cache->GetResolvedFields(); 539 mirror::FieldDexCacheType* relocated_fields = RelocatedAddressOfPointer(orig_fields); 540 copy_dex_cache->SetField64<false>( 541 mirror::DexCache::ResolvedFieldsOffset(), 542 static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_fields))); 543 if (orig_fields != nullptr) { 544 mirror::FieldDexCacheType* copy_fields = RelocatedCopyOf(orig_fields); 545 for (size_t j = 0, num = orig_dex_cache->NumResolvedFields(); j != num; ++j) { 546 mirror::FieldDexCachePair orig = 547 mirror::DexCache::GetNativePairPtrSize(orig_fields, j, pointer_size); 548 mirror::FieldDexCachePair copy(RelocatedAddressOfPointer(orig.object), orig.index); 549 mirror::DexCache::SetNativePairPtrSize(copy_fields, j, copy, pointer_size); 550 } 551 } 552 mirror::MethodTypeDexCacheType* orig_method_types = orig_dex_cache->GetResolvedMethodTypes(); 553 mirror::MethodTypeDexCacheType* relocated_method_types = 554 RelocatedAddressOfPointer(orig_method_types); 555 copy_dex_cache->SetField64<false>( 556 mirror::DexCache::ResolvedMethodTypesOffset(), 557 static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_method_types))); 558 if (orig_method_types != nullptr) { 559 orig_dex_cache->FixupResolvedMethodTypes(RelocatedCopyOf(orig_method_types), 560 RelocatedPointerVisitor(this)); 561 } 562 563 GcRoot<mirror::CallSite>* orig_call_sites = orig_dex_cache->GetResolvedCallSites(); 564 GcRoot<mirror::CallSite>* relocated_call_sites = RelocatedAddressOfPointer(orig_call_sites); 565 copy_dex_cache->SetField64<false>( 566 mirror::DexCache::ResolvedCallSitesOffset(), 567 static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_call_sites))); 568 if (orig_call_sites != nullptr) { 569 orig_dex_cache->FixupResolvedCallSites(RelocatedCopyOf(orig_call_sites), 570 RelocatedPointerVisitor(this)); 571 } 572 } 573} 574 575bool PatchOat::PatchImage(bool primary_image) { 576 ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin()); 577 CHECK_GT(image_->Size(), sizeof(ImageHeader)); 578 // These are the roots from the original file. 579 auto* img_roots = image_header->GetImageRoots(); 580 image_header->RelocateImage(delta_); 581 582 PatchArtFields(image_header); 583 PatchArtMethods(image_header); 584 PatchImTables(image_header); 585 PatchImtConflictTables(image_header); 586 PatchInternedStrings(image_header); 587 PatchClassTable(image_header); 588 // Patch dex file int/long arrays which point to ArtFields. 589 PatchDexFileArrays(img_roots); 590 591 if (primary_image) { 592 VisitObject(img_roots); 593 } 594 595 if (!image_header->IsValid()) { 596 LOG(ERROR) << "relocation renders image header invalid"; 597 return false; 598 } 599 600 { 601 TimingLogger::ScopedTiming t("Walk Bitmap", timings_); 602 // Walk the bitmap. 603 WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); 604 bitmap_->Walk(PatchOat::BitmapCallback, this); 605 } 606 return true; 607} 608 609 610void PatchOat::PatchVisitor::operator() (ObjPtr<mirror::Object> obj, 611 MemberOffset off, 612 bool is_static_unused ATTRIBUTE_UNUSED) const { 613 mirror::Object* referent = obj->GetFieldObject<mirror::Object, kVerifyNone>(off); 614 mirror::Object* moved_object = patcher_->RelocatedAddressOfPointer(referent); 615 copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(off, moved_object); 616} 617 618void PatchOat::PatchVisitor::operator() (ObjPtr<mirror::Class> cls ATTRIBUTE_UNUSED, 619 ObjPtr<mirror::Reference> ref) const { 620 MemberOffset off = mirror::Reference::ReferentOffset(); 621 mirror::Object* referent = ref->GetReferent(); 622 DCHECK(referent == nullptr || 623 Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(referent)) << referent; 624 mirror::Object* moved_object = patcher_->RelocatedAddressOfPointer(referent); 625 copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(off, moved_object); 626} 627 628// Called by BitmapCallback 629void PatchOat::VisitObject(mirror::Object* object) { 630 mirror::Object* copy = RelocatedCopyOf(object); 631 CHECK(copy != nullptr); 632 if (kUseBakerReadBarrier) { 633 object->AssertReadBarrierState(); 634 } 635 PatchOat::PatchVisitor visitor(this, copy); 636 object->VisitReferences<kVerifyNone>(visitor, visitor); 637 if (object->IsClass<kVerifyNone>()) { 638 const PointerSize pointer_size = InstructionSetPointerSize(isa_); 639 mirror::Class* klass = object->AsClass(); 640 mirror::Class* copy_klass = down_cast<mirror::Class*>(copy); 641 RelocatedPointerVisitor native_visitor(this); 642 klass->FixupNativePointers(copy_klass, pointer_size, native_visitor); 643 auto* vtable = klass->GetVTable(); 644 if (vtable != nullptr) { 645 vtable->Fixup(RelocatedCopyOfFollowImages(vtable), pointer_size, native_visitor); 646 } 647 mirror::IfTable* iftable = klass->GetIfTable(); 648 for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) { 649 if (iftable->GetMethodArrayCount(i) > 0) { 650 auto* method_array = iftable->GetMethodArray(i); 651 CHECK(method_array != nullptr); 652 method_array->Fixup(RelocatedCopyOfFollowImages(method_array), 653 pointer_size, 654 native_visitor); 655 } 656 } 657 } else if (object->GetClass() == mirror::Method::StaticClass() || 658 object->GetClass() == mirror::Constructor::StaticClass()) { 659 // Need to go update the ArtMethod. 660 auto* dest = down_cast<mirror::Executable*>(copy); 661 auto* src = down_cast<mirror::Executable*>(object); 662 dest->SetArtMethod(RelocatedAddressOfPointer(src->GetArtMethod())); 663 } 664} 665 666void PatchOat::FixupMethod(ArtMethod* object, ArtMethod* copy) { 667 const PointerSize pointer_size = InstructionSetPointerSize(isa_); 668 copy->CopyFrom(object, pointer_size); 669 // Just update the entry points if it looks like we should. 670 // TODO: sanity check all the pointers' values 671 copy->SetDeclaringClass(RelocatedAddressOfPointer(object->GetDeclaringClass())); 672 copy->SetDexCacheResolvedMethods( 673 RelocatedAddressOfPointer(object->GetDexCacheResolvedMethods(pointer_size)), pointer_size); 674 copy->SetEntryPointFromQuickCompiledCodePtrSize(RelocatedAddressOfPointer( 675 object->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size)), pointer_size); 676 // No special handling for IMT conflict table since all pointers are moved by the same offset. 677 copy->SetDataPtrSize(RelocatedAddressOfPointer( 678 object->GetDataPtrSize(pointer_size)), pointer_size); 679} 680 681static int orig_argc; 682static char** orig_argv; 683 684static std::string CommandLine() { 685 std::vector<std::string> command; 686 for (int i = 0; i < orig_argc; ++i) { 687 command.push_back(orig_argv[i]); 688 } 689 return android::base::Join(command, ' '); 690} 691 692static void UsageErrorV(const char* fmt, va_list ap) { 693 std::string error; 694 android::base::StringAppendV(&error, fmt, ap); 695 LOG(ERROR) << error; 696} 697 698static void UsageError(const char* fmt, ...) { 699 va_list ap; 700 va_start(ap, fmt); 701 UsageErrorV(fmt, ap); 702 va_end(ap); 703} 704 705NO_RETURN static void Usage(const char *fmt, ...) { 706 va_list ap; 707 va_start(ap, fmt); 708 UsageErrorV(fmt, ap); 709 va_end(ap); 710 711 UsageError("Command: %s", CommandLine().c_str()); 712 UsageError("Usage: patchoat [options]..."); 713 UsageError(""); 714 UsageError(" --instruction-set=<isa>: Specifies the instruction set the patched code is"); 715 UsageError(" compiled for (required)."); 716 UsageError(""); 717 UsageError(" --input-image-location=<file.art>: Specifies the 'location' of the image file to"); 718 UsageError(" be patched."); 719 UsageError(""); 720 UsageError(" --output-image-file=<file.art>: Specifies the exact file to write the patched"); 721 UsageError(" image file to."); 722 UsageError(""); 723 UsageError(" --base-offset-delta=<delta>: Specify the amount to change the old base-offset by."); 724 UsageError(" This value may be negative."); 725 UsageError(""); 726 UsageError(" --dump-timings: dump out patch timing information"); 727 UsageError(""); 728 UsageError(" --no-dump-timings: do not dump out patch timing information"); 729 UsageError(""); 730 731 exit(EXIT_FAILURE); 732} 733 734static int patchoat_image(TimingLogger& timings, 735 InstructionSet isa, 736 const std::string& input_image_location, 737 const std::string& output_image_filename, 738 off_t base_delta, 739 bool base_delta_set, 740 bool debug) { 741 CHECK(!input_image_location.empty()); 742 if (output_image_filename.empty()) { 743 Usage("Image patching requires --output-image-file"); 744 } 745 746 if (!base_delta_set) { 747 Usage("Must supply a desired new offset or delta."); 748 } 749 750 if (!IsAligned<kPageSize>(base_delta)) { 751 Usage("Base offset/delta must be aligned to a pagesize (0x%08x) boundary.", kPageSize); 752 } 753 754 if (debug) { 755 LOG(INFO) << "moving offset by " << base_delta 756 << " (0x" << std::hex << base_delta << ") bytes or " 757 << std::dec << (base_delta/kPageSize) << " pages."; 758 } 759 760 TimingLogger::ScopedTiming pt("patch image and oat", &timings); 761 762 std::string output_directory = 763 output_image_filename.substr(0, output_image_filename.find_last_of('/')); 764 bool ret = PatchOat::Patch(input_image_location, base_delta, output_directory, isa, &timings); 765 766 if (kIsDebugBuild) { 767 LOG(INFO) << "Exiting with return ... " << ret; 768 } 769 return ret ? EXIT_SUCCESS : EXIT_FAILURE; 770} 771 772static int patchoat(int argc, char **argv) { 773 InitLogging(argv, Runtime::Aborter); 774 MemMap::Init(); 775 const bool debug = kIsDebugBuild; 776 orig_argc = argc; 777 orig_argv = argv; 778 TimingLogger timings("patcher", false, false); 779 780 // Skip over the command name. 781 argv++; 782 argc--; 783 784 if (argc == 0) { 785 Usage("No arguments specified"); 786 } 787 788 timings.StartTiming("Patchoat"); 789 790 // cmd line args 791 bool isa_set = false; 792 InstructionSet isa = kNone; 793 std::string input_image_location; 794 std::string output_image_filename; 795 off_t base_delta = 0; 796 bool base_delta_set = false; 797 bool dump_timings = kIsDebugBuild; 798 799 for (int i = 0; i < argc; ++i) { 800 const StringPiece option(argv[i]); 801 const bool log_options = false; 802 if (log_options) { 803 LOG(INFO) << "patchoat: option[" << i << "]=" << argv[i]; 804 } 805 if (option.starts_with("--instruction-set=")) { 806 isa_set = true; 807 const char* isa_str = option.substr(strlen("--instruction-set=")).data(); 808 isa = GetInstructionSetFromString(isa_str); 809 if (isa == kNone) { 810 Usage("Unknown or invalid instruction set %s", isa_str); 811 } 812 } else if (option.starts_with("--input-image-location=")) { 813 input_image_location = option.substr(strlen("--input-image-location=")).data(); 814 } else if (option.starts_with("--output-image-file=")) { 815 output_image_filename = option.substr(strlen("--output-image-file=")).data(); 816 } else if (option.starts_with("--base-offset-delta=")) { 817 const char* base_delta_str = option.substr(strlen("--base-offset-delta=")).data(); 818 base_delta_set = true; 819 if (!ParseInt(base_delta_str, &base_delta)) { 820 Usage("Failed to parse --base-offset-delta argument '%s' as an off_t", base_delta_str); 821 } 822 } else if (option == "--dump-timings") { 823 dump_timings = true; 824 } else if (option == "--no-dump-timings") { 825 dump_timings = false; 826 } else { 827 Usage("Unknown argument %s", option.data()); 828 } 829 } 830 831 // The instruction set is mandatory. This simplifies things... 832 if (!isa_set) { 833 Usage("Instruction set must be set."); 834 } 835 836 int ret = patchoat_image(timings, 837 isa, 838 input_image_location, 839 output_image_filename, 840 base_delta, 841 base_delta_set, 842 debug); 843 844 timings.EndTiming(); 845 if (dump_timings) { 846 LOG(INFO) << Dumpable<TimingLogger>(timings); 847 } 848 849 return ret; 850} 851 852} // namespace art 853 854int main(int argc, char **argv) { 855 return art::patchoat(argc, argv); 856} 857