Merge "Add symbolizer option to generate debug information only."
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 3ed5766..79fde5e 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -103,9 +103,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) {
   }
 
   bool Symbolize() {
@@ -124,17 +126,25 @@
     auto* text = builder_->GetText();
     auto* bss = builder_->GetBss();
 
-    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());
@@ -264,6 +274,7 @@
   std::vector<debug::MethodDebugInfo> method_debug_infos_;
   std::unordered_set<uint32_t> seen_offsets_;
   const std::string output_name_;
+  bool no_bits_;
 };
 
 class OatDumperOptions {
@@ -2450,7 +2461,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);
@@ -2463,10 +2474,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) {
@@ -2509,6 +2520,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=")) {
@@ -2603,6 +2616,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"
@@ -2632,6 +2649,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;
@@ -2672,7 +2690,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_,