Add symbolizer option to generate debug information only.

There is no need to copy the .rodata and .text sections since the
consumers can get their data form the original ELF file. We mark
those section as SHT_NOBITS instead, which is the standard way to
create ELF file with separate debug information only.

The new option is called --only-keep-debug and it essentially has
the same effect as --only-keep-debug option for "strip" command.

Change-Id: I4f7488c04bbad86288beeda11c3bf295890e740d
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index ef44a6f..26ab281 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -841,7 +841,7 @@
       load.p_type    = PT_LOAD;
       load.p_flags   = PF_R;
       load.p_offset  = load.p_vaddr = load.p_paddr = 0;
-      load.p_filesz  = load.p_memsz = sections_[0]->header_.sh_offset;
+      load.p_filesz  = load.p_memsz = sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * kMaxProgramHeaders;
       load.p_align   = kPageSize;
       phdrs.push_back(load);
     }
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 0e17fc2..00a691b 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -101,9 +101,11 @@
 template <typename ElfTypes>
 class OatSymbolizer FINAL {
  public:
-  OatSymbolizer(const OatFile* oat_file, const std::string& output_name) :
-      oat_file_(oat_file), builder_(nullptr),
-      output_name_(output_name.empty() ? "symbolized.oat" : output_name) {
+  OatSymbolizer(const OatFile* oat_file, const std::string& output_name, bool no_bits) :
+      oat_file_(oat_file),
+      builder_(nullptr),
+      output_name_(output_name.empty() ? "symbolized.oat" : output_name),
+      no_bits_(no_bits) {
   }
 
   typedef void (OatSymbolizer::*Callback)(const DexFile::ClassDef&,
@@ -132,17 +134,25 @@
     auto* strtab = builder_->GetStrTab();
     auto* symtab = builder_->GetSymTab();
 
-    rodata->Start();
     const uint8_t* rodata_begin = oat_file_->Begin();
     const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
-    rodata->WriteFully(rodata_begin, rodata_size);
-    rodata->End();
+    if (no_bits_) {
+      rodata->WriteNoBitsSection(rodata_size);
+    } else {
+      rodata->Start();
+      rodata->WriteFully(rodata_begin, rodata_size);
+      rodata->End();
+    }
 
-    text->Start();
     const uint8_t* text_begin = oat_file_->Begin() + rodata_size;
     const size_t text_size = oat_file_->End() - text_begin;
-    text->WriteFully(text_begin, text_size);
-    text->End();
+    if (no_bits_) {
+      text->WriteNoBitsSection(text_size);
+    } else {
+      text->Start();
+      text->WriteFully(text_begin, text_size);
+      text->End();
+    }
 
     if (oat_file_->BssSize() != 0) {
       bss->WriteNoBitsSection(oat_file_->BssSize());
@@ -364,6 +374,7 @@
   std::unique_ptr<ElfBuilder<ElfTypes> > builder_;
   std::unordered_map<uint32_t, uint32_t> state_;
   const std::string output_name_;
+  bool no_bits_;
 };
 
 class OatDumperOptions {
@@ -2550,7 +2561,7 @@
   }
 }
 
-static int SymbolizeOat(const char* oat_filename, std::string& output_name) {
+static int SymbolizeOat(const char* oat_filename, std::string& output_name, bool no_bits) {
   std::string error_msg;
   OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, nullptr, false,
                                     nullptr, &error_msg);
@@ -2563,10 +2574,10 @@
   // Try to produce an ELF file of the same type. This is finicky, as we have used 32-bit ELF
   // files for 64-bit code in the past.
   if (Is64BitInstructionSet(oat_file->GetOatHeader().GetInstructionSet())) {
-    OatSymbolizer<ElfTypes64> oat_symbolizer(oat_file, output_name);
+    OatSymbolizer<ElfTypes64> oat_symbolizer(oat_file, output_name, no_bits);
     result = oat_symbolizer.Symbolize();
   } else {
-    OatSymbolizer<ElfTypes32> oat_symbolizer(oat_file, output_name);
+    OatSymbolizer<ElfTypes32> oat_symbolizer(oat_file, output_name, no_bits);
     result = oat_symbolizer.Symbolize();
   }
   if (!result) {
@@ -2609,6 +2620,8 @@
     } else if (option.starts_with("--symbolize=")) {
       oat_filename_ = option.substr(strlen("--symbolize=")).data();
       symbolize_ = true;
+    } else if (option.starts_with("--only-keep-debug")) {
+      only_keep_debug_ = true;
     } else if (option.starts_with("--class-filter=")) {
       class_filter_ = option.substr(strlen("--class-filter=")).data();
     } else if (option.starts_with("--method-filter=")) {
@@ -2703,6 +2716,10 @@
         "  --symbolize=<file.oat>: output a copy of file.oat with elf symbols included.\n"
         "      Example: --symbolize=/system/framework/boot.oat\n"
         "\n"
+        "  --only-keep-debug<file.oat>: Modifies the behaviour of --symbolize so that\n"
+        "      .rodata and .text sections are omitted in the output file to save space.\n"
+        "      Example: --symbolize=/system/framework/boot.oat --only-keep-debug\n"
+        "\n"
         "  --class-filter=<class name>: only dumps classes that contain the filter.\n"
         "      Example: --class-filter=com.example.foo\n"
         "\n"
@@ -2732,6 +2749,7 @@
   bool dump_code_info_stack_maps_ = false;
   bool disassemble_code_ = true;
   bool symbolize_ = false;
+  bool only_keep_debug_ = false;
   bool list_classes_ = false;
   bool list_methods_ = false;
   bool dump_header_only_ = false;
@@ -2772,7 +2790,12 @@
     MemMap::Init();
 
     if (args_->symbolize_) {
-      return SymbolizeOat(args_->oat_filename_, args_->output_name_) == EXIT_SUCCESS;
+      // ELF has special kind of section called SHT_NOBITS which allows us to create
+      // sections which exist but their data is omitted from the ELF file to save space.
+      // This is what "strip --only-keep-debug" does when it creates separate ELF file
+      // with only debug data. We use it in similar way to exclude .rodata and .text.
+      bool no_bits = args_->only_keep_debug_;
+      return SymbolizeOat(args_->oat_filename_, args_->output_name_, no_bits) == EXIT_SUCCESS;
     } else {
       return DumpOat(nullptr,
                      args_->oat_filename_,