Write ELF image to Oat file.

(cherry picked from commit 1c84f1fd7570974bec8660cd17e0118be529afce)

Change-Id: I322579095009a09ab9ad8d2e7d7c309a5530718c
diff --git a/src/oat.cc b/src/oat.cc
index d8d01df..b3333c2 100644
--- a/src/oat.cc
+++ b/src/oat.cc
@@ -29,6 +29,7 @@
 
 OatHeader::OatHeader(InstructionSet instruction_set,
                      const std::vector<const DexFile*>* dex_files,
+                     uint32_t elf_image_count,
                      uint32_t image_file_location_checksum,
                      const std::string& image_file_location) {
   memcpy(magic_, kOatMagic, sizeof(kOatMagic));
@@ -42,6 +43,9 @@
   dex_file_count_ = dex_files->size();
   UpdateChecksum(&dex_file_count_, sizeof(dex_file_count_));
 
+  elf_image_count_ = elf_image_count;
+  UpdateChecksum(&elf_image_count_, sizeof(elf_image_count_));
+
   image_file_location_checksum_ = image_file_location_checksum;
   UpdateChecksum(&image_file_location_checksum_, sizeof(image_file_location_checksum_));
 
@@ -49,6 +53,7 @@
   UpdateChecksum(&image_file_location_size_, sizeof(image_file_location_size_));
   UpdateChecksum(image_file_location.data(), image_file_location_size_);
 
+  elf_image_table_offset_ = 0;
   executable_offset_ = 0;
 }
 
@@ -72,6 +77,16 @@
   return dex_file_count_;
 }
 
+uint32_t OatHeader::GetElfImageCount() const {
+  DCHECK(IsValid());
+  return elf_image_count_;
+}
+
+uint32_t OatHeader::GetElfImageTableOffset() const {
+  DCHECK(IsValid());
+  return elf_image_table_offset_;
+}
+
 uint32_t OatHeader::GetChecksum() const {
   CHECK(IsValid());
   return adler32_checksum_;
@@ -116,6 +131,12 @@
                      GetImageFileLocationSize());
 }
 
+void OatHeader::SetElfImageTableOffset(uint32_t elf_image_table_offset) {
+  DCHECK(IsValid());
+  elf_image_table_offset_ = elf_image_table_offset;
+  UpdateChecksum(&elf_image_table_offset_, sizeof(elf_image_table_offset_));
+}
+
 void OatHeader::SetExecutableOffset(uint32_t executable_offset) {
   DCHECK_ALIGNED(executable_offset, kPageSize);
   CHECK_GT(executable_offset, sizeof(OatHeader));
diff --git a/src/oat.h b/src/oat.h
index 25a4373..a71a75b 100644
--- a/src/oat.h
+++ b/src/oat.h
@@ -30,6 +30,7 @@
   OatHeader();
   OatHeader(InstructionSet instruction_set,
             const std::vector<const DexFile*>* dex_files,
+            uint32_t elf_image_count,
             uint32_t image_file_location_checksum,
             const std::string& image_file_location);
 
@@ -38,8 +39,11 @@
   uint32_t GetChecksum() const;
   void UpdateChecksum(const void* data, size_t length);
   uint32_t GetDexFileCount() const;
+  uint32_t GetElfImageCount() const;
+  uint32_t GetElfImageTableOffset() const;
   uint32_t GetExecutableOffset() const;
   InstructionSet GetInstructionSet() const;
+  void SetElfImageTableOffset(uint32_t elf_image_offset);
   void SetExecutableOffset(uint32_t executable_offset);
   uint32_t GetImageFileLocationChecksum() const;
   uint32_t GetImageFileLocationSize() const;
@@ -56,6 +60,8 @@
 
   InstructionSet instruction_set_;
   uint32_t dex_file_count_;
+  uint32_t elf_image_count_;
+  uint32_t elf_image_table_offset_;
   uint32_t executable_offset_;
 
   uint32_t image_file_location_checksum_;
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 8e127deb..df809d5 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -18,11 +18,14 @@
 
 #include "class_linker.h"
 #include "class_loader.h"
+#include "elf_image.h"
 #include "file.h"
 #include "os.h"
 #include "space.h"
 #include "stl_util.h"
 
+#include <zlib.h>
+
 namespace art {
 
 bool OatWriter::Create(File* file,
@@ -49,12 +52,15 @@
   image_file_location_checksum_ = image_file_location_checksum;
   image_file_location_ = image_file_location;
   dex_files_ = &dex_files;
+  elf_images_ = compiler_->GetElfImages();
   oat_header_ = NULL;
   executable_offset_padding_length_ = 0;
 
   size_t offset = InitOatHeader();
   offset = InitOatDexFiles(offset);
   offset = InitDexFiles(offset);
+  offset = InitOatElfImages(offset);
+  offset = InitElfImages(offset);
   offset = InitOatClasses(offset);
   offset = InitOatCode(offset);
   offset = InitOatCodeDexFiles(offset);
@@ -65,6 +71,7 @@
 OatWriter::~OatWriter() {
   delete oat_header_;
   STLDeleteElements(&oat_dex_files_);
+  STLDeleteElements(&oat_elf_images_);
   STLDeleteElements(&oat_classes_);
 }
 
@@ -72,6 +79,7 @@
   // create the OatHeader
   oat_header_ = new OatHeader(compiler_->GetInstructionSet(),
                               dex_files_,
+                              elf_images_.size(),
                               image_file_location_checksum_,
                               image_file_location_);
   size_t offset = sizeof(*oat_header_);
@@ -106,6 +114,29 @@
   return offset;
 }
 
+size_t OatWriter::InitOatElfImages(size_t offset) {
+  // Offset to ELF image table should be rounded up to 4-byte aligned, so that
+  // we can read the uint32_t directly.
+  offset = RoundUp(offset, 4);
+  oat_header_->SetElfImageTableOffset(offset);
+
+  for (size_t i = 0, n = elf_images_.size(); i < n; ++i) {
+    OatElfImage* oat_elf_image = new OatElfImage(elf_images_[i]);
+    oat_elf_images_.push_back(oat_elf_image);
+    offset += oat_elf_image->SizeOf();
+  }
+  return offset;
+}
+
+size_t OatWriter::InitElfImages(size_t offset) {
+  for (size_t i = 0; i < oat_elf_images_.size(); ++i) {
+    offset = RoundUp(offset, 4);
+    oat_elf_images_[i]->SetElfOffset(offset);
+    offset += oat_elf_images_[i]->GetElfSize();
+  }
+  return offset;
+}
+
 size_t OatWriter::InitOatClasses(size_t offset) {
   // create the OatClasses
   // calculate the offsets within OatDexFiles to OatClasses
@@ -424,6 +455,25 @@
       return false;
     }
   }
+  for (size_t i = 0; i != oat_elf_images_.size(); ++i) {
+    if (!oat_elf_images_[i]->Write(file)) {
+      PLOG(ERROR) << "Failed to write oat elf information to " << file->name();
+      return false;
+    }
+  }
+  for (size_t i = 0; i != oat_elf_images_.size(); ++i) {
+    uint32_t expected_offset = oat_elf_images_[i]->GetElfOffset();
+    off_t actual_offset = lseek(file->Fd(), expected_offset, SEEK_SET);
+    if (static_cast<uint32_t>(actual_offset) != expected_offset) {
+      PLOG(ERROR) << "Failed to seek to dex file section."
+                  << " Actual: " << actual_offset
+                  << " Expected: " << expected_offset;
+      return false;
+    }
+    if (!oat_elf_images_[i]->WriteElfImage(file)) {
+      return false;
+    }
+  }
   for (size_t i = 0; i != oat_classes_.size(); ++i) {
     if (!oat_classes_[i]->Write(file)) {
       PLOG(ERROR) << "Failed to write oat methods information to " << file->name();
@@ -772,4 +822,48 @@
   return true;
 }
 
+OatWriter::OatElfImage::OatElfImage(const ElfImage& image)
+    : elf_offset_(0), elf_size_(image.size()), elf_addr_(image.begin()) {
+}
+
+size_t OatWriter::OatElfImage::SizeOf() const {
+  return (sizeof(elf_offset_) + sizeof(elf_size_));
+}
+
+uint32_t OatWriter::OatElfImage::GetElfSize() const {
+  return elf_size_;
+}
+
+uint32_t OatWriter::OatElfImage::GetElfOffset() const {
+  DCHECK_NE(elf_offset_, 0U);
+  return elf_offset_;
+}
+
+void OatWriter::OatElfImage::SetElfOffset(uint32_t offset) {
+  DCHECK_NE(offset, 0U);
+  DCHECK((offset & 0x3LU) == 0);
+  elf_offset_ = offset;
+}
+
+bool OatWriter::OatElfImage::Write(File* file) const {
+  DCHECK_NE(elf_offset_, 0U);
+  if (!file->WriteFully(&elf_offset_, sizeof(elf_offset_))) {
+    PLOG(ERROR) << "Failed to write ELF offset to " << file->name();
+    return false;
+  }
+  if (!file->WriteFully(&elf_size_, sizeof(elf_size_))) {
+    PLOG(ERROR) << "Failed to write ELF size to " << file->name();
+    return false;
+  }
+  return true;
+}
+
+bool OatWriter::OatElfImage::WriteElfImage(File* file) const {
+  if (!file->WriteFully(elf_addr_, elf_size_)) {
+    PLOG(ERROR) << "Failed to write ELF image to " << file->name();
+    return false;
+  }
+  return true;
+}
+
 }  // namespace art
diff --git a/src/oat_writer.h b/src/oat_writer.h
index c3a8ff6..e0d257f 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -48,6 +48,16 @@
 // ...
 // OatClass[C]
 //
+// OatElfImage[0]    one OatElfImage for each ELF image
+// OatElfImage[1]    contains the size, checksum, and offset to the ELF image.
+// ...
+// OatElfImage[E]
+//
+// ELF[0]
+// ELF[1]
+// ...
+// ELF[E]
+//
 // padding           if necessary so that the following code will be page aligned
 //
 // CompiledMethod    one variable sized blob with the contents of each CompiledMethod
@@ -82,6 +92,8 @@
   size_t InitOatDexFiles(size_t offset);
   size_t InitDexFiles(size_t offset);
   size_t InitOatClasses(size_t offset);
+  size_t InitOatElfImages(size_t offset);
+  size_t InitElfImages(size_t offset);
   size_t InitOatCode(size_t offset);
   size_t InitOatCodeDexFiles(size_t offset);
   size_t InitOatCodeDexFile(size_t offset,
@@ -143,6 +155,25 @@
     DISALLOW_COPY_AND_ASSIGN(OatClass);
   };
 
+  class OatElfImage {
+   public:
+    explicit OatElfImage(const ElfImage& elf_image);
+    size_t SizeOf() const;
+    uint32_t GetElfSize() const;
+    uint32_t GetElfOffset() const;
+    void SetElfOffset(uint32_t offset);
+    bool Write(File* file) const;
+    bool WriteElfImage(File* file) const;
+
+   private:
+    // data to write
+    uint32_t elf_offset_;
+    const uint32_t elf_size_;
+
+    const byte* const elf_addr_;
+    DISALLOW_COPY_AND_ASSIGN(OatElfImage);
+  };
+
   const Compiler* compiler_;
 
   // TODO: remove the ClassLoader when the code storage moves out of Method
@@ -151,6 +182,8 @@
   // note OatFile does not take ownership of the DexFiles
   const std::vector<const DexFile*>* dex_files_;
 
+  std::vector<ElfImage> elf_images_;
+
   // dependency on the image
   uint32_t image_file_location_checksum_;
   std::string image_file_location_;
@@ -159,6 +192,7 @@
   OatHeader* oat_header_;
   std::vector<OatDexFile*> oat_dex_files_;
   std::vector<OatClass*> oat_classes_;
+  std::vector<OatElfImage*> oat_elf_images_;
   uint32_t executable_offset_padding_length_;
 
   template <class T> struct MapCompare {