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