patchoat.cc revision e401d146407d61eeb99f8d6176b2ac13c4df1e33
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 440void PatchOat::PatchDexFileArrays(mirror::ObjectArray<mirror::Object>* img_roots) { 441 auto* dex_caches = down_cast<mirror::ObjectArray<mirror::DexCache>*>( 442 img_roots->Get(ImageHeader::kDexCaches)); 443 for (size_t i = 0, count = dex_caches->GetLength(); i < count; ++i) { 444 auto* dex_cache = dex_caches->GetWithoutChecks(i); 445 auto* fields = dex_cache->GetResolvedFields(); 446 if (fields != nullptr) { 447 CHECK(!fields->IsObjectArray()); 448 CHECK(fields->IsArrayInstance()); 449 FixupNativePointerArray(fields); 450 } 451 auto* methods = dex_cache->GetResolvedMethods(); 452 if (methods != nullptr) { 453 CHECK(!methods->IsObjectArray()); 454 CHECK(methods->IsArrayInstance()); 455 FixupNativePointerArray(methods); 456 } 457 } 458} 459 460void PatchOat::FixupNativePointerArray(mirror::PointerArray* object) { 461 if (object->IsIntArray()) { 462 mirror::IntArray* arr = object->AsIntArray(); 463 mirror::IntArray* copy_arr = down_cast<mirror::IntArray*>(RelocatedCopyOf(arr)); 464 for (size_t j = 0, count2 = arr->GetLength(); j < count2; ++j) { 465 copy_arr->SetWithoutChecks<false>( 466 j, RelocatedAddressOfIntPointer(arr->GetWithoutChecks(j))); 467 } 468 } else { 469 CHECK(object->IsLongArray()); 470 mirror::LongArray* arr = object->AsLongArray(); 471 mirror::LongArray* copy_arr = down_cast<mirror::LongArray*>(RelocatedCopyOf(arr)); 472 for (size_t j = 0, count2 = arr->GetLength(); j < count2; ++j) { 473 copy_arr->SetWithoutChecks<false>( 474 j, RelocatedAddressOfIntPointer(arr->GetWithoutChecks(j))); 475 } 476 } 477} 478 479bool PatchOat::PatchImage() { 480 ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin()); 481 CHECK_GT(image_->Size(), sizeof(ImageHeader)); 482 // These are the roots from the original file. 483 auto* img_roots = image_header->GetImageRoots(); 484 image_header->RelocateImage(delta_); 485 486 // Patch and update ArtFields. 487 PatchArtFields(image_header); 488 489 // Patch and update ArtMethods. 490 PatchArtMethods(image_header); 491 492 // Patch dex file int/long arrays which point to ArtFields. 493 PatchDexFileArrays(img_roots); 494 495 VisitObject(img_roots); 496 if (!image_header->IsValid()) { 497 LOG(ERROR) << "reloction renders image header invalid"; 498 return false; 499 } 500 501 { 502 TimingLogger::ScopedTiming t("Walk Bitmap", timings_); 503 // Walk the bitmap. 504 WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); 505 bitmap_->Walk(PatchOat::BitmapCallback, this); 506 } 507 return true; 508} 509 510bool PatchOat::InHeap(mirror::Object* o) { 511 uintptr_t begin = reinterpret_cast<uintptr_t>(heap_->Begin()); 512 uintptr_t end = reinterpret_cast<uintptr_t>(heap_->End()); 513 uintptr_t obj = reinterpret_cast<uintptr_t>(o); 514 return o == nullptr || (begin <= obj && obj < end); 515} 516 517void PatchOat::PatchVisitor::operator() (mirror::Object* obj, MemberOffset off, 518 bool is_static_unused ATTRIBUTE_UNUSED) const { 519 mirror::Object* referent = obj->GetFieldObject<mirror::Object, kVerifyNone>(off); 520 DCHECK(patcher_->InHeap(referent)) << "Referent is not in the heap."; 521 mirror::Object* moved_object = patcher_->RelocatedAddressOfPointer(referent); 522 copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(off, moved_object); 523} 524 525void PatchOat::PatchVisitor::operator() (mirror::Class* cls ATTRIBUTE_UNUSED, 526 mirror::Reference* ref) const { 527 MemberOffset off = mirror::Reference::ReferentOffset(); 528 mirror::Object* referent = ref->GetReferent(); 529 DCHECK(patcher_->InHeap(referent)) << "Referent is not in the heap."; 530 mirror::Object* moved_object = patcher_->RelocatedAddressOfPointer(referent); 531 copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(off, moved_object); 532} 533 534const OatHeader* PatchOat::GetOatHeader(const ElfFile* elf_file) { 535 if (elf_file->Is64Bit()) { 536 return GetOatHeader<ElfFileImpl64>(elf_file->GetImpl64()); 537 } else { 538 return GetOatHeader<ElfFileImpl32>(elf_file->GetImpl32()); 539 } 540} 541 542template <typename ElfFileImpl> 543const OatHeader* PatchOat::GetOatHeader(const ElfFileImpl* elf_file) { 544 auto rodata_sec = elf_file->FindSectionByName(".rodata"); 545 if (rodata_sec == nullptr) { 546 return nullptr; 547 } 548 549 OatHeader* oat_header = reinterpret_cast<OatHeader*>(elf_file->Begin() + rodata_sec->sh_offset); 550 return oat_header; 551} 552 553// Called by BitmapCallback 554void PatchOat::VisitObject(mirror::Object* object) { 555 mirror::Object* copy = RelocatedCopyOf(object); 556 CHECK(copy != nullptr); 557 if (kUseBakerOrBrooksReadBarrier) { 558 object->AssertReadBarrierPointer(); 559 if (kUseBrooksReadBarrier) { 560 mirror::Object* moved_to = RelocatedAddressOfPointer(object); 561 copy->SetReadBarrierPointer(moved_to); 562 DCHECK_EQ(copy->GetReadBarrierPointer(), moved_to); 563 } 564 } 565 PatchOat::PatchVisitor visitor(this, copy); 566 object->VisitReferences<true, kVerifyNone>(visitor, visitor); 567 if (object->IsClass<kVerifyNone>()) { 568 auto* klass = object->AsClass(); 569 auto* copy_klass = down_cast<mirror::Class*>(copy); 570 copy_klass->SetSFieldsUnchecked(RelocatedAddressOfPointer(klass->GetSFields())); 571 copy_klass->SetIFieldsUnchecked(RelocatedAddressOfPointer(klass->GetIFields())); 572 copy_klass->SetDirectMethodsPtrUnchecked( 573 RelocatedAddressOfPointer(klass->GetDirectMethodsPtr())); 574 copy_klass->SetVirtualMethodsPtr(RelocatedAddressOfPointer(klass->GetVirtualMethodsPtr())); 575 auto* vtable = klass->GetVTable(); 576 if (vtable != nullptr) { 577 FixupNativePointerArray(vtable); 578 } 579 auto* iftable = klass->GetIfTable(); 580 if (iftable != nullptr) { 581 for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) { 582 if (iftable->GetMethodArrayCount(i) > 0) { 583 auto* method_array = iftable->GetMethodArray(i); 584 CHECK(method_array != nullptr); 585 FixupNativePointerArray(method_array); 586 } 587 } 588 } 589 if (klass->ShouldHaveEmbeddedImtAndVTable()) { 590 const size_t pointer_size = InstructionSetPointerSize(isa_); 591 for (int32_t i = 0; i < klass->GetEmbeddedVTableLength(); ++i) { 592 copy_klass->SetEmbeddedVTableEntryUnchecked(i, RelocatedAddressOfPointer( 593 klass->GetEmbeddedVTableEntry(i, pointer_size)), pointer_size); 594 } 595 for (size_t i = 0; i < mirror::Class::kImtSize; ++i) { 596 copy_klass->SetEmbeddedImTableEntry(i, RelocatedAddressOfPointer( 597 klass->GetEmbeddedImTableEntry(i, pointer_size)), pointer_size); 598 } 599 } 600 } 601 if (object->GetClass() == mirror::Method::StaticClass() || 602 object->GetClass() == mirror::Constructor::StaticClass()) { 603 // Need to go update the ArtMethod. 604 auto* dest = down_cast<mirror::AbstractMethod*>(copy); 605 auto* src = down_cast<mirror::AbstractMethod*>(object); 606 dest->SetArtMethod(RelocatedAddressOfPointer(src->GetArtMethod())); 607 } 608} 609 610void PatchOat::FixupMethod(ArtMethod* object, ArtMethod* copy) { 611 const size_t pointer_size = InstructionSetPointerSize(isa_); 612 copy->CopyFrom(object, pointer_size); 613 // Just update the entry points if it looks like we should. 614 // TODO: sanity check all the pointers' values 615 copy->SetDeclaringClass(RelocatedAddressOfPointer(object->GetDeclaringClass())); 616 copy->SetDexCacheResolvedMethods(RelocatedAddressOfPointer(object->GetDexCacheResolvedMethods())); 617 copy->SetDexCacheResolvedTypes(RelocatedAddressOfPointer(object->GetDexCacheResolvedTypes())); 618 copy->SetEntryPointFromQuickCompiledCodePtrSize(RelocatedAddressOfPointer( 619 object->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size)), pointer_size); 620 copy->SetEntryPointFromInterpreterPtrSize(RelocatedAddressOfPointer( 621 object->GetEntryPointFromInterpreterPtrSize(pointer_size)), pointer_size); 622 copy->SetEntryPointFromJniPtrSize(RelocatedAddressOfPointer( 623 object->GetEntryPointFromJniPtrSize(pointer_size)), pointer_size); 624} 625 626bool PatchOat::Patch(File* input_oat, off_t delta, File* output_oat, TimingLogger* timings, 627 bool output_oat_opened_from_fd, bool new_oat_out) { 628 CHECK(input_oat != nullptr); 629 CHECK(output_oat != nullptr); 630 CHECK_GE(input_oat->Fd(), 0); 631 CHECK_GE(output_oat->Fd(), 0); 632 TimingLogger::ScopedTiming t("Setup Oat File Patching", timings); 633 634 std::string error_msg; 635 std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat, 636 PROT_READ | PROT_WRITE, MAP_PRIVATE, &error_msg)); 637 if (elf.get() == nullptr) { 638 LOG(ERROR) << "unable to open oat file " << input_oat->GetPath() << " : " << error_msg; 639 return false; 640 } 641 642 MaybePic is_oat_pic = IsOatPic(elf.get()); 643 if (is_oat_pic >= ERROR_FIRST) { 644 // Error logged by IsOatPic 645 return false; 646 } else if (is_oat_pic == PIC) { 647 // Do not need to do ELF-file patching. Create a symlink and skip the rest. 648 // Any errors will be logged by the function call. 649 return ReplaceOatFileWithSymlink(input_oat->GetPath(), 650 output_oat->GetPath(), 651 output_oat_opened_from_fd, 652 new_oat_out); 653 } else { 654 CHECK(is_oat_pic == NOT_PIC); 655 } 656 657 PatchOat p(elf.release(), delta, timings); 658 t.NewTiming("Patch Oat file"); 659 if (!p.PatchElf()) { 660 return false; 661 } 662 663 t.NewTiming("Writing oat file"); 664 if (!p.WriteElf(output_oat)) { 665 return false; 666 } 667 return true; 668} 669 670template <typename ElfFileImpl> 671bool PatchOat::PatchOatHeader(ElfFileImpl* oat_file) { 672 auto rodata_sec = oat_file->FindSectionByName(".rodata"); 673 if (rodata_sec == nullptr) { 674 return false; 675 } 676 OatHeader* oat_header = reinterpret_cast<OatHeader*>(oat_file->Begin() + rodata_sec->sh_offset); 677 if (!oat_header->IsValid()) { 678 LOG(ERROR) << "Elf file " << oat_file->GetFile().GetPath() << " has an invalid oat header"; 679 return false; 680 } 681 oat_header->RelocateOat(delta_); 682 return true; 683} 684 685bool PatchOat::PatchElf() { 686 if (oat_file_->Is64Bit()) 687 return PatchElf<ElfFileImpl64>(oat_file_->GetImpl64()); 688 else 689 return PatchElf<ElfFileImpl32>(oat_file_->GetImpl32()); 690} 691 692template <typename ElfFileImpl> 693bool PatchOat::PatchElf(ElfFileImpl* oat_file) { 694 TimingLogger::ScopedTiming t("Fixup Elf Text Section", timings_); 695 696 // Fix up absolute references to locations within the boot image. 697 if (!oat_file->ApplyOatPatchesTo(".text", delta_)) { 698 return false; 699 } 700 701 // Update the OatHeader fields referencing the boot image. 702 if (!PatchOatHeader<ElfFileImpl>(oat_file)) { 703 return false; 704 } 705 706 bool need_boot_oat_fixup = true; 707 for (unsigned int i = 0; i < oat_file->GetProgramHeaderNum(); ++i) { 708 auto hdr = oat_file->GetProgramHeader(i); 709 if (hdr->p_type == PT_LOAD && hdr->p_vaddr == 0u) { 710 need_boot_oat_fixup = false; 711 break; 712 } 713 } 714 if (!need_boot_oat_fixup) { 715 // This is an app oat file that can be loaded at an arbitrary address in memory. 716 // Boot image references were patched above and there's nothing else to do. 717 return true; 718 } 719 720 // This is a boot oat file that's loaded at a particular address and we need 721 // to patch all absolute addresses, starting with ELF program headers. 722 723 t.NewTiming("Fixup Elf Headers"); 724 // Fixup Phdr's 725 oat_file->FixupProgramHeaders(delta_); 726 727 t.NewTiming("Fixup Section Headers"); 728 // Fixup Shdr's 729 oat_file->FixupSectionHeaders(delta_); 730 731 t.NewTiming("Fixup Dynamics"); 732 oat_file->FixupDynamic(delta_); 733 734 t.NewTiming("Fixup Elf Symbols"); 735 // Fixup dynsym 736 if (!oat_file->FixupSymbols(delta_, true)) { 737 return false; 738 } 739 // Fixup symtab 740 if (!oat_file->FixupSymbols(delta_, false)) { 741 return false; 742 } 743 744 t.NewTiming("Fixup Debug Sections"); 745 if (!oat_file->FixupDebugSections(delta_)) { 746 return false; 747 } 748 749 return true; 750} 751 752static int orig_argc; 753static char** orig_argv; 754 755static std::string CommandLine() { 756 std::vector<std::string> command; 757 for (int i = 0; i < orig_argc; ++i) { 758 command.push_back(orig_argv[i]); 759 } 760 return Join(command, ' '); 761} 762 763static void UsageErrorV(const char* fmt, va_list ap) { 764 std::string error; 765 StringAppendV(&error, fmt, ap); 766 LOG(ERROR) << error; 767} 768 769static void UsageError(const char* fmt, ...) { 770 va_list ap; 771 va_start(ap, fmt); 772 UsageErrorV(fmt, ap); 773 va_end(ap); 774} 775 776NO_RETURN static void Usage(const char *fmt, ...) { 777 va_list ap; 778 va_start(ap, fmt); 779 UsageErrorV(fmt, ap); 780 va_end(ap); 781 782 UsageError("Command: %s", CommandLine().c_str()); 783 UsageError("Usage: patchoat [options]..."); 784 UsageError(""); 785 UsageError(" --instruction-set=<isa>: Specifies the instruction set the patched code is"); 786 UsageError(" compiled for. Required if you use --input-oat-location"); 787 UsageError(""); 788 UsageError(" --input-oat-file=<file.oat>: Specifies the exact filename of the oat file to be"); 789 UsageError(" patched."); 790 UsageError(""); 791 UsageError(" --input-oat-fd=<file-descriptor>: Specifies the file-descriptor of the oat file"); 792 UsageError(" to be patched."); 793 UsageError(""); 794 UsageError(" --input-oat-location=<file.oat>: Specifies the 'location' to read the patched"); 795 UsageError(" oat file from. If used one must also supply the --instruction-set"); 796 UsageError(""); 797 UsageError(" --input-image-location=<file.art>: Specifies the 'location' of the image file to"); 798 UsageError(" be patched. If --instruction-set is not given it will use the instruction set"); 799 UsageError(" extracted from the --input-oat-file."); 800 UsageError(""); 801 UsageError(" --output-oat-file=<file.oat>: Specifies the exact file to write the patched oat"); 802 UsageError(" file to."); 803 UsageError(""); 804 UsageError(" --output-oat-fd=<file-descriptor>: Specifies the file-descriptor to write the"); 805 UsageError(" the patched oat file to."); 806 UsageError(""); 807 UsageError(" --output-image-file=<file.art>: Specifies the exact file to write the patched"); 808 UsageError(" image file to."); 809 UsageError(""); 810 UsageError(" --output-image-fd=<file-descriptor>: Specifies the file-descriptor to write the"); 811 UsageError(" the patched image file to."); 812 UsageError(""); 813 UsageError(" --orig-base-offset=<original-base-offset>: Specify the base offset the input file"); 814 UsageError(" was compiled with. This is needed if one is specifying a --base-offset"); 815 UsageError(""); 816 UsageError(" --base-offset=<new-base-offset>: Specify the base offset we will repatch the"); 817 UsageError(" given files to use. This requires that --orig-base-offset is also given."); 818 UsageError(""); 819 UsageError(" --base-offset-delta=<delta>: Specify the amount to change the old base-offset by."); 820 UsageError(" This value may be negative."); 821 UsageError(""); 822 UsageError(" --patched-image-file=<file.art>: Use the same patch delta as was used to patch"); 823 UsageError(" the given image file."); 824 UsageError(""); 825 UsageError(" --patched-image-location=<file.art>: Use the same patch delta as was used to"); 826 UsageError(" patch the given image location. If used one must also specify the"); 827 UsageError(" --instruction-set flag. It will search for this image in the same way that"); 828 UsageError(" is done when loading one."); 829 UsageError(""); 830 UsageError(" --lock-output: Obtain a flock on output oat file before starting."); 831 UsageError(""); 832 UsageError(" --no-lock-output: Do not attempt to obtain a flock on output oat file."); 833 UsageError(""); 834 UsageError(" --dump-timings: dump out patch timing information"); 835 UsageError(""); 836 UsageError(" --no-dump-timings: do not dump out patch timing information"); 837 UsageError(""); 838 839 exit(EXIT_FAILURE); 840} 841 842static bool ReadBaseDelta(const char* name, off_t* delta, std::string* error_msg) { 843 CHECK(name != nullptr); 844 CHECK(delta != nullptr); 845 std::unique_ptr<File> file; 846 if (OS::FileExists(name)) { 847 file.reset(OS::OpenFileForReading(name)); 848 if (file.get() == nullptr) { 849 *error_msg = "Failed to open file %s for reading"; 850 return false; 851 } 852 } else { 853 *error_msg = "File %s does not exist"; 854 return false; 855 } 856 CHECK(file.get() != nullptr); 857 ImageHeader hdr; 858 if (sizeof(hdr) != file->Read(reinterpret_cast<char*>(&hdr), sizeof(hdr), 0)) { 859 *error_msg = "Failed to read file %s"; 860 return false; 861 } 862 if (!hdr.IsValid()) { 863 *error_msg = "%s does not contain a valid image header."; 864 return false; 865 } 866 *delta = hdr.GetPatchDelta(); 867 return true; 868} 869 870static File* CreateOrOpen(const char* name, bool* created) { 871 if (OS::FileExists(name)) { 872 *created = false; 873 return OS::OpenFileReadWrite(name); 874 } else { 875 *created = true; 876 std::unique_ptr<File> f(OS::CreateEmptyFile(name)); 877 if (f.get() != nullptr) { 878 if (fchmod(f->Fd(), 0644) != 0) { 879 PLOG(ERROR) << "Unable to make " << name << " world readable"; 880 TEMP_FAILURE_RETRY(unlink(name)); 881 return nullptr; 882 } 883 } 884 return f.release(); 885 } 886} 887 888// Either try to close the file (close=true), or erase it. 889static bool FinishFile(File* file, bool close) { 890 if (close) { 891 if (file->FlushCloseOrErase() != 0) { 892 PLOG(ERROR) << "Failed to flush and close file."; 893 return false; 894 } 895 return true; 896 } else { 897 file->Erase(); 898 return false; 899 } 900} 901 902static int patchoat(int argc, char **argv) { 903 InitLogging(argv); 904 MemMap::Init(); 905 const bool debug = kIsDebugBuild; 906 orig_argc = argc; 907 orig_argv = argv; 908 TimingLogger timings("patcher", false, false); 909 910 InitLogging(argv); 911 912 // Skip over the command name. 913 argv++; 914 argc--; 915 916 if (argc == 0) { 917 Usage("No arguments specified"); 918 } 919 920 timings.StartTiming("Patchoat"); 921 922 // cmd line args 923 bool isa_set = false; 924 InstructionSet isa = kNone; 925 std::string input_oat_filename; 926 std::string input_oat_location; 927 int input_oat_fd = -1; 928 bool have_input_oat = false; 929 std::string input_image_location; 930 std::string output_oat_filename; 931 int output_oat_fd = -1; 932 bool have_output_oat = false; 933 std::string output_image_filename; 934 int output_image_fd = -1; 935 bool have_output_image = false; 936 uintptr_t base_offset = 0; 937 bool base_offset_set = false; 938 uintptr_t orig_base_offset = 0; 939 bool orig_base_offset_set = false; 940 off_t base_delta = 0; 941 bool base_delta_set = false; 942 std::string patched_image_filename; 943 std::string patched_image_location; 944 bool dump_timings = kIsDebugBuild; 945 bool lock_output = true; 946 947 for (int i = 0; i < argc; ++i) { 948 const StringPiece option(argv[i]); 949 const bool log_options = false; 950 if (log_options) { 951 LOG(INFO) << "patchoat: option[" << i << "]=" << argv[i]; 952 } 953 if (option.starts_with("--instruction-set=")) { 954 isa_set = true; 955 const char* isa_str = option.substr(strlen("--instruction-set=")).data(); 956 isa = GetInstructionSetFromString(isa_str); 957 if (isa == kNone) { 958 Usage("Unknown or invalid instruction set %s", isa_str); 959 } 960 } else if (option.starts_with("--input-oat-location=")) { 961 if (have_input_oat) { 962 Usage("Only one of --input-oat-file, --input-oat-location and --input-oat-fd may be used."); 963 } 964 have_input_oat = true; 965 input_oat_location = option.substr(strlen("--input-oat-location=")).data(); 966 } else if (option.starts_with("--input-oat-file=")) { 967 if (have_input_oat) { 968 Usage("Only one of --input-oat-file, --input-oat-location and --input-oat-fd may be used."); 969 } 970 have_input_oat = true; 971 input_oat_filename = option.substr(strlen("--input-oat-file=")).data(); 972 } else if (option.starts_with("--input-oat-fd=")) { 973 if (have_input_oat) { 974 Usage("Only one of --input-oat-file, --input-oat-location and --input-oat-fd may be used."); 975 } 976 have_input_oat = true; 977 const char* oat_fd_str = option.substr(strlen("--input-oat-fd=")).data(); 978 if (!ParseInt(oat_fd_str, &input_oat_fd)) { 979 Usage("Failed to parse --input-oat-fd argument '%s' as an integer", oat_fd_str); 980 } 981 if (input_oat_fd < 0) { 982 Usage("--input-oat-fd pass a negative value %d", input_oat_fd); 983 } 984 } else if (option.starts_with("--input-image-location=")) { 985 input_image_location = option.substr(strlen("--input-image-location=")).data(); 986 } else if (option.starts_with("--output-oat-file=")) { 987 if (have_output_oat) { 988 Usage("Only one of --output-oat-file, and --output-oat-fd may be used."); 989 } 990 have_output_oat = true; 991 output_oat_filename = option.substr(strlen("--output-oat-file=")).data(); 992 } else if (option.starts_with("--output-oat-fd=")) { 993 if (have_output_oat) { 994 Usage("Only one of --output-oat-file, --output-oat-fd may be used."); 995 } 996 have_output_oat = true; 997 const char* oat_fd_str = option.substr(strlen("--output-oat-fd=")).data(); 998 if (!ParseInt(oat_fd_str, &output_oat_fd)) { 999 Usage("Failed to parse --output-oat-fd argument '%s' as an integer", oat_fd_str); 1000 } 1001 if (output_oat_fd < 0) { 1002 Usage("--output-oat-fd pass a negative value %d", output_oat_fd); 1003 } 1004 } else if (option.starts_with("--output-image-file=")) { 1005 if (have_output_image) { 1006 Usage("Only one of --output-image-file, and --output-image-fd may be used."); 1007 } 1008 have_output_image = true; 1009 output_image_filename = option.substr(strlen("--output-image-file=")).data(); 1010 } else if (option.starts_with("--output-image-fd=")) { 1011 if (have_output_image) { 1012 Usage("Only one of --output-image-file, and --output-image-fd may be used."); 1013 } 1014 have_output_image = true; 1015 const char* image_fd_str = option.substr(strlen("--output-image-fd=")).data(); 1016 if (!ParseInt(image_fd_str, &output_image_fd)) { 1017 Usage("Failed to parse --output-image-fd argument '%s' as an integer", image_fd_str); 1018 } 1019 if (output_image_fd < 0) { 1020 Usage("--output-image-fd pass a negative value %d", output_image_fd); 1021 } 1022 } else if (option.starts_with("--orig-base-offset=")) { 1023 const char* orig_base_offset_str = option.substr(strlen("--orig-base-offset=")).data(); 1024 orig_base_offset_set = true; 1025 if (!ParseUint(orig_base_offset_str, &orig_base_offset)) { 1026 Usage("Failed to parse --orig-base-offset argument '%s' as an uintptr_t", 1027 orig_base_offset_str); 1028 } 1029 } else if (option.starts_with("--base-offset=")) { 1030 const char* base_offset_str = option.substr(strlen("--base-offset=")).data(); 1031 base_offset_set = true; 1032 if (!ParseUint(base_offset_str, &base_offset)) { 1033 Usage("Failed to parse --base-offset argument '%s' as an uintptr_t", base_offset_str); 1034 } 1035 } else if (option.starts_with("--base-offset-delta=")) { 1036 const char* base_delta_str = option.substr(strlen("--base-offset-delta=")).data(); 1037 base_delta_set = true; 1038 if (!ParseInt(base_delta_str, &base_delta)) { 1039 Usage("Failed to parse --base-offset-delta argument '%s' as an off_t", base_delta_str); 1040 } 1041 } else if (option.starts_with("--patched-image-location=")) { 1042 patched_image_location = option.substr(strlen("--patched-image-location=")).data(); 1043 } else if (option.starts_with("--patched-image-file=")) { 1044 patched_image_filename = option.substr(strlen("--patched-image-file=")).data(); 1045 } else if (option == "--lock-output") { 1046 lock_output = true; 1047 } else if (option == "--no-lock-output") { 1048 lock_output = false; 1049 } else if (option == "--dump-timings") { 1050 dump_timings = true; 1051 } else if (option == "--no-dump-timings") { 1052 dump_timings = false; 1053 } else { 1054 Usage("Unknown argument %s", option.data()); 1055 } 1056 } 1057 1058 { 1059 // Only 1 of these may be set. 1060 uint32_t cnt = 0; 1061 cnt += (base_delta_set) ? 1 : 0; 1062 cnt += (base_offset_set && orig_base_offset_set) ? 1 : 0; 1063 cnt += (!patched_image_filename.empty()) ? 1 : 0; 1064 cnt += (!patched_image_location.empty()) ? 1 : 0; 1065 if (cnt > 1) { 1066 Usage("Only one of --base-offset/--orig-base-offset, --base-offset-delta, " 1067 "--patched-image-filename or --patched-image-location may be used."); 1068 } else if (cnt == 0) { 1069 Usage("Must specify --base-offset-delta, --base-offset and --orig-base-offset, " 1070 "--patched-image-location or --patched-image-file"); 1071 } 1072 } 1073 1074 if (have_input_oat != have_output_oat) { 1075 Usage("Either both input and output oat must be supplied or niether must be."); 1076 } 1077 1078 if ((!input_image_location.empty()) != have_output_image) { 1079 Usage("Either both input and output image must be supplied or niether must be."); 1080 } 1081 1082 // We know we have both the input and output so rename for clarity. 1083 bool have_image_files = have_output_image; 1084 bool have_oat_files = have_output_oat; 1085 1086 if (!have_oat_files && !have_image_files) { 1087 Usage("Must be patching either an oat or an image file or both."); 1088 } 1089 1090 if (!have_oat_files && !isa_set) { 1091 Usage("Must include ISA if patching an image file without an oat file."); 1092 } 1093 1094 if (!input_oat_location.empty()) { 1095 if (!isa_set) { 1096 Usage("specifying a location requires specifying an instruction set"); 1097 } 1098 if (!LocationToFilename(input_oat_location, isa, &input_oat_filename)) { 1099 Usage("Unable to find filename for input oat location %s", input_oat_location.c_str()); 1100 } 1101 if (debug) { 1102 LOG(INFO) << "Using input-oat-file " << input_oat_filename; 1103 } 1104 } 1105 if (!patched_image_location.empty()) { 1106 if (!isa_set) { 1107 Usage("specifying a location requires specifying an instruction set"); 1108 } 1109 std::string system_filename; 1110 bool has_system = false; 1111 std::string cache_filename; 1112 bool has_cache = false; 1113 bool has_android_data_unused = false; 1114 bool is_global_cache = false; 1115 if (!gc::space::ImageSpace::FindImageFilename(patched_image_location.c_str(), isa, 1116 &system_filename, &has_system, &cache_filename, 1117 &has_android_data_unused, &has_cache, 1118 &is_global_cache)) { 1119 Usage("Unable to determine image file for location %s", patched_image_location.c_str()); 1120 } 1121 if (has_cache) { 1122 patched_image_filename = cache_filename; 1123 } else if (has_system) { 1124 LOG(WARNING) << "Only image file found was in /system for image location " 1125 << patched_image_location; 1126 patched_image_filename = system_filename; 1127 } else { 1128 Usage("Unable to determine image file for location %s", patched_image_location.c_str()); 1129 } 1130 if (debug) { 1131 LOG(INFO) << "Using patched-image-file " << patched_image_filename; 1132 } 1133 } 1134 1135 if (!base_delta_set) { 1136 if (orig_base_offset_set && base_offset_set) { 1137 base_delta_set = true; 1138 base_delta = base_offset - orig_base_offset; 1139 } else if (!patched_image_filename.empty()) { 1140 base_delta_set = true; 1141 std::string error_msg; 1142 if (!ReadBaseDelta(patched_image_filename.c_str(), &base_delta, &error_msg)) { 1143 Usage(error_msg.c_str(), patched_image_filename.c_str()); 1144 } 1145 } else { 1146 if (base_offset_set) { 1147 Usage("Unable to determine original base offset."); 1148 } else { 1149 Usage("Must supply a desired new offset or delta."); 1150 } 1151 } 1152 } 1153 1154 if (!IsAligned<kPageSize>(base_delta)) { 1155 Usage("Base offset/delta must be alligned to a pagesize (0x%08x) boundary.", kPageSize); 1156 } 1157 1158 // Do we need to cleanup output files if we fail? 1159 bool new_image_out = false; 1160 bool new_oat_out = false; 1161 1162 std::unique_ptr<File> input_oat; 1163 std::unique_ptr<File> output_oat; 1164 std::unique_ptr<File> output_image; 1165 1166 if (have_image_files) { 1167 CHECK(!input_image_location.empty()); 1168 1169 if (output_image_fd != -1) { 1170 if (output_image_filename.empty()) { 1171 output_image_filename = "output-image-file"; 1172 } 1173 output_image.reset(new File(output_image_fd, output_image_filename, true)); 1174 } else { 1175 CHECK(!output_image_filename.empty()); 1176 output_image.reset(CreateOrOpen(output_image_filename.c_str(), &new_image_out)); 1177 } 1178 } else { 1179 CHECK(output_image_filename.empty() && output_image_fd == -1 && input_image_location.empty()); 1180 } 1181 1182 if (have_oat_files) { 1183 if (input_oat_fd != -1) { 1184 if (input_oat_filename.empty()) { 1185 input_oat_filename = "input-oat-file"; 1186 } 1187 input_oat.reset(new File(input_oat_fd, input_oat_filename, false)); 1188 if (input_oat_fd == output_oat_fd) { 1189 input_oat.get()->DisableAutoClose(); 1190 } 1191 if (input_oat == nullptr) { 1192 // Unlikely, but ensure exhaustive logging in non-0 exit code case 1193 LOG(ERROR) << "Failed to open input oat file by its FD" << input_oat_fd; 1194 } 1195 } else { 1196 CHECK(!input_oat_filename.empty()); 1197 input_oat.reset(OS::OpenFileForReading(input_oat_filename.c_str())); 1198 if (input_oat == nullptr) { 1199 int err = errno; 1200 LOG(ERROR) << "Failed to open input oat file " << input_oat_filename 1201 << ": " << strerror(err) << "(" << err << ")"; 1202 } 1203 } 1204 1205 if (output_oat_fd != -1) { 1206 if (output_oat_filename.empty()) { 1207 output_oat_filename = "output-oat-file"; 1208 } 1209 output_oat.reset(new File(output_oat_fd, output_oat_filename, true)); 1210 if (output_oat == nullptr) { 1211 // Unlikely, but ensure exhaustive logging in non-0 exit code case 1212 LOG(ERROR) << "Failed to open output oat file by its FD" << output_oat_fd; 1213 } 1214 } else { 1215 CHECK(!output_oat_filename.empty()); 1216 output_oat.reset(CreateOrOpen(output_oat_filename.c_str(), &new_oat_out)); 1217 if (output_oat == nullptr) { 1218 int err = errno; 1219 LOG(ERROR) << "Failed to open output oat file " << output_oat_filename 1220 << ": " << strerror(err) << "(" << err << ")"; 1221 } 1222 } 1223 } 1224 1225 // TODO: get rid of this. 1226 auto cleanup = [&output_image_filename, &output_oat_filename, 1227 &new_oat_out, &new_image_out, &timings, &dump_timings](bool success) { 1228 timings.EndTiming(); 1229 if (!success) { 1230 if (new_oat_out) { 1231 CHECK(!output_oat_filename.empty()); 1232 TEMP_FAILURE_RETRY(unlink(output_oat_filename.c_str())); 1233 } 1234 if (new_image_out) { 1235 CHECK(!output_image_filename.empty()); 1236 TEMP_FAILURE_RETRY(unlink(output_image_filename.c_str())); 1237 } 1238 } 1239 if (dump_timings) { 1240 LOG(INFO) << Dumpable<TimingLogger>(timings); 1241 } 1242 1243 if (kIsDebugBuild) { 1244 LOG(INFO) << "Cleaning up.. success? " << success; 1245 } 1246 }; 1247 1248 if (have_oat_files && (input_oat.get() == nullptr || output_oat.get() == nullptr)) { 1249 LOG(ERROR) << "Failed to open input/output oat files"; 1250 cleanup(false); 1251 return EXIT_FAILURE; 1252 } else if (have_image_files && output_image.get() == nullptr) { 1253 LOG(ERROR) << "Failed to open output image file"; 1254 cleanup(false); 1255 return EXIT_FAILURE; 1256 } 1257 1258 if (debug) { 1259 LOG(INFO) << "moving offset by " << base_delta 1260 << " (0x" << std::hex << base_delta << ") bytes or " 1261 << std::dec << (base_delta/kPageSize) << " pages."; 1262 } 1263 1264 // TODO: is it going to be promatic to unlink a file that was flock-ed? 1265 ScopedFlock output_oat_lock; 1266 if (lock_output) { 1267 std::string error_msg; 1268 if (have_oat_files && !output_oat_lock.Init(output_oat.get(), &error_msg)) { 1269 LOG(ERROR) << "Unable to lock output oat " << output_image->GetPath() << ": " << error_msg; 1270 cleanup(false); 1271 return EXIT_FAILURE; 1272 } 1273 } 1274 1275 bool ret; 1276 if (have_image_files && have_oat_files) { 1277 TimingLogger::ScopedTiming pt("patch image and oat", &timings); 1278 ret = PatchOat::Patch(input_oat.get(), input_image_location, base_delta, 1279 output_oat.get(), output_image.get(), isa, &timings, 1280 output_oat_fd >= 0, // was it opened from FD? 1281 new_oat_out); 1282 // The order here doesn't matter. If the first one is successfully saved and the second one 1283 // erased, ImageSpace will still detect a problem and not use the files. 1284 ret = ret && FinishFile(output_image.get(), ret); 1285 ret = ret && FinishFile(output_oat.get(), ret); 1286 } else if (have_oat_files) { 1287 TimingLogger::ScopedTiming pt("patch oat", &timings); 1288 ret = PatchOat::Patch(input_oat.get(), base_delta, output_oat.get(), &timings, 1289 output_oat_fd >= 0, // was it opened from FD? 1290 new_oat_out); 1291 ret = ret && FinishFile(output_oat.get(), ret); 1292 } else if (have_image_files) { 1293 TimingLogger::ScopedTiming pt("patch image", &timings); 1294 ret = PatchOat::Patch(input_image_location, base_delta, output_image.get(), isa, &timings); 1295 ret = ret && FinishFile(output_image.get(), ret); 1296 } else { 1297 CHECK(false); 1298 ret = true; 1299 } 1300 1301 if (kIsDebugBuild) { 1302 LOG(INFO) << "Exiting with return ... " << ret; 1303 } 1304 cleanup(ret); 1305 return (ret) ? EXIT_SUCCESS : EXIT_FAILURE; 1306} 1307 1308} // namespace art 1309 1310int main(int argc, char **argv) { 1311 return art::patchoat(argc, argv); 1312} 1313