patchoat.cc revision b348b3b28469d6afe720a202d1a8d23e7345c4ff
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
360bool PatchOat::Patch(const std::string& image_location,
361                     off_t delta,
362                     const std::string& output_image_directory,
363                     const std::string& output_image_relocation_directory,
364                     InstructionSet isa,
365                     TimingLogger* timings) {
366  bool output_image = !output_image_directory.empty();
367  bool output_image_relocation = !output_image_relocation_directory.empty();
368  if ((!output_image) && (!output_image_relocation)) {
369    // Nothing to do
370    return true;
371  }
372  if ((output_image_relocation) && (delta == 0)) {
373    LOG(ERROR) << "Cannot output image relocation information when requested relocation delta is 0";
374    return false;
375  }
376
377  CHECK(Runtime::Current() == nullptr);
378  CHECK(!image_location.empty()) << "image file must have a filename.";
379
380  TimingLogger::ScopedTiming t("Runtime Setup", timings);
381
382  CHECK_NE(isa, InstructionSet::kNone);
383  const char* isa_name = GetInstructionSetString(isa);
384
385  // Set up the runtime
386  RuntimeOptions options;
387  NoopCompilerCallbacks callbacks;
388  options.push_back(std::make_pair("compilercallbacks", &callbacks));
389  std::string img = "-Ximage:" + image_location;
390  options.push_back(std::make_pair(img.c_str(), nullptr));
391  options.push_back(std::make_pair("imageinstructionset", reinterpret_cast<const void*>(isa_name)));
392  options.push_back(std::make_pair("-Xno-sig-chain", nullptr));
393  if (!Runtime::Create(options, false)) {
394    LOG(ERROR) << "Unable to initialize runtime";
395    return false;
396  }
397  std::unique_ptr<Runtime> runtime(Runtime::Current());
398
399  // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
400  // give it away now and then switch to a more manageable ScopedObjectAccess.
401  Thread::Current()->TransitionFromRunnableToSuspended(kNative);
402  ScopedObjectAccess soa(Thread::Current());
403
404  t.NewTiming("Image Patching setup");
405  std::vector<gc::space::ImageSpace*> spaces = Runtime::Current()->GetHeap()->GetBootImageSpaces();
406  std::map<gc::space::ImageSpace*, std::unique_ptr<File>> space_to_file_map;
407  std::map<gc::space::ImageSpace*, std::unique_ptr<MemMap>> space_to_memmap_map;
408  std::map<gc::space::ImageSpace*, PatchOat> space_to_patchoat_map;
409
410  for (size_t i = 0; i < spaces.size(); ++i) {
411    gc::space::ImageSpace* space = spaces[i];
412    std::string input_image_filename = space->GetImageFilename();
413    std::unique_ptr<File> input_image(OS::OpenFileForReading(input_image_filename.c_str()));
414    if (input_image.get() == nullptr) {
415      LOG(ERROR) << "Unable to open input image file at " << input_image_filename;
416      return false;
417    }
418
419    int64_t image_len = input_image->GetLength();
420    if (image_len < 0) {
421      LOG(ERROR) << "Error while getting image length";
422      return false;
423    }
424    ImageHeader image_header;
425    if (sizeof(image_header) != input_image->Read(reinterpret_cast<char*>(&image_header),
426                                                  sizeof(image_header), 0)) {
427      LOG(ERROR) << "Unable to read image header from image file " << input_image->GetPath();
428    }
429
430    /*bool is_image_pic = */IsImagePic(image_header, input_image->GetPath());
431    // Nothing special to do right now since the image always needs to get patched.
432    // Perhaps in some far-off future we may have images with relative addresses that are true-PIC.
433
434    // Create the map where we will write the image patches to.
435    std::string error_msg;
436    std::unique_ptr<MemMap> image(MemMap::MapFile(image_len,
437                                                  PROT_READ | PROT_WRITE,
438                                                  MAP_PRIVATE,
439                                                  input_image->Fd(),
440                                                  0,
441                                                  /*low_4gb*/false,
442                                                  input_image->GetPath().c_str(),
443                                                  &error_msg));
444    if (image.get() == nullptr) {
445      LOG(ERROR) << "Unable to map image file " << input_image->GetPath() << " : " << error_msg;
446      return false;
447    }
448    space_to_file_map.emplace(space, std::move(input_image));
449    space_to_memmap_map.emplace(space, std::move(image));
450  }
451
452  // Symlink PIC oat and vdex files and patch the image spaces in memory.
453  for (size_t i = 0; i < spaces.size(); ++i) {
454    gc::space::ImageSpace* space = spaces[i];
455    std::string input_image_filename = space->GetImageFilename();
456    std::string input_vdex_filename =
457        ImageHeader::GetVdexLocationFromImageLocation(input_image_filename);
458    std::string input_oat_filename =
459        ImageHeader::GetOatLocationFromImageLocation(input_image_filename);
460    std::unique_ptr<File> input_oat_file(OS::OpenFileForReading(input_oat_filename.c_str()));
461    if (input_oat_file.get() == nullptr) {
462      LOG(ERROR) << "Unable to open input oat file at " << input_oat_filename;
463      return false;
464    }
465    std::string error_msg;
466    std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat_file.get(),
467                                               PROT_READ | PROT_WRITE, MAP_PRIVATE, &error_msg));
468    if (elf.get() == nullptr) {
469      LOG(ERROR) << "Unable to open oat file " << input_oat_file->GetPath() << " : " << error_msg;
470      return false;
471    }
472
473    if (output_image) {
474      MaybePic is_oat_pic = IsOatPic(elf.get());
475      if (is_oat_pic >= ERROR_FIRST) {
476        // Error logged by IsOatPic
477        return false;
478      } else if (is_oat_pic == NOT_PIC) {
479        LOG(ERROR) << "patchoat cannot be used on non-PIC oat file: " << input_oat_file->GetPath();
480        return false;
481      } else {
482        CHECK(is_oat_pic == PIC);
483
484        // Create a symlink.
485        std::string converted_image_filename = space->GetImageLocation();
486        std::replace(
487            converted_image_filename.begin() + 1, converted_image_filename.end(), '/', '@');
488        std::string output_image_filename = output_image_directory +
489            (android::base::StartsWith(converted_image_filename, "/") ? "" : "/") +
490            converted_image_filename;
491        std::string output_vdex_filename =
492            ImageHeader::GetVdexLocationFromImageLocation(output_image_filename);
493        std::string output_oat_filename =
494            ImageHeader::GetOatLocationFromImageLocation(output_image_filename);
495
496        if (!ReplaceOatFileWithSymlink(input_oat_file->GetPath(),
497                                       output_oat_filename) ||
498            !SymlinkFile(input_vdex_filename, output_vdex_filename)) {
499          // Errors already logged by above call.
500          return false;
501        }
502      }
503    }
504
505    PatchOat& p = space_to_patchoat_map.emplace(space,
506                                                PatchOat(
507                                                    isa,
508                                                    space_to_memmap_map.find(space)->second.get(),
509                                                    space->GetLiveBitmap(),
510                                                    space->GetMemMap(),
511                                                    delta,
512                                                    &space_to_memmap_map,
513                                                    timings)).first->second;
514
515    t.NewTiming("Patching image");
516    if (!p.PatchImage(i == 0)) {
517      LOG(ERROR) << "Failed to patch image file " << input_image_filename;
518      return false;
519    }
520  }
521
522  if (output_image) {
523    // Write the patched image spaces.
524    for (size_t i = 0; i < spaces.size(); ++i) {
525      gc::space::ImageSpace* space = spaces[i];
526
527      t.NewTiming("Writing image");
528      std::string converted_image_filename = space->GetImageLocation();
529      std::replace(converted_image_filename.begin() + 1, converted_image_filename.end(), '/', '@');
530      std::string output_image_filename = output_image_directory +
531          (android::base::StartsWith(converted_image_filename, "/") ? "" : "/") +
532          converted_image_filename;
533      std::unique_ptr<File> output_image_file(CreateOrOpen(output_image_filename.c_str()));
534      if (output_image_file.get() == nullptr) {
535        LOG(ERROR) << "Failed to open output image file at " << output_image_filename;
536        return false;
537      }
538
539      PatchOat& p = space_to_patchoat_map.find(space)->second;
540
541      bool success = p.WriteImage(output_image_file.get());
542      success = FinishFile(output_image_file.get(), success);
543      if (!success) {
544        return false;
545      }
546    }
547  }
548
549  if (output_image_relocation) {
550    // Write the image relocation information for each space.
551    for (size_t i = 0; i < spaces.size(); ++i) {
552      gc::space::ImageSpace* space = spaces[i];
553
554      t.NewTiming("Writing image relocation");
555      std::string original_image_filename(space->GetImageLocation() + ".rel");
556      std::string image_relocation_filename =
557          output_image_relocation_directory
558              + (android::base::StartsWith(original_image_filename, "/") ? "" : "/")
559              + original_image_filename.substr(original_image_filename.find_last_of("/"));
560      File& input_image = *space_to_file_map.find(space)->second;
561      int64_t input_image_size = input_image.GetLength();
562      if (input_image_size < 0) {
563        LOG(ERROR) << "Error while getting input image size";
564        return false;
565      }
566      std::string error_msg;
567      std::unique_ptr<MemMap> original(MemMap::MapFile(input_image_size,
568                                                       PROT_READ,
569                                                       MAP_PRIVATE,
570                                                       input_image.Fd(),
571                                                       0,
572                                                       /*low_4gb*/false,
573                                                       input_image.GetPath().c_str(),
574                                                       &error_msg));
575      if (original.get() == nullptr) {
576        LOG(ERROR) << "Unable to map image file " << input_image.GetPath() << " : " << error_msg;
577        return false;
578      }
579
580      PatchOat& p = space_to_patchoat_map.find(space)->second;
581      const MemMap* relocated = p.image_;
582
583      if (!WriteRelFile(*original, *relocated, image_relocation_filename, &error_msg)) {
584        LOG(ERROR) << "Failed to create image relocation file " << image_relocation_filename
585            << ": " << error_msg;
586        return false;
587      }
588    }
589  }
590
591  if (!kIsDebugBuild && !(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) {
592    // We want to just exit on non-debug builds, not bringing the runtime down
593    // in an orderly fashion. So release the following fields.
594    runtime.release();
595  }
596
597  return true;
598}
599
600bool PatchOat::Verify(const std::string& image_location,
601                      const std::string& output_image_directory,
602                      InstructionSet isa,
603                      TimingLogger* timings) {
604  if (image_location.empty()) {
605    LOG(ERROR) << "Original image file not provided";
606    return false;
607  }
608  if (output_image_directory.empty()) {
609    LOG(ERROR) << "Relocated image directory not provided";
610    return false;
611  }
612
613  TimingLogger::ScopedTiming t("Runtime Setup", timings);
614
615  CHECK_NE(isa, InstructionSet::kNone);
616  const char* isa_name = GetInstructionSetString(isa);
617
618  // Set up the runtime
619  RuntimeOptions options;
620  NoopCompilerCallbacks callbacks;
621  options.push_back(std::make_pair("compilercallbacks", &callbacks));
622  std::string img = "-Ximage:" + image_location;
623  options.push_back(std::make_pair(img.c_str(), nullptr));
624  options.push_back(std::make_pair("imageinstructionset", reinterpret_cast<const void*>(isa_name)));
625  options.push_back(std::make_pair("-Xno-sig-chain", nullptr));
626  if (!Runtime::Create(options, false)) {
627    LOG(ERROR) << "Unable to initialize runtime";
628    return false;
629  }
630  std::unique_ptr<Runtime> runtime(Runtime::Current());
631
632  // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
633  // give it away now and then switch to a more manageable ScopedObjectAccess.
634  Thread::Current()->TransitionFromRunnableToSuspended(kNative);
635  ScopedObjectAccess soa(Thread::Current());
636
637  t.NewTiming("Image Verification setup");
638  std::vector<gc::space::ImageSpace*> spaces = Runtime::Current()->GetHeap()->GetBootImageSpaces();
639
640  // TODO: Check that no other .rel files exist in the original dir
641
642  bool success = true;
643  std::string image_location_dir = android::base::Dirname(image_location);
644  for (size_t i = 0; i < spaces.size(); ++i) {
645    gc::space::ImageSpace* space = spaces[i];
646    std::string image_filename = space->GetImageLocation();
647
648    std::string relocated_image_filename;
649    std::string error_msg;
650    if (!GetDalvikCacheFilename(image_filename.c_str(),
651            output_image_directory.c_str(), &relocated_image_filename, &error_msg)) {
652      LOG(ERROR) << "Failed to find relocated image file name: " << error_msg;
653      success = false;
654      break;
655    }
656    // location:     /system/framework/boot.art
657    // isa:          arm64
658    // basename:     boot.art
659    // original:     /system/framework/arm64/boot.art
660    // relocation:   /system/framework/arm64/boot.art.rel
661    std::string original_image_filename = GetSystemImageFilename(image_filename.c_str(), isa);
662
663    if (!CheckImageIdenticalToOriginalExceptForRelocation(
664            relocated_image_filename, original_image_filename, &error_msg)) {
665      LOG(ERROR) << error_msg;
666      success = false;
667      break;
668    }
669  }
670
671  if (!kIsDebugBuild && !(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) {
672    // We want to just exit on non-debug builds, not bringing the runtime down
673    // in an orderly fashion. So release the following fields.
674    runtime.release();
675  }
676
677  return success;
678}
679
680bool PatchOat::WriteImage(File* out) {
681  TimingLogger::ScopedTiming t("Writing image File", timings_);
682  std::string error_msg;
683
684  // No error checking here, this is best effort. The locking may or may not
685  // succeed and we don't really care either way.
686  ScopedFlock img_flock = LockedFile::DupOf(out->Fd(), out->GetPath(),
687                                            true /* read_only_mode */, &error_msg);
688
689  CHECK(image_ != nullptr);
690  CHECK(out != nullptr);
691  size_t expect = image_->Size();
692  if (out->WriteFully(reinterpret_cast<char*>(image_->Begin()), expect) &&
693      out->SetLength(expect) == 0) {
694    return true;
695  } else {
696    LOG(ERROR) << "Writing to image file " << out->GetPath() << " failed.";
697    return false;
698  }
699}
700
701bool PatchOat::IsImagePic(const ImageHeader& image_header, const std::string& image_path) {
702  if (!image_header.CompilePic()) {
703    if (kIsDebugBuild) {
704      LOG(INFO) << "image at location " << image_path << " was *not* compiled pic";
705    }
706    return false;
707  }
708
709  if (kIsDebugBuild) {
710    LOG(INFO) << "image at location " << image_path << " was compiled PIC";
711  }
712
713  return true;
714}
715
716PatchOat::MaybePic PatchOat::IsOatPic(const ElfFile* oat_in) {
717  if (oat_in == nullptr) {
718    LOG(ERROR) << "No ELF input oat fie available";
719    return ERROR_OAT_FILE;
720  }
721
722  const std::string& file_path = oat_in->GetFilePath();
723
724  const OatHeader* oat_header = GetOatHeader(oat_in);
725  if (oat_header == nullptr) {
726    LOG(ERROR) << "Failed to find oat header in oat file " << file_path;
727    return ERROR_OAT_FILE;
728  }
729
730  if (!oat_header->IsValid()) {
731    LOG(ERROR) << "Elf file " << file_path << " has an invalid oat header";
732    return ERROR_OAT_FILE;
733  }
734
735  bool is_pic = oat_header->IsPic();
736  if (kIsDebugBuild) {
737    LOG(INFO) << "Oat file at " << file_path << " is " << (is_pic ? "PIC" : "not pic");
738  }
739
740  return is_pic ? PIC : NOT_PIC;
741}
742
743bool PatchOat::ReplaceOatFileWithSymlink(const std::string& input_oat_filename,
744                                         const std::string& output_oat_filename) {
745  // Delete the original file, since we won't need it.
746  unlink(output_oat_filename.c_str());
747
748  // Create a symlink from the old oat to the new oat
749  if (symlink(input_oat_filename.c_str(), output_oat_filename.c_str()) < 0) {
750    int err = errno;
751    LOG(ERROR) << "Failed to create symlink at " << output_oat_filename
752               << " error(" << err << "): " << strerror(err);
753    return false;
754  }
755
756  if (kIsDebugBuild) {
757    LOG(INFO) << "Created symlink " << output_oat_filename << " -> " << input_oat_filename;
758  }
759
760  return true;
761}
762
763class PatchOat::PatchOatArtFieldVisitor : public ArtFieldVisitor {
764 public:
765  explicit PatchOatArtFieldVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {}
766
767  void Visit(ArtField* field) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
768    ArtField* const dest = patch_oat_->RelocatedCopyOf(field);
769    dest->SetDeclaringClass(
770        patch_oat_->RelocatedAddressOfPointer(field->GetDeclaringClass().Ptr()));
771  }
772
773 private:
774  PatchOat* const patch_oat_;
775};
776
777void PatchOat::PatchArtFields(const ImageHeader* image_header) {
778  PatchOatArtFieldVisitor visitor(this);
779  image_header->VisitPackedArtFields(&visitor, heap_->Begin());
780}
781
782class PatchOat::PatchOatArtMethodVisitor : public ArtMethodVisitor {
783 public:
784  explicit PatchOatArtMethodVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {}
785
786  void Visit(ArtMethod* method) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
787    ArtMethod* const dest = patch_oat_->RelocatedCopyOf(method);
788    patch_oat_->FixupMethod(method, dest);
789  }
790
791 private:
792  PatchOat* const patch_oat_;
793};
794
795void PatchOat::PatchArtMethods(const ImageHeader* image_header) {
796  const PointerSize pointer_size = InstructionSetPointerSize(isa_);
797  PatchOatArtMethodVisitor visitor(this);
798  image_header->VisitPackedArtMethods(&visitor, heap_->Begin(), pointer_size);
799}
800
801void PatchOat::PatchImTables(const ImageHeader* image_header) {
802  const PointerSize pointer_size = InstructionSetPointerSize(isa_);
803  // We can safely walk target image since the conflict tables are independent.
804  image_header->VisitPackedImTables(
805      [this](ArtMethod* method) {
806        return RelocatedAddressOfPointer(method);
807      },
808      image_->Begin(),
809      pointer_size);
810}
811
812void PatchOat::PatchImtConflictTables(const ImageHeader* image_header) {
813  const PointerSize pointer_size = InstructionSetPointerSize(isa_);
814  // We can safely walk target image since the conflict tables are independent.
815  image_header->VisitPackedImtConflictTables(
816      [this](ArtMethod* method) {
817        return RelocatedAddressOfPointer(method);
818      },
819      image_->Begin(),
820      pointer_size);
821}
822
823class PatchOat::FixupRootVisitor : public RootVisitor {
824 public:
825  explicit FixupRootVisitor(const PatchOat* patch_oat) : patch_oat_(patch_oat) {
826  }
827
828  void VisitRoots(mirror::Object*** roots, size_t count, const RootInfo& info ATTRIBUTE_UNUSED)
829      OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
830    for (size_t i = 0; i < count; ++i) {
831      *roots[i] = patch_oat_->RelocatedAddressOfPointer(*roots[i]);
832    }
833  }
834
835  void VisitRoots(mirror::CompressedReference<mirror::Object>** roots, size_t count,
836                  const RootInfo& info ATTRIBUTE_UNUSED)
837      OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
838    for (size_t i = 0; i < count; ++i) {
839      roots[i]->Assign(patch_oat_->RelocatedAddressOfPointer(roots[i]->AsMirrorPtr()));
840    }
841  }
842
843 private:
844  const PatchOat* const patch_oat_;
845};
846
847void PatchOat::PatchInternedStrings(const ImageHeader* image_header) {
848  const auto& section = image_header->GetInternedStringsSection();
849  if (section.Size() == 0) {
850    return;
851  }
852  InternTable temp_table;
853  // Note that we require that ReadFromMemory does not make an internal copy of the elements.
854  // This also relies on visit roots not doing any verification which could fail after we update
855  // the roots to be the image addresses.
856  temp_table.AddTableFromMemory(image_->Begin() + section.Offset());
857  FixupRootVisitor visitor(this);
858  temp_table.VisitRoots(&visitor, kVisitRootFlagAllRoots);
859}
860
861void PatchOat::PatchClassTable(const ImageHeader* image_header) {
862  const auto& section = image_header->GetClassTableSection();
863  if (section.Size() == 0) {
864    return;
865  }
866  // Note that we require that ReadFromMemory does not make an internal copy of the elements.
867  // This also relies on visit roots not doing any verification which could fail after we update
868  // the roots to be the image addresses.
869  WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
870  ClassTable temp_table;
871  temp_table.ReadFromMemory(image_->Begin() + section.Offset());
872  FixupRootVisitor visitor(this);
873  temp_table.VisitRoots(UnbufferedRootVisitor(&visitor, RootInfo(kRootUnknown)));
874}
875
876
877class PatchOat::RelocatedPointerVisitor {
878 public:
879  explicit RelocatedPointerVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {}
880
881  template <typename T>
882  T* operator()(T* ptr, void** dest_addr ATTRIBUTE_UNUSED = 0) const {
883    return patch_oat_->RelocatedAddressOfPointer(ptr);
884  }
885
886 private:
887  PatchOat* const patch_oat_;
888};
889
890void PatchOat::PatchDexFileArrays(mirror::ObjectArray<mirror::Object>* img_roots) {
891  auto* dex_caches = down_cast<mirror::ObjectArray<mirror::DexCache>*>(
892      img_roots->Get(ImageHeader::kDexCaches));
893  const PointerSize pointer_size = InstructionSetPointerSize(isa_);
894  for (size_t i = 0, count = dex_caches->GetLength(); i < count; ++i) {
895    auto* orig_dex_cache = dex_caches->GetWithoutChecks(i);
896    auto* copy_dex_cache = RelocatedCopyOf(orig_dex_cache);
897    // Though the DexCache array fields are usually treated as native pointers, we set the full
898    // 64-bit values here, clearing the top 32 bits for 32-bit targets. The zero-extension is
899    // done by casting to the unsigned type uintptr_t before casting to int64_t, i.e.
900    //     static_cast<int64_t>(reinterpret_cast<uintptr_t>(image_begin_ + offset))).
901    mirror::StringDexCacheType* orig_strings = orig_dex_cache->GetStrings();
902    mirror::StringDexCacheType* relocated_strings = RelocatedAddressOfPointer(orig_strings);
903    copy_dex_cache->SetField64<false>(
904        mirror::DexCache::StringsOffset(),
905        static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_strings)));
906    if (orig_strings != nullptr) {
907      orig_dex_cache->FixupStrings(RelocatedCopyOf(orig_strings), RelocatedPointerVisitor(this));
908    }
909    mirror::TypeDexCacheType* orig_types = orig_dex_cache->GetResolvedTypes();
910    mirror::TypeDexCacheType* relocated_types = RelocatedAddressOfPointer(orig_types);
911    copy_dex_cache->SetField64<false>(
912        mirror::DexCache::ResolvedTypesOffset(),
913        static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_types)));
914    if (orig_types != nullptr) {
915      orig_dex_cache->FixupResolvedTypes(RelocatedCopyOf(orig_types),
916                                         RelocatedPointerVisitor(this));
917    }
918    mirror::MethodDexCacheType* orig_methods = orig_dex_cache->GetResolvedMethods();
919    mirror::MethodDexCacheType* relocated_methods = RelocatedAddressOfPointer(orig_methods);
920    copy_dex_cache->SetField64<false>(
921        mirror::DexCache::ResolvedMethodsOffset(),
922        static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_methods)));
923    if (orig_methods != nullptr) {
924      mirror::MethodDexCacheType* copy_methods = RelocatedCopyOf(orig_methods);
925      for (size_t j = 0, num = orig_dex_cache->NumResolvedMethods(); j != num; ++j) {
926        mirror::MethodDexCachePair orig =
927            mirror::DexCache::GetNativePairPtrSize(orig_methods, j, pointer_size);
928        mirror::MethodDexCachePair copy(RelocatedAddressOfPointer(orig.object), orig.index);
929        mirror::DexCache::SetNativePairPtrSize(copy_methods, j, copy, pointer_size);
930      }
931    }
932    mirror::FieldDexCacheType* orig_fields = orig_dex_cache->GetResolvedFields();
933    mirror::FieldDexCacheType* relocated_fields = RelocatedAddressOfPointer(orig_fields);
934    copy_dex_cache->SetField64<false>(
935        mirror::DexCache::ResolvedFieldsOffset(),
936        static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_fields)));
937    if (orig_fields != nullptr) {
938      mirror::FieldDexCacheType* copy_fields = RelocatedCopyOf(orig_fields);
939      for (size_t j = 0, num = orig_dex_cache->NumResolvedFields(); j != num; ++j) {
940        mirror::FieldDexCachePair orig =
941            mirror::DexCache::GetNativePairPtrSize(orig_fields, j, pointer_size);
942        mirror::FieldDexCachePair copy(RelocatedAddressOfPointer(orig.object), orig.index);
943        mirror::DexCache::SetNativePairPtrSize(copy_fields, j, copy, pointer_size);
944      }
945    }
946    mirror::MethodTypeDexCacheType* orig_method_types = orig_dex_cache->GetResolvedMethodTypes();
947    mirror::MethodTypeDexCacheType* relocated_method_types =
948        RelocatedAddressOfPointer(orig_method_types);
949    copy_dex_cache->SetField64<false>(
950        mirror::DexCache::ResolvedMethodTypesOffset(),
951        static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_method_types)));
952    if (orig_method_types != nullptr) {
953      orig_dex_cache->FixupResolvedMethodTypes(RelocatedCopyOf(orig_method_types),
954                                               RelocatedPointerVisitor(this));
955    }
956
957    GcRoot<mirror::CallSite>* orig_call_sites = orig_dex_cache->GetResolvedCallSites();
958    GcRoot<mirror::CallSite>* relocated_call_sites = RelocatedAddressOfPointer(orig_call_sites);
959    copy_dex_cache->SetField64<false>(
960        mirror::DexCache::ResolvedCallSitesOffset(),
961        static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_call_sites)));
962    if (orig_call_sites != nullptr) {
963      orig_dex_cache->FixupResolvedCallSites(RelocatedCopyOf(orig_call_sites),
964                                             RelocatedPointerVisitor(this));
965    }
966  }
967}
968
969bool PatchOat::PatchImage(bool primary_image) {
970  ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin());
971  CHECK_GT(image_->Size(), sizeof(ImageHeader));
972  // These are the roots from the original file.
973  auto* img_roots = image_header->GetImageRoots();
974  image_header->RelocateImage(delta_);
975
976  PatchArtFields(image_header);
977  PatchArtMethods(image_header);
978  PatchImTables(image_header);
979  PatchImtConflictTables(image_header);
980  PatchInternedStrings(image_header);
981  PatchClassTable(image_header);
982  // Patch dex file int/long arrays which point to ArtFields.
983  PatchDexFileArrays(img_roots);
984
985  if (primary_image) {
986    VisitObject(img_roots);
987  }
988
989  if (!image_header->IsValid()) {
990    LOG(ERROR) << "relocation renders image header invalid";
991    return false;
992  }
993
994  {
995    TimingLogger::ScopedTiming t("Walk Bitmap", timings_);
996    // Walk the bitmap.
997    WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
998    auto visitor = [&](mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
999      VisitObject(obj);
1000    };
1001    bitmap_->Walk(visitor);
1002  }
1003  return true;
1004}
1005
1006
1007void PatchOat::PatchVisitor::operator() (ObjPtr<mirror::Object> obj,
1008                                         MemberOffset off,
1009                                         bool is_static_unused ATTRIBUTE_UNUSED) const {
1010  mirror::Object* referent = obj->GetFieldObject<mirror::Object, kVerifyNone>(off);
1011  mirror::Object* moved_object = patcher_->RelocatedAddressOfPointer(referent);
1012  copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(off, moved_object);
1013}
1014
1015void PatchOat::PatchVisitor::operator() (ObjPtr<mirror::Class> cls ATTRIBUTE_UNUSED,
1016                                         ObjPtr<mirror::Reference> ref) const {
1017  MemberOffset off = mirror::Reference::ReferentOffset();
1018  mirror::Object* referent = ref->GetReferent();
1019  DCHECK(referent == nullptr ||
1020         Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(referent)) << referent;
1021  mirror::Object* moved_object = patcher_->RelocatedAddressOfPointer(referent);
1022  copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(off, moved_object);
1023}
1024
1025// Called by PatchImage.
1026void PatchOat::VisitObject(mirror::Object* object) {
1027  mirror::Object* copy = RelocatedCopyOf(object);
1028  CHECK(copy != nullptr);
1029  if (kUseBakerReadBarrier) {
1030    object->AssertReadBarrierState();
1031  }
1032  PatchOat::PatchVisitor visitor(this, copy);
1033  object->VisitReferences<kVerifyNone>(visitor, visitor);
1034  if (object->IsClass<kVerifyNone>()) {
1035    const PointerSize pointer_size = InstructionSetPointerSize(isa_);
1036    mirror::Class* klass = object->AsClass();
1037    mirror::Class* copy_klass = down_cast<mirror::Class*>(copy);
1038    RelocatedPointerVisitor native_visitor(this);
1039    klass->FixupNativePointers(copy_klass, pointer_size, native_visitor);
1040    auto* vtable = klass->GetVTable();
1041    if (vtable != nullptr) {
1042      vtable->Fixup(RelocatedCopyOfFollowImages(vtable), pointer_size, native_visitor);
1043    }
1044    mirror::IfTable* iftable = klass->GetIfTable();
1045    for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) {
1046      if (iftable->GetMethodArrayCount(i) > 0) {
1047        auto* method_array = iftable->GetMethodArray(i);
1048        CHECK(method_array != nullptr);
1049        method_array->Fixup(RelocatedCopyOfFollowImages(method_array),
1050                            pointer_size,
1051                            native_visitor);
1052      }
1053    }
1054  } else if (object->GetClass() == mirror::Method::StaticClass() ||
1055             object->GetClass() == mirror::Constructor::StaticClass()) {
1056    // Need to go update the ArtMethod.
1057    auto* dest = down_cast<mirror::Executable*>(copy);
1058    auto* src = down_cast<mirror::Executable*>(object);
1059    dest->SetArtMethod(RelocatedAddressOfPointer(src->GetArtMethod()));
1060  }
1061}
1062
1063void PatchOat::FixupMethod(ArtMethod* object, ArtMethod* copy) {
1064  const PointerSize pointer_size = InstructionSetPointerSize(isa_);
1065  copy->CopyFrom(object, pointer_size);
1066  // Just update the entry points if it looks like we should.
1067  // TODO: sanity check all the pointers' values
1068  copy->SetDeclaringClass(RelocatedAddressOfPointer(object->GetDeclaringClass()));
1069  copy->SetEntryPointFromQuickCompiledCodePtrSize(RelocatedAddressOfPointer(
1070      object->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size)), pointer_size);
1071  // No special handling for IMT conflict table since all pointers are moved by the same offset.
1072  copy->SetDataPtrSize(RelocatedAddressOfPointer(
1073      object->GetDataPtrSize(pointer_size)), pointer_size);
1074}
1075
1076static int orig_argc;
1077static char** orig_argv;
1078
1079static std::string CommandLine() {
1080  std::vector<std::string> command;
1081  for (int i = 0; i < orig_argc; ++i) {
1082    command.push_back(orig_argv[i]);
1083  }
1084  return android::base::Join(command, ' ');
1085}
1086
1087static void UsageErrorV(const char* fmt, va_list ap) {
1088  std::string error;
1089  android::base::StringAppendV(&error, fmt, ap);
1090  LOG(ERROR) << error;
1091}
1092
1093static void UsageError(const char* fmt, ...) {
1094  va_list ap;
1095  va_start(ap, fmt);
1096  UsageErrorV(fmt, ap);
1097  va_end(ap);
1098}
1099
1100NO_RETURN static void Usage(const char *fmt, ...) {
1101  va_list ap;
1102  va_start(ap, fmt);
1103  UsageErrorV(fmt, ap);
1104  va_end(ap);
1105
1106  UsageError("Command: %s", CommandLine().c_str());
1107  UsageError("Usage: patchoat [options]...");
1108  UsageError("");
1109  UsageError("  --instruction-set=<isa>: Specifies the instruction set the patched code is");
1110  UsageError("      compiled for (required).");
1111  UsageError("");
1112  UsageError("  --input-image-location=<file.art>: Specifies the 'location' of the image file to");
1113  UsageError("      be patched.");
1114  UsageError("");
1115  UsageError("  --output-image-file=<file.art>: Specifies the exact file to write the patched");
1116  UsageError("      image file to.");
1117  UsageError("");
1118  UsageError("  --output-image-relocation-file=<file.art.rel>: Specifies the exact file to write");
1119  UsageError("      the image relocation information to.");
1120  UsageError("");
1121  UsageError("  --base-offset-delta=<delta>: Specify the amount to change the old base-offset by.");
1122  UsageError("      This value may be negative.");
1123  UsageError("");
1124  UsageError("  --verify: Verify an existing patched file instead of creating one.");
1125  UsageError("");
1126  UsageError("  --dump-timings: dump out patch timing information");
1127  UsageError("");
1128  UsageError("  --no-dump-timings: do not dump out patch timing information");
1129  UsageError("");
1130
1131  exit(EXIT_FAILURE);
1132}
1133
1134static int patchoat_patch_image(TimingLogger& timings,
1135                                InstructionSet isa,
1136                                const std::string& input_image_location,
1137                                const std::string& output_image_directory,
1138                                const std::string& output_image_relocation_filename,
1139                                off_t base_delta,
1140                                bool base_delta_set,
1141                                bool debug) {
1142  CHECK(!input_image_location.empty());
1143  if ((output_image_directory.empty()) && (output_image_relocation_filename.empty())) {
1144    Usage("Image patching requires --output-image-file or --output-image-relocation-file");
1145  }
1146
1147  if (!base_delta_set) {
1148    Usage("Must supply a desired new offset or delta.");
1149  }
1150
1151  if (!IsAligned<kPageSize>(base_delta)) {
1152    Usage("Base offset/delta must be aligned to a pagesize (0x%08x) boundary.", kPageSize);
1153  }
1154
1155  if (debug) {
1156    LOG(INFO) << "moving offset by " << base_delta
1157        << " (0x" << std::hex << base_delta << ") bytes or "
1158        << std::dec << (base_delta/kPageSize) << " pages.";
1159  }
1160
1161  TimingLogger::ScopedTiming pt("patch image and oat", &timings);
1162
1163  std::string output_image_relocation_directory =
1164      output_image_relocation_filename.substr(
1165          0, output_image_relocation_filename.find_last_of('/'));
1166  bool ret =
1167      PatchOat::Patch(
1168          input_image_location,
1169          base_delta,
1170          output_image_directory,
1171          output_image_relocation_directory,
1172          isa,
1173          &timings);
1174
1175  if (kIsDebugBuild) {
1176    LOG(INFO) << "Exiting with return ... " << ret;
1177  }
1178  return ret ? EXIT_SUCCESS : EXIT_FAILURE;
1179}
1180
1181static int patchoat_verify_image(TimingLogger& timings,
1182                                 InstructionSet isa,
1183                                 const std::string& input_image_location,
1184                                 const std::string& output_image_directory) {
1185  CHECK(!input_image_location.empty());
1186  TimingLogger::ScopedTiming pt("verify image and oat", &timings);
1187
1188  bool ret =
1189      PatchOat::Verify(
1190          input_image_location,
1191          output_image_directory,
1192          isa,
1193          &timings);
1194
1195  if (kIsDebugBuild) {
1196    LOG(INFO) << "Exiting with return ... " << ret;
1197  }
1198  return ret ? EXIT_SUCCESS : EXIT_FAILURE;
1199}
1200
1201static int patchoat(int argc, char **argv) {
1202  InitLogging(argv, Runtime::Abort);
1203  MemMap::Init();
1204  const bool debug = kIsDebugBuild;
1205  orig_argc = argc;
1206  orig_argv = argv;
1207  TimingLogger timings("patcher", false, false);
1208
1209  // Skip over the command name.
1210  argv++;
1211  argc--;
1212
1213  if (argc == 0) {
1214    Usage("No arguments specified");
1215  }
1216
1217  timings.StartTiming("Patchoat");
1218
1219  // cmd line args
1220  bool isa_set = false;
1221  InstructionSet isa = InstructionSet::kNone;
1222  std::string input_image_location;
1223  std::string output_image_filename;
1224  std::string output_image_relocation_filename;
1225  off_t base_delta = 0;
1226  bool base_delta_set = false;
1227  bool dump_timings = kIsDebugBuild;
1228  bool verify = false;
1229
1230  for (int i = 0; i < argc; ++i) {
1231    const StringPiece option(argv[i]);
1232    const bool log_options = false;
1233    if (log_options) {
1234      LOG(INFO) << "patchoat: option[" << i << "]=" << argv[i];
1235    }
1236    if (option.starts_with("--instruction-set=")) {
1237      isa_set = true;
1238      const char* isa_str = option.substr(strlen("--instruction-set=")).data();
1239      isa = GetInstructionSetFromString(isa_str);
1240      if (isa == InstructionSet::kNone) {
1241        Usage("Unknown or invalid instruction set %s", isa_str);
1242      }
1243    } else if (option.starts_with("--input-image-location=")) {
1244      input_image_location = option.substr(strlen("--input-image-location=")).data();
1245    } else if (option.starts_with("--output-image-file=")) {
1246      output_image_filename = option.substr(strlen("--output-image-file=")).data();
1247    } else if (option.starts_with("--output-image-relocation-file=")) {
1248      output_image_relocation_filename =
1249          option.substr(strlen("--output-image-relocation-file=")).data();
1250    } else if (option.starts_with("--base-offset-delta=")) {
1251      const char* base_delta_str = option.substr(strlen("--base-offset-delta=")).data();
1252      base_delta_set = true;
1253      if (!ParseInt(base_delta_str, &base_delta)) {
1254        Usage("Failed to parse --base-offset-delta argument '%s' as an off_t", base_delta_str);
1255      }
1256    } else if (option == "--dump-timings") {
1257      dump_timings = true;
1258    } else if (option == "--no-dump-timings") {
1259      dump_timings = false;
1260    } else if (option == "--verify") {
1261      verify = true;
1262    } else {
1263      Usage("Unknown argument %s", option.data());
1264    }
1265  }
1266
1267  // TODO: Have calls to patchoat pass in the output_image directory instead of
1268  // the output_image_filename.
1269  std::string output_image_directory;
1270  if (!output_image_filename.empty())
1271    output_image_directory = android::base::Dirname(output_image_filename);
1272
1273  // The instruction set is mandatory. This simplifies things...
1274  if (!isa_set) {
1275    Usage("Instruction set must be set.");
1276  }
1277
1278  int ret;
1279  if (verify) {
1280    ret = patchoat_verify_image(timings,
1281                                isa,
1282                                input_image_location,
1283                                output_image_directory);
1284  } else {
1285    ret = patchoat_patch_image(timings,
1286                               isa,
1287                               input_image_location,
1288                               output_image_directory,
1289                               output_image_relocation_filename,
1290                               base_delta,
1291                               base_delta_set,
1292                               debug);
1293  }
1294
1295  timings.EndTiming();
1296  if (dump_timings) {
1297    LOG(INFO) << Dumpable<TimingLogger>(timings);
1298  }
1299
1300  return ret;
1301}
1302
1303}  // namespace art
1304
1305int main(int argc, char **argv) {
1306  return art::patchoat(argc, argv);
1307}
1308