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