Add patchoat tool to Art.

Add a new executable called patchoat to art. This tool takes already
compiled images and oat files and changes their base address, acting as
a cheap form of relocation.

Add a --include-patch-information flag to dex2oat and code to add
required patch information to oat files created with the quick compiler.

Bug: 15358152

Change-Id: Ie0c580db45bb14ec180deb84930def6c3628d97d
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index fb3341b..92b2fee 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -43,6 +43,7 @@
   static const size_t kDefaultNumDexMethodsThreshold = 900;
   static constexpr double kDefaultTopKProfileThreshold = 90.0;
   static const bool kDefaultIncludeDebugSymbols = kIsDebugBuild;
+  static const bool kDefaultIncludePatchInformation = false;
 
   CompilerOptions() :
     compiler_filter_(kDefaultCompilerFilter),
@@ -52,6 +53,7 @@
     tiny_method_threshold_(kDefaultTinyMethodThreshold),
     num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold),
     generate_gdb_information_(false),
+    include_patch_information_(kDefaultIncludePatchInformation),
     top_k_profile_threshold_(kDefaultTopKProfileThreshold),
     include_debug_symbols_(kDefaultIncludeDebugSymbols),
     explicit_null_checks_(true),
@@ -69,6 +71,7 @@
                   size_t tiny_method_threshold,
                   size_t num_dex_methods_threshold,
                   bool generate_gdb_information,
+                  bool include_patch_information,
                   double top_k_profile_threshold,
                   bool include_debug_symbols,
                   bool explicit_null_checks,
@@ -85,6 +88,7 @@
     tiny_method_threshold_(tiny_method_threshold),
     num_dex_methods_threshold_(num_dex_methods_threshold),
     generate_gdb_information_(generate_gdb_information),
+    include_patch_information_(include_patch_information),
     top_k_profile_threshold_(top_k_profile_threshold),
     include_debug_symbols_(include_debug_symbols),
     explicit_null_checks_(explicit_null_checks),
@@ -188,6 +192,10 @@
     return generate_gdb_information_;
   }
 
+  bool GetIncludePatchInformation() const {
+    return include_patch_information_;
+  }
+
  private:
   CompilerFilter compiler_filter_;
   size_t huge_method_threshold_;
@@ -196,6 +204,7 @@
   size_t tiny_method_threshold_;
   size_t num_dex_methods_threshold_;
   bool generate_gdb_information_;
+  bool include_patch_information_;
   // When using a profile file only the top K% of the profiled samples will be compiled.
   double top_k_profile_threshold_;
   bool include_debug_symbols_;
diff --git a/compiler/elf_fixup.cc b/compiler/elf_fixup.cc
index 404e3f8..60f76ef 100644
--- a/compiler/elf_fixup.cc
+++ b/compiler/elf_fixup.cc
@@ -69,97 +69,7 @@
   for (Elf32_Word i = 0; i < elf_file.GetDynamicNum(); i++) {
     Elf32_Dyn& elf_dyn = elf_file.GetDynamic(i);
     Elf32_Word d_tag = elf_dyn.d_tag;
-    bool elf_dyn_needs_fixup = false;
-    switch (d_tag) {
-      // case 1: well known d_tag values that imply Elf32_Dyn.d_un contains an address in d_ptr
-      case DT_PLTGOT:
-      case DT_HASH:
-      case DT_STRTAB:
-      case DT_SYMTAB:
-      case DT_RELA:
-      case DT_INIT:
-      case DT_FINI:
-      case DT_REL:
-      case DT_DEBUG:
-      case DT_JMPREL: {
-        elf_dyn_needs_fixup = true;
-        break;
-      }
-      // d_val or ignored values
-      case DT_NULL:
-      case DT_NEEDED:
-      case DT_PLTRELSZ:
-      case DT_RELASZ:
-      case DT_RELAENT:
-      case DT_STRSZ:
-      case DT_SYMENT:
-      case DT_SONAME:
-      case DT_RPATH:
-      case DT_SYMBOLIC:
-      case DT_RELSZ:
-      case DT_RELENT:
-      case DT_PLTREL:
-      case DT_TEXTREL:
-      case DT_BIND_NOW:
-      case DT_INIT_ARRAYSZ:
-      case DT_FINI_ARRAYSZ:
-      case DT_RUNPATH:
-      case DT_FLAGS: {
-        break;
-      }
-      // boundary values that should not be used
-      case DT_ENCODING:
-      case DT_LOOS:
-      case DT_HIOS:
-      case DT_LOPROC:
-      case DT_HIPROC: {
-        LOG(FATAL) << "Illegal d_tag value 0x" << std::hex << d_tag;
-        break;
-      }
-      default: {
-        // case 2: "regular" DT_* ranges where even d_tag values imply an address in d_ptr
-        if ((DT_ENCODING  < d_tag && d_tag < DT_LOOS)
-            || (DT_LOOS   < d_tag && d_tag < DT_HIOS)
-            || (DT_LOPROC < d_tag && d_tag < DT_HIPROC)) {
-          // Special case for MIPS which breaks the regular rules between DT_LOPROC and DT_HIPROC
-          if (elf_file.GetHeader().e_machine == EM_MIPS) {
-            switch (d_tag) {
-              case DT_MIPS_RLD_VERSION:
-              case DT_MIPS_TIME_STAMP:
-              case DT_MIPS_ICHECKSUM:
-              case DT_MIPS_IVERSION:
-              case DT_MIPS_FLAGS:
-              case DT_MIPS_LOCAL_GOTNO:
-              case DT_MIPS_CONFLICTNO:
-              case DT_MIPS_LIBLISTNO:
-              case DT_MIPS_SYMTABNO:
-              case DT_MIPS_UNREFEXTNO:
-              case DT_MIPS_GOTSYM:
-              case DT_MIPS_HIPAGENO: {
-                break;
-              }
-              case DT_MIPS_BASE_ADDRESS:
-              case DT_MIPS_CONFLICT:
-              case DT_MIPS_LIBLIST:
-              case DT_MIPS_RLD_MAP: {
-                elf_dyn_needs_fixup = true;
-                break;
-              }
-              default: {
-                LOG(FATAL) << "Unknown MIPS d_tag value 0x" << std::hex << d_tag;
-                break;
-              }
-            }
-          } else if ((elf_dyn.d_tag % 2) == 0) {
-            elf_dyn_needs_fixup = true;
-          }
-        } else {
-          LOG(FATAL) << "Unknown d_tag value 0x" << std::hex << d_tag;
-        }
-        break;
-      }
-    }
-    if (elf_dyn_needs_fixup) {
+    if (IsDynamicSectionPointer(d_tag, elf_file.GetHeader().e_machine)) {
       uint32_t d_ptr = elf_dyn.d_un.d_ptr;
       if (DEBUG_FIXUP) {
         LOG(INFO) << StringPrintf("In %s moving Elf32_Dyn[%d] from 0x%08x to 0x%08" PRIxPTR,
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index e4dcaa7..06f6e89 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <unordered_set>
+
 #include "elf_writer_quick.h"
 
 #include "base/logging.h"
@@ -803,6 +805,25 @@
   return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
 }
 
+// Add patch information to this section. Each patch is a Elf32_Word that
+// identifies an offset from the start of the text section
+void ElfWriterQuick::ReservePatchSpace(std::vector<uint8_t>* buffer, bool debug) {
+  size_t size =
+      compiler_driver_->GetCodeToPatch().size() +
+      compiler_driver_->GetMethodsToPatch().size() +
+      compiler_driver_->GetClassesToPatch().size();
+  if (size == 0) {
+    if (debug) {
+      LOG(INFO) << "No patches to record";
+    }
+    return;
+  }
+  buffer->resize(size * sizeof(uintptr_t));
+  if (debug) {
+    LOG(INFO) << "Patches reserved for " << size;
+  }
+}
+
 bool ElfWriterQuick::Write(OatWriter* oat_writer,
                            const std::vector<const DexFile*>& dex_files_unused,
                            const std::string& android_root_unused,
@@ -836,6 +857,13 @@
     builder.RegisterRawSection(debug_str);
   }
 
+  if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation()) {
+    ElfRawSectionBuilder oat_patches(".oat_patches", SHT_OAT_PATCH, 0, NULL, 0,
+                                     sizeof(size_t), sizeof(size_t));
+    ReservePatchSpace(oat_patches.GetBuffer(), debug);
+    builder.RegisterRawSection(oat_patches);
+  }
+
   return builder.Write();
 }
 
diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h
index 6eb5d68..a0d36df 100644
--- a/compiler/elf_writer_quick.h
+++ b/compiler/elf_writer_quick.h
@@ -51,6 +51,7 @@
   void AddDebugSymbols(ElfBuilder& builder,
                        OatWriter* oat_writer,
                        bool debug);
+  void ReservePatchSpace(std::vector<uint8_t>* buffer, bool debug);
 
   class ElfSectionBuilder {
    public:
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 6e5f19a..2d25b7a 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -27,6 +27,8 @@
 #include "compiled_method.h"
 #include "dex_file-inl.h"
 #include "driver/compiler_driver.h"
+#include "elf_file.h"
+#include "elf_utils.h"
 #include "elf_writer.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/accounting/heap_bitmap.h"
@@ -138,7 +140,8 @@
   ElfWriter::GetOatElfInformation(oat_file.get(), oat_loaded_size, oat_data_offset);
   CalculateNewObjectOffsets(oat_loaded_size, oat_data_offset);
   CopyAndFixupObjects();
-  PatchOatCodeAndMethods();
+
+  PatchOatCodeAndMethods(oat_file.get());
   Thread::Current()->TransitionFromRunnableToSuspended(kNative);
 
   std::unique_ptr<File> image_file(OS::CreateEmptyFile(image_filename.c_str()));
@@ -782,7 +785,25 @@
   return klass;
 }
 
-void ImageWriter::PatchOatCodeAndMethods() {
+void ImageWriter::PatchOatCodeAndMethods(File* elf_file) {
+  std::vector<uintptr_t> patches;
+  std::set<uintptr_t> patches_set;
+  auto maybe_push = [&patches, &patches_set] (uintptr_t p) {
+    if (patches_set.find(p) == patches_set.end()) {
+      patches.push_back(p);
+      patches_set.insert(p);
+    }
+  };
+  const bool add_patches = compiler_driver_.GetCompilerOptions().GetIncludePatchInformation();
+  if (add_patches) {
+    // TODO if we are adding patches the resulting ELF file might have a
+    // potentially rather large amount of free space where patches might have been
+    // placed. We should adjust the ELF file to get rid of this excess space.
+    patches.reserve(compiler_driver_.GetCodeToPatch().size() +
+                    compiler_driver_.GetMethodsToPatch().size() +
+                    compiler_driver_.GetClassesToPatch().size());
+  }
+  uintptr_t loc = 0;
   Thread* self = Thread::Current();
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
@@ -828,14 +849,20 @@
     } else {
       value = PointerToLowMemUInt32(GetOatAddress(code_offset));
     }
-    SetPatchLocation(patch, value);
+    SetPatchLocation(patch, value, &loc);
+    if (add_patches && !patch->AsCall()->IsRelative()) {
+      maybe_push(loc);
+    }
   }
 
   const CallPatches& methods_to_patch = compiler_driver_.GetMethodsToPatch();
   for (size_t i = 0; i < methods_to_patch.size(); i++) {
     const CompilerDriver::CallPatchInformation* patch = methods_to_patch[i];
     ArtMethod* target = GetTargetMethod(patch);
-    SetPatchLocation(patch, PointerToLowMemUInt32(GetImageAddress(target)));
+    SetPatchLocation(patch, PointerToLowMemUInt32(GetImageAddress(target)), &loc);
+    if (add_patches && !patch->AsCall()->IsRelative()) {
+      maybe_push(loc);
+    }
   }
 
   const std::vector<const CompilerDriver::TypePatchInformation*>& classes_to_patch =
@@ -843,16 +870,51 @@
   for (size_t i = 0; i < classes_to_patch.size(); i++) {
     const CompilerDriver::TypePatchInformation* patch = classes_to_patch[i];
     Class* target = GetTargetType(patch);
-    SetPatchLocation(patch, PointerToLowMemUInt32(GetImageAddress(target)));
+    SetPatchLocation(patch, PointerToLowMemUInt32(GetImageAddress(target)), &loc);
+    if (add_patches) {
+      maybe_push(loc);
+    }
   }
 
   // Update the image header with the new checksum after patching
   ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin());
   image_header->SetOatChecksum(oat_file_->GetOatHeader().GetChecksum());
   self->EndAssertNoThreadSuspension(old_cause);
+
+  // Update the ElfFiles SHT_OAT_PATCH section to include the patches.
+  if (add_patches) {
+    std::string err;
+    // TODO we are mapping in the contents of this file twice. We should be able
+    // to do it only once, which would be better.
+    std::unique_ptr<ElfFile> file(ElfFile::Open(elf_file, true, false, &err));
+    if (file == nullptr) {
+      LOG(ERROR) << err;
+    }
+    Elf32_Shdr* shdr = file->FindSectionByName(".oat_patches");
+    if (shdr != nullptr) {
+      DCHECK_EQ(shdr, file->FindSectionByType(SHT_OAT_PATCH))
+          << "Incorrect type for .oat_patches section";
+      CHECK_LE(patches.size() * sizeof(uintptr_t), shdr->sh_size)
+          << "We got more patches than anticipated";
+      CHECK_LE(reinterpret_cast<uintptr_t>(file->Begin()) + shdr->sh_offset + shdr->sh_size,
+               reinterpret_cast<uintptr_t>(file->End())) << "section is too large";
+      CHECK(shdr == &file->GetSectionHeader(file->GetSectionHeaderNum() - 1) ||
+            shdr->sh_offset + shdr->sh_size <= (shdr + 1)->sh_offset)
+          << "Section overlaps onto next section";
+      // It's mmap'd so we can just memcpy.
+      memcpy(file->Begin() + shdr->sh_offset, patches.data(), patches.size()*sizeof(uintptr_t));
+      // TODO We should fill in the newly empty space between the last patch and
+      // the start of the next section by moving the following sections down if
+      // possible.
+      shdr->sh_size = patches.size() * sizeof(uintptr_t);
+    } else {
+      LOG(ERROR) << "Unable to find section header for SHT_OAT_PATCH";
+    }
+  }
 }
 
-void ImageWriter::SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value) {
+void ImageWriter::SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value,
+                                   uintptr_t* patched_ptr) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   const void* quick_oat_code = class_linker->GetQuickOatCodeFor(patch->GetDexFile(),
                                                                 patch->GetReferrerClassDefIdx(),
@@ -885,6 +947,14 @@
   }
   *patch_location = value;
   oat_header.UpdateChecksum(patch_location, sizeof(value));
+
+  uintptr_t loc = reinterpret_cast<uintptr_t>(patch_location) -
+      (reinterpret_cast<uintptr_t>(oat_file_->Begin()) + oat_header.GetExecutableOffset());
+  CHECK_GT(reinterpret_cast<uintptr_t>(patch_location),
+            reinterpret_cast<uintptr_t>(oat_file_->Begin()) + oat_header.GetExecutableOffset());
+  CHECK_LT(loc, oat_file_->Size() - oat_header.GetExecutableOffset());
+
+  *patched_ptr = loc;
 }
 
 }  // namespace art
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index aff155a..2bcb41e 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -150,9 +150,10 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Patches references in OatFile to expect runtime addresses.
-  void PatchOatCodeAndMethods()
+  void PatchOatCodeAndMethods(File* elf_file)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value)
+  void SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value,
+                        uintptr_t* patched_location)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   const CompilerDriver& compiler_driver_;