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 "art_field-inl.h" 28#include "art_method-inl.h" 29#include "base/dumpable.h" 30#include "base/scoped_flock.h" 31#include "base/stringpiece.h" 32#include "base/stringprintf.h" 33#include "base/unix_file/fd_file.h" 34#include "elf_utils.h" 35#include "elf_file.h" 36#include "elf_file_impl.h" 37#include "gc/space/image_space.h" 38#include "image.h" 39#include "mirror/abstract_method.h" 40#include "mirror/object-inl.h" 41#include "mirror/method.h" 42#include "mirror/reference.h" 43#include "noop_compiler_callbacks.h" 44#include "offsets.h" 45#include "os.h" 46#include "runtime.h" 47#include "scoped_thread_state_change.h" 48#include "thread.h" 49#include "utils.h" 50 51namespace art { 52 53static bool LocationToFilename(const std::string& location, InstructionSet isa, 54 std::string* filename) { 55 bool has_system = false; 56 bool has_cache = false; 57 // image_location = /system/framework/boot.art 58 // system_image_filename = /system/framework/<image_isa>/boot.art 59 std::string system_filename(GetSystemImageFilename(location.c_str(), isa)); 60 if (OS::FileExists(system_filename.c_str())) { 61 has_system = true; 62 } 63 64 bool have_android_data = false; 65 bool dalvik_cache_exists = false; 66 bool is_global_cache = false; 67 std::string dalvik_cache; 68 GetDalvikCache(GetInstructionSetString(isa), false, &dalvik_cache, 69 &have_android_data, &dalvik_cache_exists, &is_global_cache); 70 71 std::string cache_filename; 72 if (have_android_data && dalvik_cache_exists) { 73 // Always set output location even if it does not exist, 74 // so that the caller knows where to create the image. 75 // 76 // image_location = /system/framework/boot.art 77 // *image_filename = /data/dalvik-cache/<image_isa>/boot.art 78 std::string error_msg; 79 if (GetDalvikCacheFilename(location.c_str(), dalvik_cache.c_str(), 80 &cache_filename, &error_msg)) { 81 has_cache = true; 82 } 83 } 84 if (has_system) { 85 *filename = system_filename; 86 return true; 87 } else if (has_cache) { 88 *filename = cache_filename; 89 return true; 90 } else { 91 return false; 92 } 93} 94 95bool PatchOat::Patch(const std::string& image_location, off_t delta, 96 File* output_image, InstructionSet isa, 97 TimingLogger* timings) { 98 CHECK(Runtime::Current() == nullptr); 99 CHECK(output_image != nullptr); 100 CHECK_GE(output_image->Fd(), 0); 101 CHECK(!image_location.empty()) << "image file must have a filename."; 102 CHECK_NE(isa, kNone); 103 104 TimingLogger::ScopedTiming t("Runtime Setup", timings); 105 const char *isa_name = GetInstructionSetString(isa); 106 std::string image_filename; 107 if (!LocationToFilename(image_location, isa, &image_filename)) { 108 LOG(ERROR) << "Unable to find image at location " << image_location; 109 return false; 110 } 111 std::unique_ptr<File> input_image(OS::OpenFileForReading(image_filename.c_str())); 112 if (input_image.get() == nullptr) { 113 LOG(ERROR) << "unable to open input image file at " << image_filename 114 << " for location " << image_location; 115 return false; 116 } 117 118 int64_t image_len = input_image->GetLength(); 119 if (image_len < 0) { 120 LOG(ERROR) << "Error while getting image length"; 121 return false; 122 } 123 ImageHeader image_header; 124 if (sizeof(image_header) != input_image->Read(reinterpret_cast<char*>(&image_header), 125 sizeof(image_header), 0)) { 126 LOG(ERROR) << "Unable to read image header from image file " << input_image->GetPath(); 127 return false; 128 } 129 130 /*bool is_image_pic = */IsImagePic(image_header, input_image->GetPath()); 131 // Nothing special to do right now since the image always needs to get patched. 132 // Perhaps in some far-off future we may have images with relative addresses that are true-PIC. 133 134 // Set up the runtime 135 RuntimeOptions options; 136 NoopCompilerCallbacks callbacks; 137 options.push_back(std::make_pair("compilercallbacks", &callbacks)); 138 std::string img = "-Ximage:" + image_location; 139 options.push_back(std::make_pair(img.c_str(), nullptr)); 140 options.push_back(std::make_pair("imageinstructionset", reinterpret_cast<const void*>(isa_name))); 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 and oat Patching setup"); 151 // Create the map where we will write the image patches to. 152 std::string error_msg; 153 std::unique_ptr<MemMap> image(MemMap::MapFile(image_len, PROT_READ | PROT_WRITE, MAP_PRIVATE, 154 input_image->Fd(), 0, 155 input_image->GetPath().c_str(), 156 &error_msg)); 157 if (image.get() == nullptr) { 158 LOG(ERROR) << "unable to map image file " << input_image->GetPath() << " : " << error_msg; 159 return false; 160 } 161 gc::space::ImageSpace* ispc = Runtime::Current()->GetHeap()->GetImageSpace(); 162 163 PatchOat p(isa, image.release(), ispc->GetLiveBitmap(), ispc->GetMemMap(), 164 delta, timings); 165 t.NewTiming("Patching files"); 166 if (!p.PatchImage()) { 167 LOG(ERROR) << "Failed to patch image file " << input_image->GetPath(); 168 return false; 169 } 170 171 t.NewTiming("Writing files"); 172 if (!p.WriteImage(output_image)) { 173 return false; 174 } 175 return true; 176} 177 178bool PatchOat::Patch(File* input_oat, const std::string& image_location, off_t delta, 179 File* output_oat, File* output_image, InstructionSet isa, 180 TimingLogger* timings, 181 bool output_oat_opened_from_fd, 182 bool new_oat_out) { 183 CHECK(Runtime::Current() == nullptr); 184 CHECK(output_image != nullptr); 185 CHECK_GE(output_image->Fd(), 0); 186 CHECK(input_oat != nullptr); 187 CHECK(output_oat != nullptr); 188 CHECK_GE(input_oat->Fd(), 0); 189 CHECK_GE(output_oat->Fd(), 0); 190 CHECK(!image_location.empty()) << "image file must have a filename."; 191 192 TimingLogger::ScopedTiming t("Runtime Setup", timings); 193 194 if (isa == kNone) { 195 Elf32_Ehdr elf_hdr; 196 if (sizeof(elf_hdr) != input_oat->Read(reinterpret_cast<char*>(&elf_hdr), sizeof(elf_hdr), 0)) { 197 LOG(ERROR) << "unable to read elf header"; 198 return false; 199 } 200 isa = GetInstructionSetFromELF(elf_hdr.e_machine, elf_hdr.e_flags); 201 } 202 const char* isa_name = GetInstructionSetString(isa); 203 std::string image_filename; 204 if (!LocationToFilename(image_location, isa, &image_filename)) { 205 LOG(ERROR) << "Unable to find image at location " << image_location; 206 return false; 207 } 208 std::unique_ptr<File> input_image(OS::OpenFileForReading(image_filename.c_str())); 209 if (input_image.get() == nullptr) { 210 LOG(ERROR) << "unable to open input image file at " << image_filename 211 << " for location " << image_location; 212 return false; 213 } 214 int64_t image_len = input_image->GetLength(); 215 if (image_len < 0) { 216 LOG(ERROR) << "Error while getting image length"; 217 return false; 218 } 219 ImageHeader image_header; 220 if (sizeof(image_header) != input_image->Read(reinterpret_cast<char*>(&image_header), 221 sizeof(image_header), 0)) { 222 LOG(ERROR) << "Unable to read image header from image file " << input_image->GetPath(); 223 } 224 225 /*bool is_image_pic = */IsImagePic(image_header, input_image->GetPath()); 226 // Nothing special to do right now since the image always needs to get patched. 227 // Perhaps in some far-off future we may have images with relative addresses that are true-PIC. 228 229 // Set up the runtime 230 RuntimeOptions options; 231 NoopCompilerCallbacks callbacks; 232 options.push_back(std::make_pair("compilercallbacks", &callbacks)); 233 std::string img = "-Ximage:" + image_location; 234 options.push_back(std::make_pair(img.c_str(), nullptr)); 235 options.push_back(std::make_pair("imageinstructionset", reinterpret_cast<const void*>(isa_name))); 236 if (!Runtime::Create(options, false)) { 237 LOG(ERROR) << "Unable to initialize runtime"; 238 return false; 239 } 240 // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start, 241 // give it away now and then switch to a more manageable ScopedObjectAccess. 242 Thread::Current()->TransitionFromRunnableToSuspended(kNative); 243 ScopedObjectAccess soa(Thread::Current()); 244 245 t.NewTiming("Image and oat Patching setup"); 246 // Create the map where we will write the image patches to. 247 std::string error_msg; 248 std::unique_ptr<MemMap> image(MemMap::MapFile(image_len, PROT_READ | PROT_WRITE, MAP_PRIVATE, 249 input_image->Fd(), 0, 250 input_image->GetPath().c_str(), 251 &error_msg)); 252 if (image.get() == nullptr) { 253 LOG(ERROR) << "unable to map image file " << input_image->GetPath() << " : " << error_msg; 254 return false; 255 } 256 gc::space::ImageSpace* ispc = Runtime::Current()->GetHeap()->GetImageSpace(); 257 258 std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat, 259 PROT_READ | PROT_WRITE, MAP_PRIVATE, &error_msg)); 260 if (elf.get() == nullptr) { 261 LOG(ERROR) << "unable to open oat file " << input_oat->GetPath() << " : " << error_msg; 262 return false; 263 } 264 265 bool skip_patching_oat = false; 266 MaybePic is_oat_pic = IsOatPic(elf.get()); 267 if (is_oat_pic >= ERROR_FIRST) { 268 // Error logged by IsOatPic 269 return false; 270 } else if (is_oat_pic == PIC) { 271 // Do not need to do ELF-file patching. Create a symlink and skip the ELF patching. 272 if (!ReplaceOatFileWithSymlink(input_oat->GetPath(), 273 output_oat->GetPath(), 274 output_oat_opened_from_fd, 275 new_oat_out)) { 276 // Errors already logged by above call. 277 return false; 278 } 279 // Don't patch the OAT, since we just symlinked it. Image still needs patching. 280 skip_patching_oat = true; 281 } else { 282 CHECK(is_oat_pic == NOT_PIC); 283 } 284 285 PatchOat p(isa, elf.release(), image.release(), ispc->GetLiveBitmap(), ispc->GetMemMap(), 286 delta, timings); 287 t.NewTiming("Patching files"); 288 if (!skip_patching_oat && !p.PatchElf()) { 289 LOG(ERROR) << "Failed to patch oat file " << input_oat->GetPath(); 290 return false; 291 } 292 if (!p.PatchImage()) { 293 LOG(ERROR) << "Failed to patch image file " << input_image->GetPath(); 294 return false; 295 } 296 297 t.NewTiming("Writing files"); 298 if (!skip_patching_oat && !p.WriteElf(output_oat)) { 299 LOG(ERROR) << "Failed to write oat file " << input_oat->GetPath(); 300 return false; 301 } 302 if (!p.WriteImage(output_image)) { 303 LOG(ERROR) << "Failed to write image file " << input_image->GetPath(); 304 return false; 305 } 306 return true; 307} 308 309bool PatchOat::WriteElf(File* out) { 310 TimingLogger::ScopedTiming t("Writing Elf File", timings_); 311 312 CHECK(oat_file_.get() != nullptr); 313 CHECK(out != nullptr); 314 size_t expect = oat_file_->Size(); 315 if (out->WriteFully(reinterpret_cast<char*>(oat_file_->Begin()), expect) && 316 out->SetLength(expect) == 0) { 317 return true; 318 } else { 319 LOG(ERROR) << "Writing to oat file " << out->GetPath() << " failed."; 320 return false; 321 } 322} 323 324bool PatchOat::WriteImage(File* out) { 325 TimingLogger::ScopedTiming t("Writing image File", timings_); 326 std::string error_msg; 327 328 ScopedFlock img_flock; 329 img_flock.Init(out, &error_msg); 330 331 CHECK(image_ != nullptr); 332 CHECK(out != nullptr); 333 size_t expect = image_->Size(); 334 if (out->WriteFully(reinterpret_cast<char*>(image_->Begin()), expect) && 335 out->SetLength(expect) == 0) { 336 return true; 337 } else { 338 LOG(ERROR) << "Writing to image file " << out->GetPath() << " failed."; 339 return false; 340 } 341} 342 343bool PatchOat::IsImagePic(const ImageHeader& image_header, const std::string& image_path) { 344 if (!image_header.CompilePic()) { 345 if (kIsDebugBuild) { 346 LOG(INFO) << "image at location " << image_path << " was *not* compiled pic"; 347 } 348 return false; 349 } 350 351 if (kIsDebugBuild) { 352 LOG(INFO) << "image at location " << image_path << " was compiled PIC"; 353 } 354 355 return true; 356} 357 358PatchOat::MaybePic PatchOat::IsOatPic(const ElfFile* oat_in) { 359 if (oat_in == nullptr) { 360 LOG(ERROR) << "No ELF input oat fie available"; 361 return ERROR_OAT_FILE; 362 } 363 364 const std::string& file_path = oat_in->GetFile().GetPath(); 365 366 const OatHeader* oat_header = GetOatHeader(oat_in); 367 if (oat_header == nullptr) { 368 LOG(ERROR) << "Failed to find oat header in oat file " << file_path; 369 return ERROR_OAT_FILE; 370 } 371 372 if (!oat_header->IsValid()) { 373 LOG(ERROR) << "Elf file " << file_path << " has an invalid oat header"; 374 return ERROR_OAT_FILE; 375 } 376 377 bool is_pic = oat_header->IsPic(); 378 if (kIsDebugBuild) { 379 LOG(INFO) << "Oat file at " << file_path << " is " << (is_pic ? "PIC" : "not pic"); 380 } 381 382 return is_pic ? PIC : NOT_PIC; 383} 384 385bool PatchOat::ReplaceOatFileWithSymlink(const std::string& input_oat_filename, 386 const std::string& output_oat_filename, 387 bool output_oat_opened_from_fd, 388 bool new_oat_out) { 389 // Need a file when we are PIC, since we symlink over it. Refusing to symlink into FD. 390 if (output_oat_opened_from_fd) { 391 // TODO: installd uses --output-oat-fd. Should we change class linking logic for PIC? 392 LOG(ERROR) << "No output oat filename specified, needs filename for when we are PIC"; 393 return false; 394 } 395 396 // Image was PIC. Create symlink where the oat is supposed to go. 397 if (!new_oat_out) { 398 LOG(ERROR) << "Oat file " << output_oat_filename << " already exists, refusing to overwrite"; 399 return false; 400 } 401 402 // Delete the original file, since we won't need it. 403 TEMP_FAILURE_RETRY(unlink(output_oat_filename.c_str())); 404 405 // Create a symlink from the old oat to the new oat 406 if (symlink(input_oat_filename.c_str(), output_oat_filename.c_str()) < 0) { 407 int err = errno; 408 LOG(ERROR) << "Failed to create symlink at " << output_oat_filename 409 << " error(" << err << "): " << strerror(err); 410 return false; 411 } 412 413 if (kIsDebugBuild) { 414 LOG(INFO) << "Created symlink " << output_oat_filename << " -> " << input_oat_filename; 415 } 416 417 return true; 418} 419 420void PatchOat::PatchArtFields(const ImageHeader* image_header) { 421 const auto& section = image_header->GetImageSection(ImageHeader::kSectionArtFields); 422 for (size_t pos = 0; pos < section.Size(); pos += sizeof(ArtField)) { 423 auto* src = reinterpret_cast<ArtField*>(heap_->Begin() + section.Offset() + pos); 424 auto* dest = RelocatedCopyOf(src); 425 dest->SetDeclaringClass(RelocatedAddressOfPointer(src->GetDeclaringClass())); 426 } 427} 428 429void PatchOat::PatchArtMethods(const ImageHeader* image_header) { 430 const auto& section = image_header->GetMethodsSection(); 431 const size_t pointer_size = InstructionSetPointerSize(isa_); 432 size_t method_size = ArtMethod::ObjectSize(pointer_size); 433 for (size_t pos = 0; pos < section.Size(); pos += method_size) { 434 auto* src = reinterpret_cast<ArtMethod*>(heap_->Begin() + section.Offset() + pos); 435 auto* dest = RelocatedCopyOf(src); 436 FixupMethod(src, dest); 437 } 438} 439 440class FixupRootVisitor : public RootVisitor { 441 public: 442 explicit FixupRootVisitor(const PatchOat* patch_oat) : patch_oat_(patch_oat) { 443 } 444 445 void VisitRoots(mirror::Object*** roots, size_t count, const RootInfo& info ATTRIBUTE_UNUSED) 446 OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 447 for (size_t i = 0; i < count; ++i) { 448 *roots[i] = patch_oat_->RelocatedAddressOfPointer(*roots[i]); 449 } 450 } 451 452 void VisitRoots(mirror::CompressedReference<mirror::Object>** roots, size_t count, 453 const RootInfo& info ATTRIBUTE_UNUSED) 454 OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 455 for (size_t i = 0; i < count; ++i) { 456 roots[i]->Assign(patch_oat_->RelocatedAddressOfPointer(roots[i]->AsMirrorPtr())); 457 } 458 } 459 460 private: 461 const PatchOat* const patch_oat_; 462}; 463 464void PatchOat::PatchInternedStrings(const ImageHeader* image_header) { 465 const auto& section = image_header->GetImageSection(ImageHeader::kSectionInternedStrings); 466 InternTable temp_table; 467 // Note that we require that ReadFromMemory does not make an internal copy of the elements. 468 // This also relies on visit roots not doing any verification which could fail after we update 469 // the roots to be the image addresses. 470 temp_table.ReadFromMemory(image_->Begin() + section.Offset()); 471 FixupRootVisitor visitor(this); 472 temp_table.VisitRoots(&visitor, kVisitRootFlagAllRoots); 473} 474 475void PatchOat::PatchDexFileArrays(mirror::ObjectArray<mirror::Object>* img_roots) { 476 auto* dex_caches = down_cast<mirror::ObjectArray<mirror::DexCache>*>( 477 img_roots->Get(ImageHeader::kDexCaches)); 478 for (size_t i = 0, count = dex_caches->GetLength(); i < count; ++i) { 479 auto* dex_cache = dex_caches->GetWithoutChecks(i); 480 auto* fields = dex_cache->GetResolvedFields(); 481 if (fields != nullptr) { 482 CHECK(!fields->IsObjectArray()); 483 CHECK(fields->IsArrayInstance()); 484 FixupNativePointerArray(fields); 485 } 486 auto* methods = dex_cache->GetResolvedMethods(); 487 if (methods != nullptr) { 488 CHECK(!methods->IsObjectArray()); 489 CHECK(methods->IsArrayInstance()); 490 FixupNativePointerArray(methods); 491 } 492 } 493} 494 495void PatchOat::FixupNativePointerArray(mirror::PointerArray* object) { 496 if (object->IsIntArray()) { 497 mirror::IntArray* arr = object->AsIntArray(); 498 mirror::IntArray* copy_arr = down_cast<mirror::IntArray*>(RelocatedCopyOf(arr)); 499 for (size_t j = 0, count2 = arr->GetLength(); j < count2; ++j) { 500 copy_arr->SetWithoutChecks<false>( 501 j, RelocatedAddressOfIntPointer(arr->GetWithoutChecks(j))); 502 } 503 } else { 504 CHECK(object->IsLongArray()); 505 mirror::LongArray* arr = object->AsLongArray(); 506 mirror::LongArray* copy_arr = down_cast<mirror::LongArray*>(RelocatedCopyOf(arr)); 507 for (size_t j = 0, count2 = arr->GetLength(); j < count2; ++j) { 508 copy_arr->SetWithoutChecks<false>( 509 j, RelocatedAddressOfIntPointer(arr->GetWithoutChecks(j))); 510 } 511 } 512} 513 514bool PatchOat::PatchImage() { 515 ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin()); 516 CHECK_GT(image_->Size(), sizeof(ImageHeader)); 517 // These are the roots from the original file. 518 auto* img_roots = image_header->GetImageRoots(); 519 image_header->RelocateImage(delta_); 520 521 PatchArtFields(image_header); 522 PatchArtMethods(image_header); 523 PatchInternedStrings(image_header); 524 // Patch dex file int/long arrays which point to ArtFields. 525 PatchDexFileArrays(img_roots); 526 527 VisitObject(img_roots); 528 if (!image_header->IsValid()) { 529 LOG(ERROR) << "reloction renders image header invalid"; 530 return false; 531 } 532 533 { 534 TimingLogger::ScopedTiming t("Walk Bitmap", timings_); 535 // Walk the bitmap. 536 WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); 537 bitmap_->Walk(PatchOat::BitmapCallback, this); 538 } 539 return true; 540} 541 542bool PatchOat::InHeap(mirror::Object* o) { 543 uintptr_t begin = reinterpret_cast<uintptr_t>(heap_->Begin()); 544 uintptr_t end = reinterpret_cast<uintptr_t>(heap_->End()); 545 uintptr_t obj = reinterpret_cast<uintptr_t>(o); 546 return o == nullptr || (begin <= obj && obj < end); 547} 548 549void PatchOat::PatchVisitor::operator() (mirror::Object* obj, MemberOffset off, 550 bool is_static_unused ATTRIBUTE_UNUSED) const { 551 mirror::Object* referent = obj->GetFieldObject<mirror::Object, kVerifyNone>(off); 552 DCHECK(patcher_->InHeap(referent)) << "Referent is not in the heap."; 553 mirror::Object* moved_object = patcher_->RelocatedAddressOfPointer(referent); 554 copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(off, moved_object); 555} 556 557void PatchOat::PatchVisitor::operator() (mirror::Class* cls ATTRIBUTE_UNUSED, 558 mirror::Reference* ref) const { 559 MemberOffset off = mirror::Reference::ReferentOffset(); 560 mirror::Object* referent = ref->GetReferent(); 561 DCHECK(patcher_->InHeap(referent)) << "Referent is not in the heap."; 562 mirror::Object* moved_object = patcher_->RelocatedAddressOfPointer(referent); 563 copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(off, moved_object); 564} 565 566const OatHeader* PatchOat::GetOatHeader(const ElfFile* elf_file) { 567 if (elf_file->Is64Bit()) { 568 return GetOatHeader<ElfFileImpl64>(elf_file->GetImpl64()); 569 } else { 570 return GetOatHeader<ElfFileImpl32>(elf_file->GetImpl32()); 571 } 572} 573 574template <typename ElfFileImpl> 575const OatHeader* PatchOat::GetOatHeader(const ElfFileImpl* elf_file) { 576 auto rodata_sec = elf_file->FindSectionByName(".rodata"); 577 if (rodata_sec == nullptr) { 578 return nullptr; 579 } 580 581 OatHeader* oat_header = reinterpret_cast<OatHeader*>(elf_file->Begin() + rodata_sec->sh_offset); 582 return oat_header; 583} 584 585// Called by BitmapCallback 586void PatchOat::VisitObject(mirror::Object* object) { 587 mirror::Object* copy = RelocatedCopyOf(object); 588 CHECK(copy != nullptr); 589 if (kUseBakerOrBrooksReadBarrier) { 590 object->AssertReadBarrierPointer(); 591 if (kUseBrooksReadBarrier) { 592 mirror::Object* moved_to = RelocatedAddressOfPointer(object); 593 copy->SetReadBarrierPointer(moved_to); 594 DCHECK_EQ(copy->GetReadBarrierPointer(), moved_to); 595 } 596 } 597 PatchOat::PatchVisitor visitor(this, copy); 598 object->VisitReferences<true, kVerifyNone>(visitor, visitor); 599 if (object->IsClass<kVerifyNone>()) { 600 auto* klass = object->AsClass(); 601 auto* copy_klass = down_cast<mirror::Class*>(copy); 602 copy_klass->SetSFieldsUnchecked(RelocatedAddressOfPointer(klass->GetSFields())); 603 copy_klass->SetIFieldsUnchecked(RelocatedAddressOfPointer(klass->GetIFields())); 604 copy_klass->SetDirectMethodsPtrUnchecked( 605 RelocatedAddressOfPointer(klass->GetDirectMethodsPtr())); 606 copy_klass->SetVirtualMethodsPtr(RelocatedAddressOfPointer(klass->GetVirtualMethodsPtr())); 607 auto* vtable = klass->GetVTable(); 608 if (vtable != nullptr) { 609 FixupNativePointerArray(vtable); 610 } 611 auto* iftable = klass->GetIfTable(); 612 if (iftable != nullptr) { 613 for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) { 614 if (iftable->GetMethodArrayCount(i) > 0) { 615 auto* method_array = iftable->GetMethodArray(i); 616 CHECK(method_array != nullptr); 617 FixupNativePointerArray(method_array); 618 } 619 } 620 } 621 if (klass->ShouldHaveEmbeddedImtAndVTable()) { 622 const size_t pointer_size = InstructionSetPointerSize(isa_); 623 for (int32_t i = 0; i < klass->GetEmbeddedVTableLength(); ++i) { 624 copy_klass->SetEmbeddedVTableEntryUnchecked(i, RelocatedAddressOfPointer( 625 klass->GetEmbeddedVTableEntry(i, pointer_size)), pointer_size); 626 } 627 for (size_t i = 0; i < mirror::Class::kImtSize; ++i) { 628 copy_klass->SetEmbeddedImTableEntry(i, RelocatedAddressOfPointer( 629 klass->GetEmbeddedImTableEntry(i, pointer_size)), pointer_size); 630 } 631 } 632 } 633 if (object->GetClass() == mirror::Method::StaticClass() || 634 object->GetClass() == mirror::Constructor::StaticClass()) { 635 // Need to go update the ArtMethod. 636 auto* dest = down_cast<mirror::AbstractMethod*>(copy); 637 auto* src = down_cast<mirror::AbstractMethod*>(object); 638 dest->SetArtMethod(RelocatedAddressOfPointer(src->GetArtMethod())); 639 } 640} 641 642void PatchOat::FixupMethod(ArtMethod* object, ArtMethod* copy) { 643 const size_t pointer_size = InstructionSetPointerSize(isa_); 644 copy->CopyFrom(object, pointer_size); 645 // Just update the entry points if it looks like we should. 646 // TODO: sanity check all the pointers' values 647 copy->SetDeclaringClass(RelocatedAddressOfPointer(object->GetDeclaringClass())); 648 copy->SetDexCacheResolvedMethods(RelocatedAddressOfPointer(object->GetDexCacheResolvedMethods())); 649 copy->SetDexCacheResolvedTypes(RelocatedAddressOfPointer(object->GetDexCacheResolvedTypes())); 650 copy->SetEntryPointFromQuickCompiledCodePtrSize(RelocatedAddressOfPointer( 651 object->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size)), pointer_size); 652 copy->SetEntryPointFromInterpreterPtrSize(RelocatedAddressOfPointer( 653 object->GetEntryPointFromInterpreterPtrSize(pointer_size)), pointer_size); 654 copy->SetEntryPointFromJniPtrSize(RelocatedAddressOfPointer( 655 object->GetEntryPointFromJniPtrSize(pointer_size)), pointer_size); 656} 657 658bool PatchOat::Patch(File* input_oat, off_t delta, File* output_oat, TimingLogger* timings, 659 bool output_oat_opened_from_fd, bool new_oat_out) { 660 CHECK(input_oat != nullptr); 661 CHECK(output_oat != nullptr); 662 CHECK_GE(input_oat->Fd(), 0); 663 CHECK_GE(output_oat->Fd(), 0); 664 TimingLogger::ScopedTiming t("Setup Oat File Patching", timings); 665 666 std::string error_msg; 667 std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat, 668 PROT_READ | PROT_WRITE, MAP_PRIVATE, &error_msg)); 669 if (elf.get() == nullptr) { 670 LOG(ERROR) << "unable to open oat file " << input_oat->GetPath() << " : " << error_msg; 671 return false; 672 } 673 674 MaybePic is_oat_pic = IsOatPic(elf.get()); 675 if (is_oat_pic >= ERROR_FIRST) { 676 // Error logged by IsOatPic 677 return false; 678 } else if (is_oat_pic == PIC) { 679 // Do not need to do ELF-file patching. Create a symlink and skip the rest. 680 // Any errors will be logged by the function call. 681 return ReplaceOatFileWithSymlink(input_oat->GetPath(), 682 output_oat->GetPath(), 683 output_oat_opened_from_fd, 684 new_oat_out); 685 } else { 686 CHECK(is_oat_pic == NOT_PIC); 687 } 688 689 PatchOat p(elf.release(), delta, timings); 690 t.NewTiming("Patch Oat file"); 691 if (!p.PatchElf()) { 692 return false; 693 } 694 695 t.NewTiming("Writing oat file"); 696 if (!p.WriteElf(output_oat)) { 697 return false; 698 } 699 return true; 700} 701 702template <typename ElfFileImpl> 703bool PatchOat::PatchOatHeader(ElfFileImpl* oat_file) { 704 auto rodata_sec = oat_file->FindSectionByName(".rodata"); 705 if (rodata_sec == nullptr) { 706 return false; 707 } 708 OatHeader* oat_header = reinterpret_cast<OatHeader*>(oat_file->Begin() + rodata_sec->sh_offset); 709 if (!oat_header->IsValid()) { 710 LOG(ERROR) << "Elf file " << oat_file->GetFile().GetPath() << " has an invalid oat header"; 711 return false; 712 } 713 oat_header->RelocateOat(delta_); 714 return true; 715} 716 717bool PatchOat::PatchElf() { 718 if (oat_file_->Is64Bit()) 719 return PatchElf<ElfFileImpl64>(oat_file_->GetImpl64()); 720 else 721 return PatchElf<ElfFileImpl32>(oat_file_->GetImpl32()); 722} 723 724template <typename ElfFileImpl> 725bool PatchOat::PatchElf(ElfFileImpl* oat_file) { 726 TimingLogger::ScopedTiming t("Fixup Elf Text Section", timings_); 727 728 // Fix up absolute references to locations within the boot image. 729 if (!oat_file->ApplyOatPatchesTo(".text", delta_)) { 730 return false; 731 } 732 733 // Update the OatHeader fields referencing the boot image. 734 if (!PatchOatHeader<ElfFileImpl>(oat_file)) { 735 return false; 736 } 737 738 bool need_boot_oat_fixup = true; 739 for (unsigned int i = 0; i < oat_file->GetProgramHeaderNum(); ++i) { 740 auto hdr = oat_file->GetProgramHeader(i); 741 if (hdr->p_type == PT_LOAD && hdr->p_vaddr == 0u) { 742 need_boot_oat_fixup = false; 743 break; 744 } 745 } 746 if (!need_boot_oat_fixup) { 747 // This is an app oat file that can be loaded at an arbitrary address in memory. 748 // Boot image references were patched above and there's nothing else to do. 749 return true; 750 } 751 752 // This is a boot oat file that's loaded at a particular address and we need 753 // to patch all absolute addresses, starting with ELF program headers. 754 755 t.NewTiming("Fixup Elf Headers"); 756 // Fixup Phdr's 757 oat_file->FixupProgramHeaders(delta_); 758 759 t.NewTiming("Fixup Section Headers"); 760 // Fixup Shdr's 761 oat_file->FixupSectionHeaders(delta_); 762 763 t.NewTiming("Fixup Dynamics"); 764 oat_file->FixupDynamic(delta_); 765 766 t.NewTiming("Fixup Elf Symbols"); 767 // Fixup dynsym 768 if (!oat_file->FixupSymbols(delta_, true)) { 769 return false; 770 } 771 // Fixup symtab 772 if (!oat_file->FixupSymbols(delta_, false)) { 773 return false; 774 } 775 776 t.NewTiming("Fixup Debug Sections"); 777 if (!oat_file->FixupDebugSections(delta_)) { 778 return false; 779 } 780 781 return true; 782} 783 784static int orig_argc; 785static char** orig_argv; 786 787static std::string CommandLine() { 788 std::vector<std::string> command; 789 for (int i = 0; i < orig_argc; ++i) { 790 command.push_back(orig_argv[i]); 791 } 792 return Join(command, ' '); 793} 794 795static void UsageErrorV(const char* fmt, va_list ap) { 796 std::string error; 797 StringAppendV(&error, fmt, ap); 798 LOG(ERROR) << error; 799} 800 801static void UsageError(const char* fmt, ...) { 802 va_list ap; 803 va_start(ap, fmt); 804 UsageErrorV(fmt, ap); 805 va_end(ap); 806} 807 808NO_RETURN static void Usage(const char *fmt, ...) { 809 va_list ap; 810 va_start(ap, fmt); 811 UsageErrorV(fmt, ap); 812 va_end(ap); 813 814 UsageError("Command: %s", CommandLine().c_str()); 815 UsageError("Usage: patchoat [options]..."); 816 UsageError(""); 817 UsageError(" --instruction-set=<isa>: Specifies the instruction set the patched code is"); 818 UsageError(" compiled for. Required if you use --input-oat-location"); 819 UsageError(""); 820 UsageError(" --input-oat-file=<file.oat>: Specifies the exact filename of the oat file to be"); 821 UsageError(" patched."); 822 UsageError(""); 823 UsageError(" --input-oat-fd=<file-descriptor>: Specifies the file-descriptor of the oat file"); 824 UsageError(" to be patched."); 825 UsageError(""); 826 UsageError(" --input-oat-location=<file.oat>: Specifies the 'location' to read the patched"); 827 UsageError(" oat file from. If used one must also supply the --instruction-set"); 828 UsageError(""); 829 UsageError(" --input-image-location=<file.art>: Specifies the 'location' of the image file to"); 830 UsageError(" be patched. If --instruction-set is not given it will use the instruction set"); 831 UsageError(" extracted from the --input-oat-file."); 832 UsageError(""); 833 UsageError(" --output-oat-file=<file.oat>: Specifies the exact file to write the patched oat"); 834 UsageError(" file to."); 835 UsageError(""); 836 UsageError(" --output-oat-fd=<file-descriptor>: Specifies the file-descriptor to write the"); 837 UsageError(" the patched oat file to."); 838 UsageError(""); 839 UsageError(" --output-image-file=<file.art>: Specifies the exact file to write the patched"); 840 UsageError(" image file to."); 841 UsageError(""); 842 UsageError(" --output-image-fd=<file-descriptor>: Specifies the file-descriptor to write the"); 843 UsageError(" the patched image file to."); 844 UsageError(""); 845 UsageError(" --orig-base-offset=<original-base-offset>: Specify the base offset the input file"); 846 UsageError(" was compiled with. This is needed if one is specifying a --base-offset"); 847 UsageError(""); 848 UsageError(" --base-offset=<new-base-offset>: Specify the base offset we will repatch the"); 849 UsageError(" given files to use. This requires that --orig-base-offset is also given."); 850 UsageError(""); 851 UsageError(" --base-offset-delta=<delta>: Specify the amount to change the old base-offset by."); 852 UsageError(" This value may be negative."); 853 UsageError(""); 854 UsageError(" --patched-image-file=<file.art>: Use the same patch delta as was used to patch"); 855 UsageError(" the given image file."); 856 UsageError(""); 857 UsageError(" --patched-image-location=<file.art>: Use the same patch delta as was used to"); 858 UsageError(" patch the given image location. If used one must also specify the"); 859 UsageError(" --instruction-set flag. It will search for this image in the same way that"); 860 UsageError(" is done when loading one."); 861 UsageError(""); 862 UsageError(" --lock-output: Obtain a flock on output oat file before starting."); 863 UsageError(""); 864 UsageError(" --no-lock-output: Do not attempt to obtain a flock on output oat file."); 865 UsageError(""); 866 UsageError(" --dump-timings: dump out patch timing information"); 867 UsageError(""); 868 UsageError(" --no-dump-timings: do not dump out patch timing information"); 869 UsageError(""); 870 871 exit(EXIT_FAILURE); 872} 873 874static bool ReadBaseDelta(const char* name, off_t* delta, std::string* error_msg) { 875 CHECK(name != nullptr); 876 CHECK(delta != nullptr); 877 std::unique_ptr<File> file; 878 if (OS::FileExists(name)) { 879 file.reset(OS::OpenFileForReading(name)); 880 if (file.get() == nullptr) { 881 *error_msg = "Failed to open file %s for reading"; 882 return false; 883 } 884 } else { 885 *error_msg = "File %s does not exist"; 886 return false; 887 } 888 CHECK(file.get() != nullptr); 889 ImageHeader hdr; 890 if (sizeof(hdr) != file->Read(reinterpret_cast<char*>(&hdr), sizeof(hdr), 0)) { 891 *error_msg = "Failed to read file %s"; 892 return false; 893 } 894 if (!hdr.IsValid()) { 895 *error_msg = "%s does not contain a valid image header."; 896 return false; 897 } 898 *delta = hdr.GetPatchDelta(); 899 return true; 900} 901 902static File* CreateOrOpen(const char* name, bool* created) { 903 if (OS::FileExists(name)) { 904 *created = false; 905 return OS::OpenFileReadWrite(name); 906 } else { 907 *created = true; 908 std::unique_ptr<File> f(OS::CreateEmptyFile(name)); 909 if (f.get() != nullptr) { 910 if (fchmod(f->Fd(), 0644) != 0) { 911 PLOG(ERROR) << "Unable to make " << name << " world readable"; 912 TEMP_FAILURE_RETRY(unlink(name)); 913 return nullptr; 914 } 915 } 916 return f.release(); 917 } 918} 919 920// Either try to close the file (close=true), or erase it. 921static bool FinishFile(File* file, bool close) { 922 if (close) { 923 if (file->FlushCloseOrErase() != 0) { 924 PLOG(ERROR) << "Failed to flush and close file."; 925 return false; 926 } 927 return true; 928 } else { 929 file->Erase(); 930 return false; 931 } 932} 933 934static int patchoat(int argc, char **argv) { 935 InitLogging(argv); 936 MemMap::Init(); 937 const bool debug = kIsDebugBuild; 938 orig_argc = argc; 939 orig_argv = argv; 940 TimingLogger timings("patcher", false, false); 941 942 InitLogging(argv); 943 944 // Skip over the command name. 945 argv++; 946 argc--; 947 948 if (argc == 0) { 949 Usage("No arguments specified"); 950 } 951 952 timings.StartTiming("Patchoat"); 953 954 // cmd line args 955 bool isa_set = false; 956 InstructionSet isa = kNone; 957 std::string input_oat_filename; 958 std::string input_oat_location; 959 int input_oat_fd = -1; 960 bool have_input_oat = false; 961 std::string input_image_location; 962 std::string output_oat_filename; 963 int output_oat_fd = -1; 964 bool have_output_oat = false; 965 std::string output_image_filename; 966 int output_image_fd = -1; 967 bool have_output_image = false; 968 uintptr_t base_offset = 0; 969 bool base_offset_set = false; 970 uintptr_t orig_base_offset = 0; 971 bool orig_base_offset_set = false; 972 off_t base_delta = 0; 973 bool base_delta_set = false; 974 std::string patched_image_filename; 975 std::string patched_image_location; 976 bool dump_timings = kIsDebugBuild; 977 bool lock_output = true; 978 979 for (int i = 0; i < argc; ++i) { 980 const StringPiece option(argv[i]); 981 const bool log_options = false; 982 if (log_options) { 983 LOG(INFO) << "patchoat: option[" << i << "]=" << argv[i]; 984 } 985 if (option.starts_with("--instruction-set=")) { 986 isa_set = true; 987 const char* isa_str = option.substr(strlen("--instruction-set=")).data(); 988 isa = GetInstructionSetFromString(isa_str); 989 if (isa == kNone) { 990 Usage("Unknown or invalid instruction set %s", isa_str); 991 } 992 } else if (option.starts_with("--input-oat-location=")) { 993 if (have_input_oat) { 994 Usage("Only one of --input-oat-file, --input-oat-location and --input-oat-fd may be used."); 995 } 996 have_input_oat = true; 997 input_oat_location = option.substr(strlen("--input-oat-location=")).data(); 998 } else if (option.starts_with("--input-oat-file=")) { 999 if (have_input_oat) { 1000 Usage("Only one of --input-oat-file, --input-oat-location and --input-oat-fd may be used."); 1001 } 1002 have_input_oat = true; 1003 input_oat_filename = option.substr(strlen("--input-oat-file=")).data(); 1004 } else if (option.starts_with("--input-oat-fd=")) { 1005 if (have_input_oat) { 1006 Usage("Only one of --input-oat-file, --input-oat-location and --input-oat-fd may be used."); 1007 } 1008 have_input_oat = true; 1009 const char* oat_fd_str = option.substr(strlen("--input-oat-fd=")).data(); 1010 if (!ParseInt(oat_fd_str, &input_oat_fd)) { 1011 Usage("Failed to parse --input-oat-fd argument '%s' as an integer", oat_fd_str); 1012 } 1013 if (input_oat_fd < 0) { 1014 Usage("--input-oat-fd pass a negative value %d", input_oat_fd); 1015 } 1016 } else if (option.starts_with("--input-image-location=")) { 1017 input_image_location = option.substr(strlen("--input-image-location=")).data(); 1018 } else if (option.starts_with("--output-oat-file=")) { 1019 if (have_output_oat) { 1020 Usage("Only one of --output-oat-file, and --output-oat-fd may be used."); 1021 } 1022 have_output_oat = true; 1023 output_oat_filename = option.substr(strlen("--output-oat-file=")).data(); 1024 } else if (option.starts_with("--output-oat-fd=")) { 1025 if (have_output_oat) { 1026 Usage("Only one of --output-oat-file, --output-oat-fd may be used."); 1027 } 1028 have_output_oat = true; 1029 const char* oat_fd_str = option.substr(strlen("--output-oat-fd=")).data(); 1030 if (!ParseInt(oat_fd_str, &output_oat_fd)) { 1031 Usage("Failed to parse --output-oat-fd argument '%s' as an integer", oat_fd_str); 1032 } 1033 if (output_oat_fd < 0) { 1034 Usage("--output-oat-fd pass a negative value %d", output_oat_fd); 1035 } 1036 } else if (option.starts_with("--output-image-file=")) { 1037 if (have_output_image) { 1038 Usage("Only one of --output-image-file, and --output-image-fd may be used."); 1039 } 1040 have_output_image = true; 1041 output_image_filename = option.substr(strlen("--output-image-file=")).data(); 1042 } else if (option.starts_with("--output-image-fd=")) { 1043 if (have_output_image) { 1044 Usage("Only one of --output-image-file, and --output-image-fd may be used."); 1045 } 1046 have_output_image = true; 1047 const char* image_fd_str = option.substr(strlen("--output-image-fd=")).data(); 1048 if (!ParseInt(image_fd_str, &output_image_fd)) { 1049 Usage("Failed to parse --output-image-fd argument '%s' as an integer", image_fd_str); 1050 } 1051 if (output_image_fd < 0) { 1052 Usage("--output-image-fd pass a negative value %d", output_image_fd); 1053 } 1054 } else if (option.starts_with("--orig-base-offset=")) { 1055 const char* orig_base_offset_str = option.substr(strlen("--orig-base-offset=")).data(); 1056 orig_base_offset_set = true; 1057 if (!ParseUint(orig_base_offset_str, &orig_base_offset)) { 1058 Usage("Failed to parse --orig-base-offset argument '%s' as an uintptr_t", 1059 orig_base_offset_str); 1060 } 1061 } else if (option.starts_with("--base-offset=")) { 1062 const char* base_offset_str = option.substr(strlen("--base-offset=")).data(); 1063 base_offset_set = true; 1064 if (!ParseUint(base_offset_str, &base_offset)) { 1065 Usage("Failed to parse --base-offset argument '%s' as an uintptr_t", base_offset_str); 1066 } 1067 } else if (option.starts_with("--base-offset-delta=")) { 1068 const char* base_delta_str = option.substr(strlen("--base-offset-delta=")).data(); 1069 base_delta_set = true; 1070 if (!ParseInt(base_delta_str, &base_delta)) { 1071 Usage("Failed to parse --base-offset-delta argument '%s' as an off_t", base_delta_str); 1072 } 1073 } else if (option.starts_with("--patched-image-location=")) { 1074 patched_image_location = option.substr(strlen("--patched-image-location=")).data(); 1075 } else if (option.starts_with("--patched-image-file=")) { 1076 patched_image_filename = option.substr(strlen("--patched-image-file=")).data(); 1077 } else if (option == "--lock-output") { 1078 lock_output = true; 1079 } else if (option == "--no-lock-output") { 1080 lock_output = false; 1081 } else if (option == "--dump-timings") { 1082 dump_timings = true; 1083 } else if (option == "--no-dump-timings") { 1084 dump_timings = false; 1085 } else { 1086 Usage("Unknown argument %s", option.data()); 1087 } 1088 } 1089 1090 { 1091 // Only 1 of these may be set. 1092 uint32_t cnt = 0; 1093 cnt += (base_delta_set) ? 1 : 0; 1094 cnt += (base_offset_set && orig_base_offset_set) ? 1 : 0; 1095 cnt += (!patched_image_filename.empty()) ? 1 : 0; 1096 cnt += (!patched_image_location.empty()) ? 1 : 0; 1097 if (cnt > 1) { 1098 Usage("Only one of --base-offset/--orig-base-offset, --base-offset-delta, " 1099 "--patched-image-filename or --patched-image-location may be used."); 1100 } else if (cnt == 0) { 1101 Usage("Must specify --base-offset-delta, --base-offset and --orig-base-offset, " 1102 "--patched-image-location or --patched-image-file"); 1103 } 1104 } 1105 1106 if (have_input_oat != have_output_oat) { 1107 Usage("Either both input and output oat must be supplied or niether must be."); 1108 } 1109 1110 if ((!input_image_location.empty()) != have_output_image) { 1111 Usage("Either both input and output image must be supplied or niether must be."); 1112 } 1113 1114 // We know we have both the input and output so rename for clarity. 1115 bool have_image_files = have_output_image; 1116 bool have_oat_files = have_output_oat; 1117 1118 if (!have_oat_files && !have_image_files) { 1119 Usage("Must be patching either an oat or an image file or both."); 1120 } 1121 1122 if (!have_oat_files && !isa_set) { 1123 Usage("Must include ISA if patching an image file without an oat file."); 1124 } 1125 1126 if (!input_oat_location.empty()) { 1127 if (!isa_set) { 1128 Usage("specifying a location requires specifying an instruction set"); 1129 } 1130 if (!LocationToFilename(input_oat_location, isa, &input_oat_filename)) { 1131 Usage("Unable to find filename for input oat location %s", input_oat_location.c_str()); 1132 } 1133 if (debug) { 1134 LOG(INFO) << "Using input-oat-file " << input_oat_filename; 1135 } 1136 } 1137 if (!patched_image_location.empty()) { 1138 if (!isa_set) { 1139 Usage("specifying a location requires specifying an instruction set"); 1140 } 1141 std::string system_filename; 1142 bool has_system = false; 1143 std::string cache_filename; 1144 bool has_cache = false; 1145 bool has_android_data_unused = false; 1146 bool is_global_cache = false; 1147 if (!gc::space::ImageSpace::FindImageFilename(patched_image_location.c_str(), isa, 1148 &system_filename, &has_system, &cache_filename, 1149 &has_android_data_unused, &has_cache, 1150 &is_global_cache)) { 1151 Usage("Unable to determine image file for location %s", patched_image_location.c_str()); 1152 } 1153 if (has_cache) { 1154 patched_image_filename = cache_filename; 1155 } else if (has_system) { 1156 LOG(WARNING) << "Only image file found was in /system for image location " 1157 << patched_image_location; 1158 patched_image_filename = system_filename; 1159 } else { 1160 Usage("Unable to determine image file for location %s", patched_image_location.c_str()); 1161 } 1162 if (debug) { 1163 LOG(INFO) << "Using patched-image-file " << patched_image_filename; 1164 } 1165 } 1166 1167 if (!base_delta_set) { 1168 if (orig_base_offset_set && base_offset_set) { 1169 base_delta_set = true; 1170 base_delta = base_offset - orig_base_offset; 1171 } else if (!patched_image_filename.empty()) { 1172 base_delta_set = true; 1173 std::string error_msg; 1174 if (!ReadBaseDelta(patched_image_filename.c_str(), &base_delta, &error_msg)) { 1175 Usage(error_msg.c_str(), patched_image_filename.c_str()); 1176 } 1177 } else { 1178 if (base_offset_set) { 1179 Usage("Unable to determine original base offset."); 1180 } else { 1181 Usage("Must supply a desired new offset or delta."); 1182 } 1183 } 1184 } 1185 1186 if (!IsAligned<kPageSize>(base_delta)) { 1187 Usage("Base offset/delta must be alligned to a pagesize (0x%08x) boundary.", kPageSize); 1188 } 1189 1190 // Do we need to cleanup output files if we fail? 1191 bool new_image_out = false; 1192 bool new_oat_out = false; 1193 1194 std::unique_ptr<File> input_oat; 1195 std::unique_ptr<File> output_oat; 1196 std::unique_ptr<File> output_image; 1197 1198 if (have_image_files) { 1199 CHECK(!input_image_location.empty()); 1200 1201 if (output_image_fd != -1) { 1202 if (output_image_filename.empty()) { 1203 output_image_filename = "output-image-file"; 1204 } 1205 output_image.reset(new File(output_image_fd, output_image_filename, true)); 1206 } else { 1207 CHECK(!output_image_filename.empty()); 1208 output_image.reset(CreateOrOpen(output_image_filename.c_str(), &new_image_out)); 1209 } 1210 } else { 1211 CHECK(output_image_filename.empty() && output_image_fd == -1 && input_image_location.empty()); 1212 } 1213 1214 if (have_oat_files) { 1215 if (input_oat_fd != -1) { 1216 if (input_oat_filename.empty()) { 1217 input_oat_filename = "input-oat-file"; 1218 } 1219 input_oat.reset(new File(input_oat_fd, input_oat_filename, false)); 1220 if (input_oat_fd == output_oat_fd) { 1221 input_oat.get()->DisableAutoClose(); 1222 } 1223 if (input_oat == nullptr) { 1224 // Unlikely, but ensure exhaustive logging in non-0 exit code case 1225 LOG(ERROR) << "Failed to open input oat file by its FD" << input_oat_fd; 1226 } 1227 } else { 1228 CHECK(!input_oat_filename.empty()); 1229 input_oat.reset(OS::OpenFileForReading(input_oat_filename.c_str())); 1230 if (input_oat == nullptr) { 1231 int err = errno; 1232 LOG(ERROR) << "Failed to open input oat file " << input_oat_filename 1233 << ": " << strerror(err) << "(" << err << ")"; 1234 } 1235 } 1236 1237 if (output_oat_fd != -1) { 1238 if (output_oat_filename.empty()) { 1239 output_oat_filename = "output-oat-file"; 1240 } 1241 output_oat.reset(new File(output_oat_fd, output_oat_filename, true)); 1242 if (output_oat == nullptr) { 1243 // Unlikely, but ensure exhaustive logging in non-0 exit code case 1244 LOG(ERROR) << "Failed to open output oat file by its FD" << output_oat_fd; 1245 } 1246 } else { 1247 CHECK(!output_oat_filename.empty()); 1248 output_oat.reset(CreateOrOpen(output_oat_filename.c_str(), &new_oat_out)); 1249 if (output_oat == nullptr) { 1250 int err = errno; 1251 LOG(ERROR) << "Failed to open output oat file " << output_oat_filename 1252 << ": " << strerror(err) << "(" << err << ")"; 1253 } 1254 } 1255 } 1256 1257 // TODO: get rid of this. 1258 auto cleanup = [&output_image_filename, &output_oat_filename, 1259 &new_oat_out, &new_image_out, &timings, &dump_timings](bool success) { 1260 timings.EndTiming(); 1261 if (!success) { 1262 if (new_oat_out) { 1263 CHECK(!output_oat_filename.empty()); 1264 TEMP_FAILURE_RETRY(unlink(output_oat_filename.c_str())); 1265 } 1266 if (new_image_out) { 1267 CHECK(!output_image_filename.empty()); 1268 TEMP_FAILURE_RETRY(unlink(output_image_filename.c_str())); 1269 } 1270 } 1271 if (dump_timings) { 1272 LOG(INFO) << Dumpable<TimingLogger>(timings); 1273 } 1274 1275 if (kIsDebugBuild) { 1276 LOG(INFO) << "Cleaning up.. success? " << success; 1277 } 1278 }; 1279 1280 if (have_oat_files && (input_oat.get() == nullptr || output_oat.get() == nullptr)) { 1281 LOG(ERROR) << "Failed to open input/output oat files"; 1282 cleanup(false); 1283 return EXIT_FAILURE; 1284 } else if (have_image_files && output_image.get() == nullptr) { 1285 LOG(ERROR) << "Failed to open output image file"; 1286 cleanup(false); 1287 return EXIT_FAILURE; 1288 } 1289 1290 if (debug) { 1291 LOG(INFO) << "moving offset by " << base_delta 1292 << " (0x" << std::hex << base_delta << ") bytes or " 1293 << std::dec << (base_delta/kPageSize) << " pages."; 1294 } 1295 1296 // TODO: is it going to be promatic to unlink a file that was flock-ed? 1297 ScopedFlock output_oat_lock; 1298 if (lock_output) { 1299 std::string error_msg; 1300 if (have_oat_files && !output_oat_lock.Init(output_oat.get(), &error_msg)) { 1301 LOG(ERROR) << "Unable to lock output oat " << output_image->GetPath() << ": " << error_msg; 1302 cleanup(false); 1303 return EXIT_FAILURE; 1304 } 1305 } 1306 1307 bool ret; 1308 if (have_image_files && have_oat_files) { 1309 TimingLogger::ScopedTiming pt("patch image and oat", &timings); 1310 ret = PatchOat::Patch(input_oat.get(), input_image_location, base_delta, 1311 output_oat.get(), output_image.get(), isa, &timings, 1312 output_oat_fd >= 0, // was it opened from FD? 1313 new_oat_out); 1314 // The order here doesn't matter. If the first one is successfully saved and the second one 1315 // erased, ImageSpace will still detect a problem and not use the files. 1316 ret = ret && FinishFile(output_image.get(), ret); 1317 ret = ret && FinishFile(output_oat.get(), ret); 1318 } else if (have_oat_files) { 1319 TimingLogger::ScopedTiming pt("patch oat", &timings); 1320 ret = PatchOat::Patch(input_oat.get(), base_delta, output_oat.get(), &timings, 1321 output_oat_fd >= 0, // was it opened from FD? 1322 new_oat_out); 1323 ret = ret && FinishFile(output_oat.get(), ret); 1324 } else if (have_image_files) { 1325 TimingLogger::ScopedTiming pt("patch image", &timings); 1326 ret = PatchOat::Patch(input_image_location, base_delta, output_image.get(), isa, &timings); 1327 ret = ret && FinishFile(output_image.get(), ret); 1328 } else { 1329 CHECK(false); 1330 ret = true; 1331 } 1332 1333 if (kIsDebugBuild) { 1334 LOG(INFO) << "Exiting with return ... " << ret; 1335 } 1336 cleanup(ret); 1337 return (ret) ? EXIT_SUCCESS : EXIT_FAILURE; 1338} 1339 1340} // namespace art 1341 1342int main(int argc, char **argv) { 1343 return art::patchoat(argc, argv); 1344} 1345