patchoat.cc revision 8f4b056427a9d2321e3aa4f21ca8ffb18b3e5ae6
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 <openssl/sha.h> 19#include <stdio.h> 20#include <stdlib.h> 21#include <sys/file.h> 22#include <sys/stat.h> 23#include <unistd.h> 24 25#include <string> 26#include <vector> 27 28#include "android-base/file.h" 29#include "android-base/stringprintf.h" 30#include "android-base/strings.h" 31 32#include "art_field-inl.h" 33#include "art_method-inl.h" 34#include "base/dumpable.h" 35#include "base/file_utils.h" 36#include "base/leb128.h" 37#include "base/logging.h" // For InitLogging. 38#include "base/mutex.h" 39#include "base/memory_tool.h" 40#include "base/os.h" 41#include "base/scoped_flock.h" 42#include "base/stringpiece.h" 43#include "base/unix_file/fd_file.h" 44#include "base/unix_file/random_access_file_utils.h" 45#include "base/utils.h" 46#include "elf_file.h" 47#include "elf_file_impl.h" 48#include "elf_utils.h" 49#include "gc/space/image_space.h" 50#include "image-inl.h" 51#include "intern_table.h" 52#include "mirror/dex_cache.h" 53#include "mirror/executable.h" 54#include "mirror/method.h" 55#include "mirror/object-inl.h" 56#include "mirror/object-refvisitor-inl.h" 57#include "mirror/reference.h" 58#include "noop_compiler_callbacks.h" 59#include "offsets.h" 60#include "runtime.h" 61#include "scoped_thread_state_change-inl.h" 62#include "thread.h" 63 64namespace art { 65 66using android::base::StringPrintf; 67 68static const OatHeader* GetOatHeader(const ElfFile* elf_file) { 69 uint64_t off = 0; 70 if (!elf_file->GetSectionOffsetAndSize(".rodata", &off, nullptr)) { 71 return nullptr; 72 } 73 74 OatHeader* oat_header = reinterpret_cast<OatHeader*>(elf_file->Begin() + off); 75 return oat_header; 76} 77 78static File* CreateOrOpen(const char* name) { 79 if (OS::FileExists(name)) { 80 return OS::OpenFileReadWrite(name); 81 } else { 82 std::unique_ptr<File> f(OS::CreateEmptyFile(name)); 83 if (f.get() != nullptr) { 84 if (fchmod(f->Fd(), 0644) != 0) { 85 PLOG(ERROR) << "Unable to make " << name << " world readable"; 86 unlink(name); 87 return nullptr; 88 } 89 } 90 return f.release(); 91 } 92} 93 94// Either try to close the file (close=true), or erase it. 95static bool FinishFile(File* file, bool close) { 96 if (close) { 97 if (file->FlushCloseOrErase() != 0) { 98 PLOG(ERROR) << "Failed to flush and close file."; 99 return false; 100 } 101 return true; 102 } else { 103 file->Erase(); 104 return false; 105 } 106} 107 108static bool SymlinkFile(const std::string& input_filename, const std::string& output_filename) { 109 if (input_filename == output_filename) { 110 // Input and output are the same, nothing to do. 111 return true; 112 } 113 114 // Unlink the original filename, since we are overwriting it. 115 unlink(output_filename.c_str()); 116 117 // Create a symlink from the source file to the target path. 118 if (symlink(input_filename.c_str(), output_filename.c_str()) < 0) { 119 PLOG(ERROR) << "Failed to create symlink " << output_filename << " -> " << input_filename; 120 return false; 121 } 122 123 if (kIsDebugBuild) { 124 LOG(INFO) << "Created symlink " << output_filename << " -> " << input_filename; 125 } 126 127 return true; 128} 129 130bool PatchOat::GeneratePatch( 131 const MemMap& original, 132 const MemMap& relocated, 133 std::vector<uint8_t>* output, 134 std::string* error_msg) { 135 // FORMAT of the patch (aka image relocation) file: 136 // * SHA-256 digest (32 bytes) of original/unrelocated file (e.g., the one from /system) 137 // * List of monotonically increasing offsets (max value defined by uint32_t) at which relocations 138 // occur. 139 // Each element is represented as the delta from the previous offset in the list (first element 140 // is a delta from 0). Each delta is encoded using unsigned LEB128: little-endian 141 // variable-length 7 bits per byte encoding, where all bytes have the highest bit (0x80) set 142 // except for the final byte which does not have that bit set. For example, 0x3f is offset 0x3f, 143 // whereas 0xbf 0x05 is offset (0x3f & 0x7f) | (0x5 << 7) which is 0x2bf. Most deltas end up 144 // being encoding using just one byte, achieving ~4x decrease in relocation file size compared 145 // to the encoding where offsets are stored verbatim, as uint32_t. 146 147 size_t original_size = original.Size(); 148 size_t relocated_size = relocated.Size(); 149 if (original_size != relocated_size) { 150 *error_msg = 151 StringPrintf( 152 "Original and relocated image sizes differ: %zu vs %zu", original_size, relocated_size); 153 return false; 154 } 155 if ((original_size % 4) != 0) { 156 *error_msg = StringPrintf("Image size not multiple of 4: %zu", original_size); 157 return false; 158 } 159 if (original_size > UINT32_MAX) { 160 *error_msg = StringPrintf("Image too large: %zu" , original_size); 161 return false; 162 } 163 164 const ImageHeader& relocated_header = 165 *reinterpret_cast<const ImageHeader*>(relocated.Begin()); 166 // Offsets are supposed to differ between original and relocated by this value 167 off_t expected_diff = relocated_header.GetPatchDelta(); 168 if (expected_diff == 0) { 169 // Can't identify offsets which are supposed to differ due to relocation 170 *error_msg = "Relocation delta is 0"; 171 return false; 172 } 173 174 // Output the SHA-256 digest of the original 175 output->resize(SHA256_DIGEST_LENGTH); 176 const uint8_t* original_bytes = original.Begin(); 177 SHA256(original_bytes, original_size, output->data()); 178 179 // Output the list of offsets at which the original and patched images differ 180 size_t last_diff_offset = 0; 181 size_t diff_offset_count = 0; 182 const uint8_t* relocated_bytes = relocated.Begin(); 183 for (size_t offset = 0; offset < original_size; offset += 4) { 184 uint32_t original_value = *reinterpret_cast<const uint32_t*>(original_bytes + offset); 185 uint32_t relocated_value = *reinterpret_cast<const uint32_t*>(relocated_bytes + offset); 186 off_t diff = relocated_value - original_value; 187 if (diff == 0) { 188 continue; 189 } else if (diff != expected_diff) { 190 *error_msg = 191 StringPrintf( 192 "Unexpected diff at offset %zu. Expected: %jd, but was: %jd", 193 offset, 194 (intmax_t) expected_diff, 195 (intmax_t) diff); 196 return false; 197 } 198 199 uint32_t offset_diff = offset - last_diff_offset; 200 last_diff_offset = offset; 201 diff_offset_count++; 202 203 EncodeUnsignedLeb128(output, offset_diff); 204 } 205 206 if (diff_offset_count == 0) { 207 *error_msg = "Original and patched images are identical"; 208 return false; 209 } 210 211 return true; 212} 213 214static bool WriteRelFile( 215 const MemMap& original, 216 const MemMap& relocated, 217 const std::string& rel_filename, 218 std::string* error_msg) { 219 std::vector<uint8_t> output; 220 if (!PatchOat::GeneratePatch(original, relocated, &output, error_msg)) { 221 return false; 222 } 223 224 std::unique_ptr<File> rel_file(OS::CreateEmptyFileWriteOnly(rel_filename.c_str())); 225 if (rel_file.get() == nullptr) { 226 *error_msg = StringPrintf("Failed to create/open output file %s", rel_filename.c_str()); 227 return false; 228 } 229 if (!rel_file->WriteFully(output.data(), output.size())) { 230 *error_msg = StringPrintf("Failed to write to %s", rel_filename.c_str()); 231 return false; 232 } 233 if (rel_file->FlushCloseOrErase() != 0) { 234 *error_msg = StringPrintf("Failed to flush and close %s", rel_filename.c_str()); 235 return false; 236 } 237 238 return true; 239} 240 241static bool CheckImageIdenticalToOriginalExceptForRelocation( 242 const std::string& relocated_filename, 243 const std::string& original_filename, 244 std::string* error_msg) { 245 *error_msg = ""; 246 std::string rel_filename = original_filename + ".rel"; 247 std::unique_ptr<File> rel_file(OS::OpenFileForReading(rel_filename.c_str())); 248 if (rel_file.get() == nullptr) { 249 *error_msg = StringPrintf("Failed to open image relocation file %s", rel_filename.c_str()); 250 return false; 251 } 252 int64_t rel_size = rel_file->GetLength(); 253 if (rel_size < 0) { 254 *error_msg = StringPrintf("Error while getting size of image relocation file %s", 255 rel_filename.c_str()); 256 return false; 257 } 258 std::unique_ptr<uint8_t[]> rel(new uint8_t[rel_size]); 259 if (!rel_file->ReadFully(rel.get(), rel_size)) { 260 *error_msg = StringPrintf("Failed to read image relocation file %s", rel_filename.c_str()); 261 return false; 262 } 263 264 std::unique_ptr<File> image_file(OS::OpenFileForReading(relocated_filename.c_str())); 265 if (image_file.get() == nullptr) { 266 *error_msg = StringPrintf("Unable to open relocated image file %s", 267 relocated_filename.c_str()); 268 return false; 269 } 270 271 int64_t image_size = image_file->GetLength(); 272 if (image_size < 0) { 273 *error_msg = StringPrintf("Error while getting size of relocated image file %s", 274 relocated_filename.c_str()); 275 return false; 276 } 277 if ((image_size % 4) != 0) { 278 *error_msg = 279 StringPrintf( 280 "Relocated image file %s size not multiple of 4: %" PRId64, 281 relocated_filename.c_str(), image_size); 282 return false; 283 } 284 if (image_size > std::numeric_limits<uint32_t>::max()) { 285 *error_msg = 286 StringPrintf( 287 "Relocated image file %s too large: %" PRId64, relocated_filename.c_str(), image_size); 288 return false; 289 } 290 291 std::unique_ptr<uint8_t[]> image(new uint8_t[image_size]); 292 if (!image_file->ReadFully(image.get(), image_size)) { 293 *error_msg = StringPrintf("Failed to read relocated image file %s", relocated_filename.c_str()); 294 return false; 295 } 296 297 const uint8_t* original_image_digest = rel.get(); 298 if (rel_size < SHA256_DIGEST_LENGTH) { 299 *error_msg = StringPrintf("Malformed image relocation file %s: too short", 300 rel_filename.c_str()); 301 return false; 302 } 303 304 const ImageHeader& image_header = *reinterpret_cast<const ImageHeader*>(image.get()); 305 off_t expected_diff = image_header.GetPatchDelta(); 306 307 if (expected_diff == 0) { 308 *error_msg = StringPrintf("Unsuported patch delta of zero in %s", 309 relocated_filename.c_str()); 310 return false; 311 } 312 313 // Relocated image is expected to differ from the original due to relocation. 314 // Unrelocate the image in memory to compensate. 315 uint8_t* image_start = image.get(); 316 const uint8_t* rel_end = &rel[rel_size]; 317 const uint8_t* rel_ptr = &rel[SHA256_DIGEST_LENGTH]; 318 // The remaining .rel file consists of offsets at which relocation should've occurred. 319 // For each offset, we "unrelocate" the image by subtracting the expected relocation 320 // diff value (as specified in the image header). 321 // 322 // Each offset is encoded as a delta/diff relative to the previous offset. With the 323 // very first offset being encoded relative to offset 0. 324 // Deltas are encoded using little-endian 7 bits per byte encoding, with all bytes except 325 // the last one having the highest bit set. 326 uint32_t offset = 0; 327 while (rel_ptr != rel_end) { 328 uint32_t offset_delta = 0; 329 if (DecodeUnsignedLeb128Checked(&rel_ptr, rel_end, &offset_delta)) { 330 offset += offset_delta; 331 uint32_t *image_value = reinterpret_cast<uint32_t*>(image_start + offset); 332 *image_value -= expected_diff; 333 } else { 334 *error_msg = 335 StringPrintf( 336 "Malformed image relocation file %s: " 337 "last byte has it's most significant bit set", 338 rel_filename.c_str()); 339 return false; 340 } 341 } 342 343 // Image in memory is now supposed to be identical to the original. We 344 // confirm this by comparing the digest of the in-memory image to the expected 345 // digest from relocation file. 346 uint8_t image_digest[SHA256_DIGEST_LENGTH]; 347 SHA256(image.get(), image_size, image_digest); 348 if (memcmp(image_digest, original_image_digest, SHA256_DIGEST_LENGTH) != 0) { 349 *error_msg = 350 StringPrintf( 351 "Relocated image %s does not match the original %s after unrelocation", 352 relocated_filename.c_str(), 353 original_filename.c_str()); 354 return false; 355 } 356 357 // Relocated image is identical to the original, once relocations are taken into account 358 return true; 359} 360 361static bool VerifySymlink(const std::string& intended_target, const std::string& link_name) { 362 std::string actual_target; 363 if (!android::base::Readlink(link_name, &actual_target)) { 364 PLOG(ERROR) << "Readlink on " << link_name << " failed."; 365 return false; 366 } 367 return actual_target == intended_target; 368} 369 370static bool VerifyVdexAndOatSymlinks(const std::string& input_image_filename, 371 const std::string& output_image_filename) { 372 return VerifySymlink(ImageHeader::GetVdexLocationFromImageLocation(input_image_filename), 373 ImageHeader::GetVdexLocationFromImageLocation(output_image_filename)) 374 && VerifySymlink(ImageHeader::GetOatLocationFromImageLocation(input_image_filename), 375 ImageHeader::GetOatLocationFromImageLocation(output_image_filename)); 376} 377 378bool PatchOat::CreateVdexAndOatSymlinks(const std::string& input_image_filename, 379 const std::string& output_image_filename) { 380 std::string input_vdex_filename = 381 ImageHeader::GetVdexLocationFromImageLocation(input_image_filename); 382 std::string input_oat_filename = 383 ImageHeader::GetOatLocationFromImageLocation(input_image_filename); 384 385 std::unique_ptr<File> input_oat_file(OS::OpenFileForReading(input_oat_filename.c_str())); 386 if (input_oat_file.get() == nullptr) { 387 LOG(ERROR) << "Unable to open input oat file at " << input_oat_filename; 388 return false; 389 } 390 std::string error_msg; 391 std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat_file.get(), 392 PROT_READ | PROT_WRITE, 393 MAP_PRIVATE, 394 &error_msg)); 395 if (elf.get() == nullptr) { 396 LOG(ERROR) << "Unable to open oat file " << input_oat_filename << " : " << error_msg; 397 return false; 398 } 399 400 MaybePic is_oat_pic = IsOatPic(elf.get()); 401 if (is_oat_pic >= ERROR_FIRST) { 402 // Error logged by IsOatPic 403 return false; 404 } else if (is_oat_pic == NOT_PIC) { 405 LOG(ERROR) << "patchoat cannot be used on non-PIC oat file: " << input_oat_filename; 406 return false; 407 } 408 409 CHECK(is_oat_pic == PIC); 410 411 std::string output_vdex_filename = 412 ImageHeader::GetVdexLocationFromImageLocation(output_image_filename); 413 std::string output_oat_filename = 414 ImageHeader::GetOatLocationFromImageLocation(output_image_filename); 415 416 return SymlinkFile(input_oat_filename, output_oat_filename) && 417 SymlinkFile(input_vdex_filename, output_vdex_filename); 418} 419 420bool PatchOat::Patch(const std::string& image_location, 421 off_t delta, 422 const std::string& output_image_directory, 423 const std::string& output_image_relocation_directory, 424 InstructionSet isa, 425 TimingLogger* timings) { 426 bool output_image = !output_image_directory.empty(); 427 bool output_image_relocation = !output_image_relocation_directory.empty(); 428 if ((!output_image) && (!output_image_relocation)) { 429 // Nothing to do 430 return true; 431 } 432 if ((output_image_relocation) && (delta == 0)) { 433 LOG(ERROR) << "Cannot output image relocation information when requested relocation delta is 0"; 434 return false; 435 } 436 437 CHECK(Runtime::Current() == nullptr); 438 CHECK(!image_location.empty()) << "image file must have a filename."; 439 440 TimingLogger::ScopedTiming t("Runtime Setup", timings); 441 442 CHECK_NE(isa, InstructionSet::kNone); 443 const char* isa_name = GetInstructionSetString(isa); 444 445 // Set up the runtime 446 RuntimeOptions options; 447 NoopCompilerCallbacks callbacks; 448 options.push_back(std::make_pair("compilercallbacks", &callbacks)); 449 std::string img = "-Ximage:" + image_location; 450 options.push_back(std::make_pair(img.c_str(), nullptr)); 451 options.push_back(std::make_pair("imageinstructionset", reinterpret_cast<const void*>(isa_name))); 452 options.push_back(std::make_pair("-Xno-sig-chain", nullptr)); 453 if (!Runtime::Create(options, false)) { 454 LOG(ERROR) << "Unable to initialize runtime"; 455 return false; 456 } 457 std::unique_ptr<Runtime> runtime(Runtime::Current()); 458 459 // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start, 460 // give it away now and then switch to a more manageable ScopedObjectAccess. 461 Thread::Current()->TransitionFromRunnableToSuspended(kNative); 462 ScopedObjectAccess soa(Thread::Current()); 463 464 std::vector<gc::space::ImageSpace*> spaces = Runtime::Current()->GetHeap()->GetBootImageSpaces(); 465 std::map<gc::space::ImageSpace*, std::unique_ptr<MemMap>> space_to_memmap_map; 466 467 for (size_t i = 0; i < spaces.size(); ++i) { 468 t.NewTiming("Image Patching setup"); 469 gc::space::ImageSpace* space = spaces[i]; 470 std::string input_image_filename = space->GetImageFilename(); 471 std::unique_ptr<File> input_image(OS::OpenFileForReading(input_image_filename.c_str())); 472 if (input_image.get() == nullptr) { 473 LOG(ERROR) << "Unable to open input image file at " << input_image_filename; 474 return false; 475 } 476 477 int64_t image_len = input_image->GetLength(); 478 if (image_len < 0) { 479 LOG(ERROR) << "Error while getting image length"; 480 return false; 481 } 482 ImageHeader image_header; 483 if (sizeof(image_header) != input_image->Read(reinterpret_cast<char*>(&image_header), 484 sizeof(image_header), 0)) { 485 LOG(ERROR) << "Unable to read image header from image file " << input_image->GetPath(); 486 } 487 488 /*bool is_image_pic = */IsImagePic(image_header, input_image->GetPath()); 489 // Nothing special to do right now since the image always needs to get patched. 490 // Perhaps in some far-off future we may have images with relative addresses that are true-PIC. 491 492 // Create the map where we will write the image patches to. 493 std::string error_msg; 494 std::unique_ptr<MemMap> image(MemMap::MapFile(image_len, 495 PROT_READ | PROT_WRITE, 496 MAP_PRIVATE, 497 input_image->Fd(), 498 0, 499 /*low_4gb*/false, 500 input_image->GetPath().c_str(), 501 &error_msg)); 502 if (image.get() == nullptr) { 503 LOG(ERROR) << "Unable to map image file " << input_image->GetPath() << " : " << error_msg; 504 return false; 505 } 506 507 508 space_to_memmap_map.emplace(space, std::move(image)); 509 PatchOat p = PatchOat(isa, 510 space_to_memmap_map.at(space).get(), 511 space->GetLiveBitmap(), 512 space->GetMemMap(), 513 delta, 514 &space_to_memmap_map, 515 timings); 516 517 t.NewTiming("Patching image"); 518 if (!p.PatchImage(i == 0)) { 519 LOG(ERROR) << "Failed to patch image file " << input_image_filename; 520 return false; 521 } 522 523 // Write the patched image spaces. 524 if (output_image) { 525 std::string output_image_filename; 526 if (!GetDalvikCacheFilename(space->GetImageLocation().c_str(), 527 output_image_directory.c_str(), 528 &output_image_filename, 529 &error_msg)) { 530 LOG(ERROR) << "Failed to find relocated image file name: " << error_msg; 531 return false; 532 } 533 534 if (!CreateVdexAndOatSymlinks(input_image_filename, output_image_filename)) 535 return false; 536 537 t.NewTiming("Writing image"); 538 std::unique_ptr<File> output_image_file(CreateOrOpen(output_image_filename.c_str())); 539 if (output_image_file.get() == nullptr) { 540 LOG(ERROR) << "Failed to open output image file at " << output_image_filename; 541 return false; 542 } 543 544 bool success = p.WriteImage(output_image_file.get()); 545 success = FinishFile(output_image_file.get(), success); 546 if (!success) { 547 return false; 548 } 549 } 550 551 if (output_image_relocation) { 552 t.NewTiming("Writing image relocation"); 553 std::string original_image_filename(space->GetImageLocation() + ".rel"); 554 std::string image_relocation_filename = 555 output_image_relocation_directory 556 + (android::base::StartsWith(original_image_filename, "/") ? "" : "/") 557 + original_image_filename.substr(original_image_filename.find_last_of("/")); 558 int64_t input_image_size = input_image->GetLength(); 559 if (input_image_size < 0) { 560 LOG(ERROR) << "Error while getting input image size"; 561 return false; 562 } 563 std::unique_ptr<MemMap> original(MemMap::MapFile(input_image_size, 564 PROT_READ, 565 MAP_PRIVATE, 566 input_image->Fd(), 567 0, 568 /*low_4gb*/false, 569 input_image->GetPath().c_str(), 570 &error_msg)); 571 if (original.get() == nullptr) { 572 LOG(ERROR) << "Unable to map image file " << input_image->GetPath() << " : " << error_msg; 573 return false; 574 } 575 576 const MemMap* relocated = p.image_; 577 578 if (!WriteRelFile(*original, *relocated, image_relocation_filename, &error_msg)) { 579 LOG(ERROR) << "Failed to create image relocation file " << image_relocation_filename 580 << ": " << error_msg; 581 return false; 582 } 583 } 584 } 585 586 if (!kIsDebugBuild && !(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) { 587 // We want to just exit on non-debug builds, not bringing the runtime down 588 // in an orderly fashion. So release the following fields. 589 runtime.release(); 590 } 591 592 return true; 593} 594 595bool PatchOat::Verify(const std::string& image_location, 596 const std::string& output_image_directory, 597 InstructionSet isa, 598 TimingLogger* timings) { 599 if (image_location.empty()) { 600 LOG(ERROR) << "Original image file not provided"; 601 return false; 602 } 603 if (output_image_directory.empty()) { 604 LOG(ERROR) << "Relocated image directory not provided"; 605 return false; 606 } 607 608 TimingLogger::ScopedTiming t("Runtime Setup", timings); 609 610 CHECK_NE(isa, InstructionSet::kNone); 611 const char* isa_name = GetInstructionSetString(isa); 612 613 // Set up the runtime 614 RuntimeOptions options; 615 NoopCompilerCallbacks callbacks; 616 options.push_back(std::make_pair("compilercallbacks", &callbacks)); 617 std::string img = "-Ximage:" + image_location; 618 options.push_back(std::make_pair(img.c_str(), nullptr)); 619 options.push_back(std::make_pair("imageinstructionset", reinterpret_cast<const void*>(isa_name))); 620 options.push_back(std::make_pair("-Xno-sig-chain", nullptr)); 621 if (!Runtime::Create(options, false)) { 622 LOG(ERROR) << "Unable to initialize runtime"; 623 return false; 624 } 625 std::unique_ptr<Runtime> runtime(Runtime::Current()); 626 627 // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start, 628 // give it away now and then switch to a more manageable ScopedObjectAccess. 629 Thread::Current()->TransitionFromRunnableToSuspended(kNative); 630 ScopedObjectAccess soa(Thread::Current()); 631 632 t.NewTiming("Image Verification setup"); 633 std::vector<gc::space::ImageSpace*> spaces = Runtime::Current()->GetHeap()->GetBootImageSpaces(); 634 635 // TODO: Check that no other .rel files exist in the original dir 636 637 bool success = true; 638 std::string image_location_dir = android::base::Dirname(image_location); 639 for (size_t i = 0; i < spaces.size(); ++i) { 640 gc::space::ImageSpace* space = spaces[i]; 641 642 std::string relocated_image_filename; 643 std::string error_msg; 644 if (!GetDalvikCacheFilename(space->GetImageLocation().c_str(), 645 output_image_directory.c_str(), &relocated_image_filename, &error_msg)) { 646 LOG(ERROR) << "Failed to find relocated image file name: " << error_msg; 647 success = false; 648 break; 649 } 650 // location: /system/framework/boot.art 651 // isa: arm64 652 // basename: boot.art 653 // original: /system/framework/arm64/boot.art 654 // relocation: /system/framework/arm64/boot.art.rel 655 std::string original_image_filename = 656 GetSystemImageFilename(space->GetImageLocation().c_str(), isa); 657 658 if (!CheckImageIdenticalToOriginalExceptForRelocation( 659 relocated_image_filename, original_image_filename, &error_msg)) { 660 LOG(ERROR) << error_msg; 661 success = false; 662 break; 663 } 664 665 if (!VerifyVdexAndOatSymlinks(original_image_filename, relocated_image_filename)) { 666 LOG(ERROR) << "Verification of vdex and oat symlinks for " 667 << space->GetImageLocation() << " failed."; 668 success = false; 669 break; 670 } 671 } 672 673 if (!kIsDebugBuild && !(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) { 674 // We want to just exit on non-debug builds, not bringing the runtime down 675 // in an orderly fashion. So release the following fields. 676 runtime.release(); 677 } 678 679 return success; 680} 681 682bool PatchOat::WriteImage(File* out) { 683 TimingLogger::ScopedTiming t("Writing image File", timings_); 684 std::string error_msg; 685 686 // No error checking here, this is best effort. The locking may or may not 687 // succeed and we don't really care either way. 688 ScopedFlock img_flock = LockedFile::DupOf(out->Fd(), out->GetPath(), 689 true /* read_only_mode */, &error_msg); 690 691 CHECK(image_ != nullptr); 692 CHECK(out != nullptr); 693 size_t expect = image_->Size(); 694 if (out->WriteFully(reinterpret_cast<char*>(image_->Begin()), expect) && 695 out->SetLength(expect) == 0) { 696 return true; 697 } else { 698 LOG(ERROR) << "Writing to image file " << out->GetPath() << " failed."; 699 return false; 700 } 701} 702 703bool PatchOat::IsImagePic(const ImageHeader& image_header, const std::string& image_path) { 704 if (!image_header.CompilePic()) { 705 if (kIsDebugBuild) { 706 LOG(INFO) << "image at location " << image_path << " was *not* compiled pic"; 707 } 708 return false; 709 } 710 711 if (kIsDebugBuild) { 712 LOG(INFO) << "image at location " << image_path << " was compiled PIC"; 713 } 714 715 return true; 716} 717 718PatchOat::MaybePic PatchOat::IsOatPic(const ElfFile* oat_in) { 719 if (oat_in == nullptr) { 720 LOG(ERROR) << "No ELF input oat fie available"; 721 return ERROR_OAT_FILE; 722 } 723 724 const std::string& file_path = oat_in->GetFilePath(); 725 726 const OatHeader* oat_header = GetOatHeader(oat_in); 727 if (oat_header == nullptr) { 728 LOG(ERROR) << "Failed to find oat header in oat file " << file_path; 729 return ERROR_OAT_FILE; 730 } 731 732 if (!oat_header->IsValid()) { 733 LOG(ERROR) << "Elf file " << file_path << " has an invalid oat header"; 734 return ERROR_OAT_FILE; 735 } 736 737 bool is_pic = oat_header->IsPic(); 738 if (kIsDebugBuild) { 739 LOG(INFO) << "Oat file at " << file_path << " is " << (is_pic ? "PIC" : "not pic"); 740 } 741 742 return is_pic ? PIC : NOT_PIC; 743} 744 745class PatchOat::PatchOatArtFieldVisitor : public ArtFieldVisitor { 746 public: 747 explicit PatchOatArtFieldVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {} 748 749 void Visit(ArtField* field) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { 750 ArtField* const dest = patch_oat_->RelocatedCopyOf(field); 751 dest->SetDeclaringClass( 752 patch_oat_->RelocatedAddressOfPointer(field->GetDeclaringClass().Ptr())); 753 } 754 755 private: 756 PatchOat* const patch_oat_; 757}; 758 759void PatchOat::PatchArtFields(const ImageHeader* image_header) { 760 PatchOatArtFieldVisitor visitor(this); 761 image_header->VisitPackedArtFields(&visitor, heap_->Begin()); 762} 763 764class PatchOat::PatchOatArtMethodVisitor : public ArtMethodVisitor { 765 public: 766 explicit PatchOatArtMethodVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {} 767 768 void Visit(ArtMethod* method) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { 769 ArtMethod* const dest = patch_oat_->RelocatedCopyOf(method); 770 patch_oat_->FixupMethod(method, dest); 771 } 772 773 private: 774 PatchOat* const patch_oat_; 775}; 776 777void PatchOat::PatchArtMethods(const ImageHeader* image_header) { 778 const PointerSize pointer_size = InstructionSetPointerSize(isa_); 779 PatchOatArtMethodVisitor visitor(this); 780 image_header->VisitPackedArtMethods(&visitor, heap_->Begin(), pointer_size); 781} 782 783void PatchOat::PatchImTables(const ImageHeader* image_header) { 784 const PointerSize pointer_size = InstructionSetPointerSize(isa_); 785 // We can safely walk target image since the conflict tables are independent. 786 image_header->VisitPackedImTables( 787 [this](ArtMethod* method) { 788 return RelocatedAddressOfPointer(method); 789 }, 790 image_->Begin(), 791 pointer_size); 792} 793 794void PatchOat::PatchImtConflictTables(const ImageHeader* image_header) { 795 const PointerSize pointer_size = InstructionSetPointerSize(isa_); 796 // We can safely walk target image since the conflict tables are independent. 797 image_header->VisitPackedImtConflictTables( 798 [this](ArtMethod* method) { 799 return RelocatedAddressOfPointer(method); 800 }, 801 image_->Begin(), 802 pointer_size); 803} 804 805class PatchOat::FixupRootVisitor : public RootVisitor { 806 public: 807 explicit FixupRootVisitor(const PatchOat* patch_oat) : patch_oat_(patch_oat) { 808 } 809 810 void VisitRoots(mirror::Object*** roots, size_t count, const RootInfo& info ATTRIBUTE_UNUSED) 811 OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { 812 for (size_t i = 0; i < count; ++i) { 813 *roots[i] = patch_oat_->RelocatedAddressOfPointer(*roots[i]); 814 } 815 } 816 817 void VisitRoots(mirror::CompressedReference<mirror::Object>** roots, size_t count, 818 const RootInfo& info ATTRIBUTE_UNUSED) 819 OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { 820 for (size_t i = 0; i < count; ++i) { 821 roots[i]->Assign(patch_oat_->RelocatedAddressOfPointer(roots[i]->AsMirrorPtr())); 822 } 823 } 824 825 private: 826 const PatchOat* const patch_oat_; 827}; 828 829void PatchOat::PatchInternedStrings(const ImageHeader* image_header) { 830 const auto& section = image_header->GetInternedStringsSection(); 831 if (section.Size() == 0) { 832 return; 833 } 834 InternTable temp_table; 835 // Note that we require that ReadFromMemory does not make an internal copy of the elements. 836 // This also relies on visit roots not doing any verification which could fail after we update 837 // the roots to be the image addresses. 838 temp_table.AddTableFromMemory(image_->Begin() + section.Offset()); 839 FixupRootVisitor visitor(this); 840 temp_table.VisitRoots(&visitor, kVisitRootFlagAllRoots); 841} 842 843void PatchOat::PatchClassTable(const ImageHeader* image_header) { 844 const auto& section = image_header->GetClassTableSection(); 845 if (section.Size() == 0) { 846 return; 847 } 848 // Note that we require that ReadFromMemory does not make an internal copy of the elements. 849 // This also relies on visit roots not doing any verification which could fail after we update 850 // the roots to be the image addresses. 851 WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); 852 ClassTable temp_table; 853 temp_table.ReadFromMemory(image_->Begin() + section.Offset()); 854 FixupRootVisitor visitor(this); 855 temp_table.VisitRoots(UnbufferedRootVisitor(&visitor, RootInfo(kRootUnknown))); 856} 857 858 859class PatchOat::RelocatedPointerVisitor { 860 public: 861 explicit RelocatedPointerVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {} 862 863 template <typename T> 864 T* operator()(T* ptr, void** dest_addr ATTRIBUTE_UNUSED = 0) const { 865 return patch_oat_->RelocatedAddressOfPointer(ptr); 866 } 867 868 private: 869 PatchOat* const patch_oat_; 870}; 871 872void PatchOat::PatchDexFileArrays(mirror::ObjectArray<mirror::Object>* img_roots) { 873 auto* dex_caches = down_cast<mirror::ObjectArray<mirror::DexCache>*>( 874 img_roots->Get(ImageHeader::kDexCaches)); 875 const PointerSize pointer_size = InstructionSetPointerSize(isa_); 876 for (size_t i = 0, count = dex_caches->GetLength(); i < count; ++i) { 877 auto* orig_dex_cache = dex_caches->GetWithoutChecks(i); 878 auto* copy_dex_cache = RelocatedCopyOf(orig_dex_cache); 879 // Though the DexCache array fields are usually treated as native pointers, we set the full 880 // 64-bit values here, clearing the top 32 bits for 32-bit targets. The zero-extension is 881 // done by casting to the unsigned type uintptr_t before casting to int64_t, i.e. 882 // static_cast<int64_t>(reinterpret_cast<uintptr_t>(image_begin_ + offset))). 883 mirror::StringDexCacheType* orig_strings = orig_dex_cache->GetStrings(); 884 mirror::StringDexCacheType* relocated_strings = RelocatedAddressOfPointer(orig_strings); 885 copy_dex_cache->SetField64<false>( 886 mirror::DexCache::StringsOffset(), 887 static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_strings))); 888 if (orig_strings != nullptr) { 889 orig_dex_cache->FixupStrings(RelocatedCopyOf(orig_strings), RelocatedPointerVisitor(this)); 890 } 891 mirror::TypeDexCacheType* orig_types = orig_dex_cache->GetResolvedTypes(); 892 mirror::TypeDexCacheType* relocated_types = RelocatedAddressOfPointer(orig_types); 893 copy_dex_cache->SetField64<false>( 894 mirror::DexCache::ResolvedTypesOffset(), 895 static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_types))); 896 if (orig_types != nullptr) { 897 orig_dex_cache->FixupResolvedTypes(RelocatedCopyOf(orig_types), 898 RelocatedPointerVisitor(this)); 899 } 900 mirror::MethodDexCacheType* orig_methods = orig_dex_cache->GetResolvedMethods(); 901 mirror::MethodDexCacheType* relocated_methods = RelocatedAddressOfPointer(orig_methods); 902 copy_dex_cache->SetField64<false>( 903 mirror::DexCache::ResolvedMethodsOffset(), 904 static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_methods))); 905 if (orig_methods != nullptr) { 906 mirror::MethodDexCacheType* copy_methods = RelocatedCopyOf(orig_methods); 907 for (size_t j = 0, num = orig_dex_cache->NumResolvedMethods(); j != num; ++j) { 908 mirror::MethodDexCachePair orig = 909 mirror::DexCache::GetNativePairPtrSize(orig_methods, j, pointer_size); 910 mirror::MethodDexCachePair copy(RelocatedAddressOfPointer(orig.object), orig.index); 911 mirror::DexCache::SetNativePairPtrSize(copy_methods, j, copy, pointer_size); 912 } 913 } 914 mirror::FieldDexCacheType* orig_fields = orig_dex_cache->GetResolvedFields(); 915 mirror::FieldDexCacheType* relocated_fields = RelocatedAddressOfPointer(orig_fields); 916 copy_dex_cache->SetField64<false>( 917 mirror::DexCache::ResolvedFieldsOffset(), 918 static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_fields))); 919 if (orig_fields != nullptr) { 920 mirror::FieldDexCacheType* copy_fields = RelocatedCopyOf(orig_fields); 921 for (size_t j = 0, num = orig_dex_cache->NumResolvedFields(); j != num; ++j) { 922 mirror::FieldDexCachePair orig = 923 mirror::DexCache::GetNativePairPtrSize(orig_fields, j, pointer_size); 924 mirror::FieldDexCachePair copy(RelocatedAddressOfPointer(orig.object), orig.index); 925 mirror::DexCache::SetNativePairPtrSize(copy_fields, j, copy, pointer_size); 926 } 927 } 928 mirror::MethodTypeDexCacheType* orig_method_types = orig_dex_cache->GetResolvedMethodTypes(); 929 mirror::MethodTypeDexCacheType* relocated_method_types = 930 RelocatedAddressOfPointer(orig_method_types); 931 copy_dex_cache->SetField64<false>( 932 mirror::DexCache::ResolvedMethodTypesOffset(), 933 static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_method_types))); 934 if (orig_method_types != nullptr) { 935 orig_dex_cache->FixupResolvedMethodTypes(RelocatedCopyOf(orig_method_types), 936 RelocatedPointerVisitor(this)); 937 } 938 939 GcRoot<mirror::CallSite>* orig_call_sites = orig_dex_cache->GetResolvedCallSites(); 940 GcRoot<mirror::CallSite>* relocated_call_sites = RelocatedAddressOfPointer(orig_call_sites); 941 copy_dex_cache->SetField64<false>( 942 mirror::DexCache::ResolvedCallSitesOffset(), 943 static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_call_sites))); 944 if (orig_call_sites != nullptr) { 945 orig_dex_cache->FixupResolvedCallSites(RelocatedCopyOf(orig_call_sites), 946 RelocatedPointerVisitor(this)); 947 } 948 } 949} 950 951bool PatchOat::PatchImage(bool primary_image) { 952 ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin()); 953 CHECK_GT(image_->Size(), sizeof(ImageHeader)); 954 // These are the roots from the original file. 955 auto* img_roots = image_header->GetImageRoots(); 956 image_header->RelocateImage(delta_); 957 958 PatchArtFields(image_header); 959 PatchArtMethods(image_header); 960 PatchImTables(image_header); 961 PatchImtConflictTables(image_header); 962 PatchInternedStrings(image_header); 963 PatchClassTable(image_header); 964 // Patch dex file int/long arrays which point to ArtFields. 965 PatchDexFileArrays(img_roots); 966 967 if (primary_image) { 968 VisitObject(img_roots); 969 } 970 971 if (!image_header->IsValid()) { 972 LOG(ERROR) << "relocation renders image header invalid"; 973 return false; 974 } 975 976 { 977 TimingLogger::ScopedTiming t("Walk Bitmap", timings_); 978 // Walk the bitmap. 979 WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); 980 auto visitor = [&](mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) { 981 VisitObject(obj); 982 }; 983 bitmap_->Walk(visitor); 984 } 985 return true; 986} 987 988 989void PatchOat::PatchVisitor::operator() (ObjPtr<mirror::Object> obj, 990 MemberOffset off, 991 bool is_static_unused ATTRIBUTE_UNUSED) const { 992 mirror::Object* referent = obj->GetFieldObject<mirror::Object, kVerifyNone>(off); 993 mirror::Object* moved_object = patcher_->RelocatedAddressOfPointer(referent); 994 copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(off, moved_object); 995} 996 997void PatchOat::PatchVisitor::operator() (ObjPtr<mirror::Class> cls ATTRIBUTE_UNUSED, 998 ObjPtr<mirror::Reference> ref) const { 999 MemberOffset off = mirror::Reference::ReferentOffset(); 1000 mirror::Object* referent = ref->GetReferent(); 1001 DCHECK(referent == nullptr || 1002 Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(referent)) << referent; 1003 mirror::Object* moved_object = patcher_->RelocatedAddressOfPointer(referent); 1004 copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(off, moved_object); 1005} 1006 1007// Called by PatchImage. 1008void PatchOat::VisitObject(mirror::Object* object) { 1009 mirror::Object* copy = RelocatedCopyOf(object); 1010 CHECK(copy != nullptr); 1011 if (kUseBakerReadBarrier) { 1012 object->AssertReadBarrierState(); 1013 } 1014 PatchOat::PatchVisitor visitor(this, copy); 1015 object->VisitReferences<kVerifyNone>(visitor, visitor); 1016 if (object->IsClass<kVerifyNone>()) { 1017 const PointerSize pointer_size = InstructionSetPointerSize(isa_); 1018 mirror::Class* klass = object->AsClass(); 1019 mirror::Class* copy_klass = down_cast<mirror::Class*>(copy); 1020 RelocatedPointerVisitor native_visitor(this); 1021 klass->FixupNativePointers(copy_klass, pointer_size, native_visitor); 1022 auto* vtable = klass->GetVTable(); 1023 if (vtable != nullptr) { 1024 vtable->Fixup(RelocatedCopyOfFollowImages(vtable), pointer_size, native_visitor); 1025 } 1026 mirror::IfTable* iftable = klass->GetIfTable(); 1027 for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) { 1028 if (iftable->GetMethodArrayCount(i) > 0) { 1029 auto* method_array = iftable->GetMethodArray(i); 1030 CHECK(method_array != nullptr); 1031 method_array->Fixup(RelocatedCopyOfFollowImages(method_array), 1032 pointer_size, 1033 native_visitor); 1034 } 1035 } 1036 } else if (object->GetClass() == mirror::Method::StaticClass() || 1037 object->GetClass() == mirror::Constructor::StaticClass()) { 1038 // Need to go update the ArtMethod. 1039 auto* dest = down_cast<mirror::Executable*>(copy); 1040 auto* src = down_cast<mirror::Executable*>(object); 1041 dest->SetArtMethod(RelocatedAddressOfPointer(src->GetArtMethod())); 1042 } 1043} 1044 1045void PatchOat::FixupMethod(ArtMethod* object, ArtMethod* copy) { 1046 const PointerSize pointer_size = InstructionSetPointerSize(isa_); 1047 copy->CopyFrom(object, pointer_size); 1048 // Just update the entry points if it looks like we should. 1049 // TODO: sanity check all the pointers' values 1050 copy->SetDeclaringClass(RelocatedAddressOfPointer(object->GetDeclaringClass())); 1051 copy->SetEntryPointFromQuickCompiledCodePtrSize(RelocatedAddressOfPointer( 1052 object->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size)), pointer_size); 1053 // No special handling for IMT conflict table since all pointers are moved by the same offset. 1054 copy->SetDataPtrSize(RelocatedAddressOfPointer( 1055 object->GetDataPtrSize(pointer_size)), pointer_size); 1056} 1057 1058static int orig_argc; 1059static char** orig_argv; 1060 1061static std::string CommandLine() { 1062 std::vector<std::string> command; 1063 for (int i = 0; i < orig_argc; ++i) { 1064 command.push_back(orig_argv[i]); 1065 } 1066 return android::base::Join(command, ' '); 1067} 1068 1069static void UsageErrorV(const char* fmt, va_list ap) { 1070 std::string error; 1071 android::base::StringAppendV(&error, fmt, ap); 1072 LOG(ERROR) << error; 1073} 1074 1075static void UsageError(const char* fmt, ...) { 1076 va_list ap; 1077 va_start(ap, fmt); 1078 UsageErrorV(fmt, ap); 1079 va_end(ap); 1080} 1081 1082NO_RETURN static void Usage(const char *fmt, ...) { 1083 va_list ap; 1084 va_start(ap, fmt); 1085 UsageErrorV(fmt, ap); 1086 va_end(ap); 1087 1088 UsageError("Command: %s", CommandLine().c_str()); 1089 UsageError("Usage: patchoat [options]..."); 1090 UsageError(""); 1091 UsageError(" --instruction-set=<isa>: Specifies the instruction set the patched code is"); 1092 UsageError(" compiled for (required)."); 1093 UsageError(""); 1094 UsageError(" --input-image-location=<file.art>: Specifies the 'location' of the image file to"); 1095 UsageError(" be patched."); 1096 UsageError(""); 1097 UsageError(" --output-image-directory=<dir>: Specifies the directory to write the patched"); 1098 UsageError(" image file(s) to."); 1099 UsageError(""); 1100 UsageError(" --output-image-relocation-directory=<dir>: Specifies the directory to write"); 1101 UsageError(" the image relocation information to."); 1102 UsageError(""); 1103 UsageError(" --base-offset-delta=<delta>: Specify the amount to change the old base-offset by."); 1104 UsageError(" This value may be negative."); 1105 UsageError(""); 1106 UsageError(" --verify: Verify an existing patched file instead of creating one."); 1107 UsageError(""); 1108 UsageError(" --dump-timings: dump out patch timing information"); 1109 UsageError(""); 1110 UsageError(" --no-dump-timings: do not dump out patch timing information"); 1111 UsageError(""); 1112 1113 exit(EXIT_FAILURE); 1114} 1115 1116static int patchoat_patch_image(TimingLogger& timings, 1117 InstructionSet isa, 1118 const std::string& input_image_location, 1119 const std::string& output_image_directory, 1120 const std::string& output_image_relocation_directory, 1121 off_t base_delta, 1122 bool base_delta_set, 1123 bool debug) { 1124 CHECK(!input_image_location.empty()); 1125 if ((output_image_directory.empty()) && (output_image_relocation_directory.empty())) { 1126 Usage("Image patching requires --output-image-directory or --output-image-relocation-directory"); 1127 } 1128 1129 if (!base_delta_set) { 1130 Usage("Must supply a desired new offset or delta."); 1131 } 1132 1133 if (!IsAligned<kPageSize>(base_delta)) { 1134 Usage("Base offset/delta must be aligned to a pagesize (0x%08x) boundary.", kPageSize); 1135 } 1136 1137 if (debug) { 1138 LOG(INFO) << "moving offset by " << base_delta 1139 << " (0x" << std::hex << base_delta << ") bytes or " 1140 << std::dec << (base_delta/kPageSize) << " pages."; 1141 } 1142 1143 TimingLogger::ScopedTiming pt("patch image and oat", &timings); 1144 1145 bool ret = 1146 PatchOat::Patch( 1147 input_image_location, 1148 base_delta, 1149 output_image_directory, 1150 output_image_relocation_directory, 1151 isa, 1152 &timings); 1153 1154 if (kIsDebugBuild) { 1155 LOG(INFO) << "Exiting with return ... " << ret; 1156 } 1157 return ret ? EXIT_SUCCESS : EXIT_FAILURE; 1158} 1159 1160static int patchoat_verify_image(TimingLogger& timings, 1161 InstructionSet isa, 1162 const std::string& input_image_location, 1163 const std::string& output_image_directory) { 1164 CHECK(!input_image_location.empty()); 1165 TimingLogger::ScopedTiming pt("verify image and oat", &timings); 1166 1167 bool ret = 1168 PatchOat::Verify( 1169 input_image_location, 1170 output_image_directory, 1171 isa, 1172 &timings); 1173 1174 if (kIsDebugBuild) { 1175 LOG(INFO) << "Exiting with return ... " << ret; 1176 } 1177 return ret ? EXIT_SUCCESS : EXIT_FAILURE; 1178} 1179 1180static int patchoat(int argc, char **argv) { 1181 Locks::Init(); 1182 InitLogging(argv, Runtime::Abort); 1183 MemMap::Init(); 1184 const bool debug = kIsDebugBuild; 1185 orig_argc = argc; 1186 orig_argv = argv; 1187 TimingLogger timings("patcher", false, false); 1188 1189 // Skip over the command name. 1190 argv++; 1191 argc--; 1192 1193 if (argc == 0) { 1194 Usage("No arguments specified"); 1195 } 1196 1197 timings.StartTiming("Patchoat"); 1198 1199 // cmd line args 1200 bool isa_set = false; 1201 InstructionSet isa = InstructionSet::kNone; 1202 std::string input_image_location; 1203 std::string output_image_directory; 1204 std::string output_image_relocation_directory; 1205 off_t base_delta = 0; 1206 bool base_delta_set = false; 1207 bool dump_timings = kIsDebugBuild; 1208 bool verify = false; 1209 1210 for (int i = 0; i < argc; ++i) { 1211 const StringPiece option(argv[i]); 1212 const bool log_options = false; 1213 if (log_options) { 1214 LOG(INFO) << "patchoat: option[" << i << "]=" << argv[i]; 1215 } 1216 if (option.starts_with("--instruction-set=")) { 1217 isa_set = true; 1218 const char* isa_str = option.substr(strlen("--instruction-set=")).data(); 1219 isa = GetInstructionSetFromString(isa_str); 1220 if (isa == InstructionSet::kNone) { 1221 Usage("Unknown or invalid instruction set %s", isa_str); 1222 } 1223 } else if (option.starts_with("--input-image-location=")) { 1224 input_image_location = option.substr(strlen("--input-image-location=")).data(); 1225 } else if (option.starts_with("--output-image-directory=")) { 1226 output_image_directory = option.substr(strlen("--output-image-directory=")).data(); 1227 } else if (option.starts_with("--output-image-relocation-directory=")) { 1228 output_image_relocation_directory = 1229 option.substr(strlen("--output-image-relocation-directory=")).data(); 1230 } else if (option.starts_with("--base-offset-delta=")) { 1231 const char* base_delta_str = option.substr(strlen("--base-offset-delta=")).data(); 1232 base_delta_set = true; 1233 if (!ParseInt(base_delta_str, &base_delta)) { 1234 Usage("Failed to parse --base-offset-delta argument '%s' as an off_t", base_delta_str); 1235 } 1236 } else if (option == "--dump-timings") { 1237 dump_timings = true; 1238 } else if (option == "--no-dump-timings") { 1239 dump_timings = false; 1240 } else if (option == "--verify") { 1241 verify = true; 1242 } else { 1243 Usage("Unknown argument %s", option.data()); 1244 } 1245 } 1246 1247 // The instruction set is mandatory. This simplifies things... 1248 if (!isa_set) { 1249 Usage("Instruction set must be set."); 1250 } 1251 1252 int ret; 1253 if (verify) { 1254 ret = patchoat_verify_image(timings, 1255 isa, 1256 input_image_location, 1257 output_image_directory); 1258 } else { 1259 ret = patchoat_patch_image(timings, 1260 isa, 1261 input_image_location, 1262 output_image_directory, 1263 output_image_relocation_directory, 1264 base_delta, 1265 base_delta_set, 1266 debug); 1267 } 1268 1269 timings.EndTiming(); 1270 if (dump_timings) { 1271 LOG(INFO) << Dumpable<TimingLogger>(timings); 1272 } 1273 1274 return ret; 1275} 1276 1277} // namespace art 1278 1279int main(int argc, char **argv) { 1280 return art::patchoat(argc, argv); 1281} 1282