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