Add ELF extractor to oatdump.

Change-Id: Ib2d09c07e1b271e033418501b690150cb2063980
diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc
index d548976..b73e997 100644
--- a/src/compiler_llvm/compilation_unit.cc
+++ b/src/compiler_llvm/compilation_unit.cc
@@ -200,7 +200,7 @@
   llvm::OwningPtr<llvm::tool_output_file> out_file(
     new llvm::tool_output_file(elf_filename_.c_str(), errmsg,
                                llvm::raw_fd_ostream::F_Binary));
-  out_file->os().write(reinterpret_cast<const char*>(GetElfImage()), GetElfSize());
+  out_file->os().write(elf_image_.data(), elf_image_.size());
   out_file->keep();
 
   LOG(INFO) << "ELF: " << elf_filename_ << " (done)";
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 6ae502c..937448c 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -61,6 +61,7 @@
 
 OatFile::~OatFile() {
   STLDeleteValues(&oat_dex_files_);
+  STLDeleteElements(&oat_elf_images_);
 }
 
 bool OatFile::Map(File& file, byte* requested_base, bool writable) {
@@ -160,6 +161,20 @@
                                                        methods_offsets_pointer);
   }
 
+  oat = map->Begin() + oat_header.GetElfImageTableOffset();
+  CHECK((reinterpret_cast<uintptr_t>(oat) & 0x3) == 0);
+
+  for (uint32_t i = 0, end = oat_header.GetElfImageCount(); i < end; ++i) {
+    uint32_t elf_offset = *reinterpret_cast<const uint32_t*>(oat);
+    oat += sizeof(uint32_t);
+
+    uint32_t elf_size = *reinterpret_cast<const uint32_t*>(oat);
+    oat += sizeof(uint32_t);
+
+    oat_elf_images_.push_back(
+        new OatElfImage(this, map->Begin() + elf_offset, elf_size));
+  }
+
   mem_map_.reset(map.release());
   return true;
 }
@@ -314,4 +329,10 @@
   method->SetOatInvokeStubOffset(GetInvokeStubOffset());
 }
 
+OatFile::OatElfImage::OatElfImage(const OatFile* oat_file,
+                                  const byte* addr,
+                                  uint32_t size)
+    : oat_file_(oat_file), elf_addr_(addr), elf_size_(size) {
+}
+
 }  // namespace art
diff --git a/src/oat_file.h b/src/oat_file.h
index d75c7c7..2d0f6f8 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -211,10 +211,39 @@
     DISALLOW_COPY_AND_ASSIGN(OatDexFile);
   };
 
+  class OatElfImage {
+   public:
+    const byte* begin() const {
+      return elf_addr_;
+    }
+
+    const byte* end() const {
+      return (elf_addr_ + elf_size_);
+    }
+
+    size_t size() const {
+      return elf_size_;
+    }
+
+   private:
+    OatElfImage(const OatFile* oat_file, const byte* addr, uint32_t size);
+
+    const OatFile* oat_file_;
+    const byte* elf_addr_;
+    uint32_t elf_size_;
+
+    friend class OatFile;
+    DISALLOW_COPY_AND_ASSIGN(OatElfImage);
+  };
+
   const OatDexFile* GetOatDexFile(const std::string& dex_file_location,
                                   bool warn_if_not_found = true) const;
   std::vector<const OatDexFile*> GetOatDexFiles() const;
 
+  const OatElfImage* GetOatElfImage(size_t i) const {
+    return oat_elf_images_[i];
+  }
+
   size_t Size() const {
     return End() - Begin();
   }
@@ -237,6 +266,8 @@
   typedef std::map<std::string, const OatDexFile*> Table;
   Table oat_dex_files_;
 
+  std::vector<OatElfImage*> oat_elf_images_;
+
   friend class OatClass;
   friend class OatDexFile;
   friend class OatDumper;  // For GetBase and GetLimit
diff --git a/src/oatdump.cc b/src/oatdump.cc
index f38f878..42f8e2a 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -57,6 +57,11 @@
           "      Example: --boot-image=/system/framework/boot.art\n"
           "\n");
   fprintf(stderr,
+          "  --extract-elf-to=<file.elf>: provide the prefix of the filename for\n"
+          "      the output ELF files.\n"
+          "      Example: --extract-elf-to=output.elf\n"
+          "\n");
+  fprintf(stderr,
           "  --host-prefix may be used to translate host paths to target paths during\n"
           "      cross compilation.\n"
           "      Example: --host-prefix=out/target/product/crespo\n"
@@ -108,6 +113,9 @@
     os << "DEX FILE COUNT:\n";
     os << oat_header.GetDexFileCount() << "\n\n";
 
+    os << "ELF IMAGE COUNT:\n";
+    os << oat_header.GetElfImageCount() << "\n\n";
+
     os << "EXECUTABLE OFFSET:\n";
     os << StringPrintf("0x%08x\n\n", oat_header.GetExecutableOffset());
 
@@ -1086,6 +1094,7 @@
   const char* oat_filename = NULL;
   const char* image_filename = NULL;
   const char* boot_image_filename = NULL;
+  std::string elf_filename_prefix;
   UniquePtr<std::string> host_prefix;
   std::ostream* os = &std::cout;
   UniquePtr<std::ofstream> out;
@@ -1098,6 +1107,8 @@
       image_filename = option.substr(strlen("--image=")).data();
     } else if (option.starts_with("--boot-image=")) {
       boot_image_filename = option.substr(strlen("--boot-image=")).data();
+    } else if (option.starts_with("--extract-elf-to=")) {
+      elf_filename_prefix = option.substr(strlen("--extract-elf-to=")).data();
     } else if (option.starts_with("--host-prefix=")) {
       host_prefix.reset(new std::string(option.substr(strlen("--host-prefix=")).data()));
     } else if (option.starts_with("--output=")) {
@@ -1141,6 +1152,23 @@
     }
     OatDumper oat_dumper(*host_prefix.get(), *oat_file);
     oat_dumper.Dump(*os);
+
+    if (!elf_filename_prefix.empty()) {
+      uint32_t elf_image_count = oat_file->GetOatHeader().GetElfImageCount();
+      for (uint32_t i = 0; i < elf_image_count; ++i) {
+        const OatFile::OatElfImage* elf_image = oat_file->GetOatElfImage(i);
+
+        std::string elf_filename(
+            StringPrintf("%s-%u", elf_filename_prefix.c_str(), i));
+
+        UniquePtr<File> elf_file(OS::OpenFile(elf_filename.c_str(), true));
+
+        if (!elf_file->WriteFully(elf_image->begin(), elf_image->size())) {
+          fprintf(stderr, "Failed to write ELF image to: %s\n",
+                  elf_filename.c_str());
+        }
+      }
+    }
     return EXIT_SUCCESS;
   }