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/runtime/elf_file.cc b/runtime/elf_file.cc
index bb33978..e5402e1 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -724,14 +724,23 @@
   return *(GetDynamicSectionStart() + i);
 }
 
-Elf32_Word ElfFile::FindDynamicValueByType(Elf32_Sword type) const {
+Elf32_Dyn* ElfFile::FindDynamicByType(Elf32_Sword type) const {
   for (Elf32_Word i = 0; i < GetDynamicNum(); i++) {
-    Elf32_Dyn& elf_dyn = GetDynamic(i);
-    if (elf_dyn.d_tag == type) {
-      return elf_dyn.d_un.d_val;
+    Elf32_Dyn* dyn = &GetDynamic(i);
+    if (dyn->d_tag == type) {
+      return dyn;
     }
   }
-  return 0;
+  return NULL;
+}
+
+Elf32_Word ElfFile::FindDynamicValueByType(Elf32_Sword type) const {
+  Elf32_Dyn* dyn = FindDynamicByType(type);
+  if (dyn == NULL) {
+    return 0;
+  } else {
+    return dyn->d_un.d_val;
+  }
 }
 
 Elf32_Rel* ElfFile::GetRelSectionStart(Elf32_Shdr& section_header) const {
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index 496690b..a966bd9 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -112,6 +112,7 @@
 
   Elf32_Word GetDynamicNum() const;
   Elf32_Dyn& GetDynamic(Elf32_Word) const;
+  Elf32_Dyn* FindDynamicByType(Elf32_Sword type) const;
   Elf32_Word FindDynamicValueByType(Elf32_Sword type) const;
 
   Elf32_Word GetRelNum(Elf32_Shdr&) const;
diff --git a/runtime/elf_utils.h b/runtime/elf_utils.h
index 2c50047..5966d05 100644
--- a/runtime/elf_utils.h
+++ b/runtime/elf_utils.h
@@ -22,6 +22,8 @@
 // Explicitly include our own elf.h to avoid Linux and other dependencies.
 #include "./elf.h"
 
+#include "base/logging.h"
+
 // Architecture dependent flags for the ELF header.
 #define EF_ARM_EABI_VER5 0x05000000
 #define EF_MIPS_ABI_O32 0x00001000
@@ -62,8 +64,103 @@
 #define DT_MIPS_HIPAGENO     0x70000014 /* Number of GOT page table entries */
 #define DT_MIPS_RLD_MAP      0x70000016 /* Address of debug map pointer */
 
+// Patching section type
+#define SHT_OAT_PATCH        SHT_LOUSER
+
 inline void SetBindingAndType(Elf32_Sym* sym, unsigned char b, unsigned char t) {
   sym->st_info = (b << 4) + (t & 0x0f);
 }
 
+inline bool IsDynamicSectionPointer(Elf32_Word d_tag, Elf32_Word e_machine) {
+  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: {
+      return true;
+    }
+    // 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: {
+      return false;
+    }
+    // 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;
+      return false;
+    }
+    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 (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: {
+              return false;
+            }
+            case DT_MIPS_BASE_ADDRESS:
+            case DT_MIPS_CONFLICT:
+            case DT_MIPS_LIBLIST:
+            case DT_MIPS_RLD_MAP: {
+              return true;
+            }
+            default: {
+              LOG(FATAL) << "Unknown MIPS d_tag value 0x" << std::hex << d_tag;
+              return false;
+            }
+          }
+        } else if ((d_tag % 2) == 0) {
+          return true;
+        } else {
+          return false;
+        }
+      } else {
+        LOG(FATAL) << "Unknown d_tag value 0x" << std::hex << d_tag;
+        return false;
+      }
+    }
+  }
+}
+
 #endif  // ART_RUNTIME_ELF_UTILS_H_
diff --git a/runtime/image.cc b/runtime/image.cc
index 528bfc6..93ec27d 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -24,7 +24,7 @@
 namespace art {
 
 const byte ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const byte ImageHeader::kImageVersion[] = { '0', '0', '7', '\0' };
+const byte ImageHeader::kImageVersion[] = { '0', '0', '8', '\0' };
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,
@@ -45,6 +45,7 @@
     oat_data_begin_(oat_data_begin),
     oat_data_end_(oat_data_end),
     oat_file_end_(oat_file_end),
+    patch_delta_(0),
     image_roots_(image_roots) {
   CHECK_EQ(image_begin, RoundUp(image_begin, kPageSize));
   CHECK_EQ(oat_file_begin, RoundUp(oat_file_begin, kPageSize));
@@ -58,6 +59,17 @@
   memcpy(version_, kImageVersion, sizeof(kImageVersion));
 }
 
+void ImageHeader::RelocateImage(off_t delta) {
+  CHECK_ALIGNED(delta, kPageSize) << " patch delta must be page aligned";
+  image_begin_ += delta;
+  oat_file_begin_ += delta;
+  oat_data_begin_ += delta;
+  oat_data_end_ += delta;
+  oat_file_end_ += delta;
+  image_roots_ += delta;
+  patch_delta_ += delta;
+}
+
 bool ImageHeader::IsValid() const {
   if (memcmp(magic_, kImageMagic, sizeof(kImageMagic)) != 0) {
     return false;
@@ -65,6 +77,25 @@
   if (memcmp(version_, kImageVersion, sizeof(kImageVersion)) != 0) {
     return false;
   }
+  // Unsigned so wraparound is well defined.
+  if (image_begin_ >= image_begin_ + image_size_) {
+    return false;
+  }
+  if (oat_file_begin_ > oat_file_end_) {
+    return false;
+  }
+  if (oat_data_begin_ > oat_data_end_) {
+    return false;
+  }
+  if (oat_file_begin_ >= oat_data_begin_) {
+    return false;
+  }
+  if (image_roots_ <= image_begin_ || oat_file_begin_ <= image_roots_) {
+    return false;
+  }
+  if (!IsAligned<kPageSize>(patch_delta_)) {
+    return false;
+  }
   return true;
 }
 
diff --git a/runtime/image.h b/runtime/image.h
index abe1ad8..424a40b 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -84,6 +84,10 @@
     return reinterpret_cast<byte*>(oat_file_end_);
   }
 
+  off_t GetPatchDelta() const {
+    return patch_delta_;
+  }
+
   size_t GetBitmapOffset() const {
     return RoundUp(image_size_, kPageSize);
   }
@@ -112,10 +116,11 @@
 
   mirror::Object* GetImageRoot(ImageRoot image_root) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- private:
   mirror::ObjectArray<mirror::Object>* GetImageRoots() const;
 
+  void RelocateImage(off_t delta);
+
+ private:
   static const byte kImageMagic[4];
   static const byte kImageVersion[4];
 
@@ -150,11 +155,13 @@
   // .so files. Used for positioning a following alloc spaces.
   uint32_t oat_file_end_;
 
+  // The total delta that this image has been patched.
+  int32_t patch_delta_;
+
   // Absolute address of an Object[] of objects needed to reinitialize from an image.
   uint32_t image_roots_;
 
   friend class ImageWriter;
-  friend class ImageDumper;  // For GetImageRoots()
 };
 
 }  // namespace art
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index eae0418..70253af 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -60,6 +60,12 @@
 
   ~OatFile();
 
+  ElfFile* GetElfFile() const {
+    CHECK_NE(reinterpret_cast<uintptr_t>(elf_file_.get()), reinterpret_cast<uintptr_t>(nullptr))
+        << "Cannot get an elf file from " << GetLocation();
+    return elf_file_.get();
+  }
+
   const std::string& GetLocation() const {
     return location_;
   }
@@ -227,6 +233,9 @@
     return End() - Begin();
   }
 
+  const byte* Begin() const;
+  const byte* End() const;
+
  private:
   static void CheckLocation(const std::string& location);
 
@@ -248,9 +257,6 @@
                    std::string* error_msg);
   bool Setup(std::string* error_msg);
 
-  const byte* Begin() const;
-  const byte* End() const;
-
   // The oat file name.
   //
   // The image will embed this to link its associated oat file.
diff --git a/runtime/utils.h b/runtime/utils.h
index eb79968..448c591 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -19,6 +19,7 @@
 
 #include <pthread.h>
 
+#include <limits>
 #include <string>
 #include <vector>
 
@@ -50,6 +51,34 @@
   kTimeUnitSecond,
 };
 
+template <typename T>
+bool ParseUint(const char *in, T* out) {
+  char* end;
+  unsigned long long int result = strtoull(in, &end, 0);  // NOLINT(runtime/int)
+  if (in == end || *end != '\0') {
+    return false;
+  }
+  if (std::numeric_limits<T>::max() < result) {
+    return false;
+  }
+  *out = static_cast<T>(result);
+  return true;
+}
+
+template <typename T>
+bool ParseInt(const char* in, T* out) {
+  char* end;
+  long long int result = strtoll(in, &end, 0);  // NOLINT(runtime/int)
+  if (in == end || *end != '\0') {
+    return false;
+  }
+  if (result < std::numeric_limits<T>::min() || std::numeric_limits<T>::max() < result) {
+    return false;
+  }
+  *out = static_cast<T>(result);
+  return true;
+}
+
 template<typename T>
 static constexpr bool IsPowerOfTwo(T x) {
   return (x & (x - 1)) == 0;