Revert "Revert "Add option to generate compressed backtrace info.""

This reverts commit 8546cc9aeb05e866e1fb6a9e4130d53ea330baa8.

Change-Id: I676fdf9af27fa3b16fa8921778ff8832ab8c437d
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index d68835a..af6f91f 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -1076,7 +1076,7 @@
       pc_rel_temp_(nullptr),
       dex_cache_arrays_min_offset_(std::numeric_limits<uint32_t>::max()),
       cfi_(&last_lir_insn_,
-           cu->compiler_driver->GetCompilerOptions().GetGenerateDebugInfo(),
+           cu->compiler_driver->GetCompilerOptions().GenerateAnyDebugInfo(),
            arena),
       in_to_reg_storage_mapping_(arena) {
   switch_tables_.reserve(4);
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index 2644528..e0b1d8b 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -37,6 +37,7 @@
       debuggable_(false),
       native_debuggable_(kDefaultNativeDebuggable),
       generate_debug_info_(kDefaultGenerateDebugInfo),
+      generate_mini_debug_info_(kDefaultGenerateMiniDebugInfo),
       implicit_null_checks_(true),
       implicit_so_checks_(true),
       implicit_suspend_checks_(false),
@@ -91,6 +92,7 @@
     debuggable_(debuggable),
     native_debuggable_(kDefaultNativeDebuggable),
     generate_debug_info_(generate_debug_info),
+    generate_mini_debug_info_(kDefaultGenerateMiniDebugInfo),
     implicit_null_checks_(implicit_null_checks),
     implicit_so_checks_(implicit_so_checks),
     implicit_suspend_checks_(implicit_suspend_checks),
@@ -215,6 +217,10 @@
     generate_debug_info_ = true;
   } else if (option == "--no-generate-debug-info") {
     generate_debug_info_ = false;
+  } else if (option == "--generate-mini-debug-info") {
+    generate_mini_debug_info_ = true;
+  } else if (option == "--no-generate-mini-debug-info") {
+    generate_mini_debug_info_ = false;
   } else if (option == "--debuggable") {
     debuggable_ = true;
   } else if (option == "--native-debuggable") {
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index d47fc2a..5294af8 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -51,6 +51,7 @@
   static constexpr double kDefaultTopKProfileThreshold = 90.0;
   static const bool kDefaultNativeDebuggable = false;
   static const bool kDefaultGenerateDebugInfo = false;
+  static const bool kDefaultGenerateMiniDebugInfo = false;
   static const bool kDefaultIncludePatchInformation = false;
   static const size_t kDefaultInlineDepthLimit = 3;
   static const size_t kDefaultInlineMaxCodeUnits = 32;
@@ -170,10 +171,20 @@
     return native_debuggable_;
   }
 
+  // This flag controls whether the compiler collects debugging information.
+  // The other flags control how the information is written to disk.
+  bool GenerateAnyDebugInfo() const {
+    return GetGenerateDebugInfo() || GetGenerateMiniDebugInfo();
+  }
+
   bool GetGenerateDebugInfo() const {
     return generate_debug_info_;
   }
 
+  bool GetGenerateMiniDebugInfo() const {
+    return generate_mini_debug_info_;
+  }
+
   bool GetImplicitNullChecks() const {
     return implicit_null_checks_;
   }
@@ -266,6 +277,7 @@
   bool debuggable_;
   bool native_debuggable_;
   bool generate_debug_info_;
+  bool generate_mini_debug_info_;
   bool implicit_null_checks_;
   bool implicit_so_checks_;
   bool implicit_suspend_checks_;
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 46484b1..3d24d19 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -165,10 +165,15 @@
       }
     }
 
-    // Set desired allocation size for .bss section.
-    void SetSize(Elf_Word size) {
-      CHECK_EQ(header_.sh_type, (Elf_Word)SHT_NOBITS);
+    // Write this section as "NOBITS" section. (used for the .bss section)
+    // This means that the ELF file does not contain the initial data for this section
+    // and it will be zero-initialized when the ELF file is loaded in the running program.
+    void WriteNoBitsSection(Elf_Word size) {
+      DCHECK_NE(header_.sh_flags & SHF_ALLOC, 0u);
+      Start();
+      header_.sh_type = SHT_NOBITS;
       header_.sh_size = size;
+      End();
     }
 
     // This function always succeeds to simplify code.
@@ -346,6 +351,12 @@
     other_sections_.push_back(std::move(s));
   }
 
+  // Set where the next section will be allocated in the virtual address space.
+  void SetVirtualAddress(Elf_Addr address) {
+    DCHECK_GE(address, virtual_address_);
+    virtual_address_ = address;
+  }
+
   void Start() {
     // Reserve space for ELF header and program headers.
     // We do not know the number of headers until later, so
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index a64c9f1..94e5d76 100644
--- a/compiler/elf_writer_debug.cc
+++ b/compiler/elf_writer_debug.cc
@@ -40,6 +40,11 @@
 #include "stack_map.h"
 #include "utils.h"
 
+// liblzma.
+#include "XzEnc.h"
+#include "7zCrc.h"
+#include "XzCrc64.h"
+
 namespace art {
 namespace dwarf {
 
@@ -1405,6 +1410,76 @@
   WriteDebugSections(builder, method_infos);
 }
 
+static void XzCompress(const std::vector<uint8_t>* src, std::vector<uint8_t>* dst) {
+  // Configure the compression library.
+  CrcGenerateTable();
+  Crc64GenerateTable();
+  CLzma2EncProps lzma2Props;
+  Lzma2EncProps_Init(&lzma2Props);
+  lzma2Props.lzmaProps.level = 1;  // Fast compression.
+  Lzma2EncProps_Normalize(&lzma2Props);
+  CXzProps props;
+  XzProps_Init(&props);
+  props.lzma2Props = &lzma2Props;
+  // Implement the required interface for communication (written in C so no virtual methods).
+  struct XzCallbacks : public ISeqInStream, public ISeqOutStream, public ICompressProgress {
+    static SRes ReadImpl(void* p, void* buf, size_t* size) {
+      auto* ctx = static_cast<XzCallbacks*>(reinterpret_cast<ISeqInStream*>(p));
+      *size = std::min(*size, ctx->src_->size() - ctx->src_pos_);
+      memcpy(buf, ctx->src_->data() + ctx->src_pos_, *size);
+      ctx->src_pos_ += *size;
+      return SZ_OK;
+    }
+    static size_t WriteImpl(void* p, const void* buf, size_t size) {
+      auto* ctx = static_cast<XzCallbacks*>(reinterpret_cast<ISeqOutStream*>(p));
+      const uint8_t* buffer = reinterpret_cast<const uint8_t*>(buf);
+      ctx->dst_->insert(ctx->dst_->end(), buffer, buffer + size);
+      return size;
+    }
+    static SRes ProgressImpl(void* , UInt64, UInt64) {
+      return SZ_OK;
+    }
+    size_t src_pos_;
+    const std::vector<uint8_t>* src_;
+    std::vector<uint8_t>* dst_;
+  };
+  XzCallbacks callbacks;
+  callbacks.Read = XzCallbacks::ReadImpl;
+  callbacks.Write = XzCallbacks::WriteImpl;
+  callbacks.Progress = XzCallbacks::ProgressImpl;
+  callbacks.src_pos_ = 0;
+  callbacks.src_ = src;
+  callbacks.dst_ = dst;
+  // Compress.
+  SRes res = Xz_Encode(&callbacks, &callbacks, &props, &callbacks);
+  CHECK_EQ(res, SZ_OK);
+}
+
+template <typename ElfTypes>
+void WriteMiniDebugInfo(ElfBuilder<ElfTypes>* parent_builder,
+                        const ArrayRef<const MethodDebugInfo>& method_infos) {
+  const InstructionSet isa = parent_builder->GetIsa();
+  std::vector<uint8_t> buffer;
+  buffer.reserve(KB);
+  VectorOutputStream out("Mini-debug-info ELF file", &buffer);
+  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out));
+  builder->Start();
+  // Write .rodata and .text as NOBITS sections.
+  // This allows tools to detect virtual address relocation of the parent ELF file.
+  builder->SetVirtualAddress(parent_builder->GetRoData()->GetAddress());
+  builder->GetRoData()->WriteNoBitsSection(parent_builder->GetRoData()->GetSize());
+  builder->SetVirtualAddress(parent_builder->GetText()->GetAddress());
+  builder->GetText()->WriteNoBitsSection(parent_builder->GetText()->GetSize());
+  WriteDebugSymbols(builder.get(), method_infos);
+  WriteCFISection(builder.get(), method_infos, DW_DEBUG_FRAME_FORMAT);
+  builder->End();
+  CHECK(builder->Good());
+  std::vector<uint8_t> compressed_buffer;
+  compressed_buffer.reserve(buffer.size() / 4);
+  XzCompress(&buffer, &compressed_buffer);
+  parent_builder->WriteSection(".gnu_debugdata", &compressed_buffer);
+}
+
 template <typename ElfTypes>
 static ArrayRef<const uint8_t> WriteDebugElfFileForMethodInternal(
     const dwarf::MethodDebugInfo& method_info) {
@@ -1477,6 +1552,12 @@
     ElfBuilder<ElfTypes64>* builder,
     const ArrayRef<const MethodDebugInfo>& method_infos,
     CFIFormat cfi_format);
+template void WriteMiniDebugInfo<ElfTypes32>(
+    ElfBuilder<ElfTypes32>* builder,
+    const ArrayRef<const MethodDebugInfo>& method_infos);
+template void WriteMiniDebugInfo<ElfTypes64>(
+    ElfBuilder<ElfTypes64>* builder,
+    const ArrayRef<const MethodDebugInfo>& method_infos);
 
 }  // namespace dwarf
 }  // namespace art
diff --git a/compiler/elf_writer_debug.h b/compiler/elf_writer_debug.h
index e4bc856..e19da08 100644
--- a/compiler/elf_writer_debug.h
+++ b/compiler/elf_writer_debug.h
@@ -35,6 +35,10 @@
                     const ArrayRef<const MethodDebugInfo>& method_infos,
                     CFIFormat cfi_format);
 
+template <typename ElfTypes>
+void WriteMiniDebugInfo(ElfBuilder<ElfTypes>* builder,
+                        const ArrayRef<const MethodDebugInfo>& method_infos);
+
 ArrayRef<const uint8_t> WriteDebugElfFileForMethod(const dwarf::MethodDebugInfo& method_info);
 
 ArrayRef<const uint8_t> WriteDebugElfFileForClasses(const InstructionSet isa,
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 7b1bdd7..6bf080a 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -137,9 +137,7 @@
 void ElfWriterQuick<ElfTypes>::SetBssSize(size_t bss_size) {
   auto* bss = builder_->GetBss();
   if (bss_size != 0u) {
-    bss->Start();
-    bss->SetSize(bss_size);
-    bss->End();
+    bss->WriteNoBitsSection(bss_size);
   }
 }
 
@@ -152,8 +150,13 @@
 void ElfWriterQuick<ElfTypes>::WriteDebugInfo(
     const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) {
   if (compiler_options_->GetGenerateDebugInfo()) {
+    // Generate all the debug information we can.
     dwarf::WriteDebugInfo(builder_.get(), method_infos, kCFIFormat);
   }
+  if (compiler_options_->GetGenerateMiniDebugInfo()) {
+    // Generate only some information and compress it.
+    dwarf::WriteMiniDebugInfo(builder_.get(), method_infos);
+  }
 }
 
 template <typename ElfTypes>
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index 52a2382..e920460 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -95,7 +95,7 @@
 
   // Assembler that holds generated instructions
   std::unique_ptr<Assembler> jni_asm(Assembler::Create(instruction_set, instruction_set_features));
-  jni_asm->cfi().SetEnabled(driver->GetCompilerOptions().GetGenerateDebugInfo());
+  jni_asm->cfi().SetEnabled(driver->GetCompilerOptions().GenerateAnyDebugInfo());
 
   // Offsets into data structures
   // TODO: if cross compiling these offsets are for the host not the target
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index a542162..569e0f4 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -806,7 +806,7 @@
         }
       }
 
-      if (writer_->compiler_driver_->GetCompilerOptions().GetGenerateDebugInfo()) {
+      if (writer_->compiler_driver_->GetCompilerOptions().GenerateAnyDebugInfo()) {
         // Record debug information for this function if we are doing that.
         const uint32_t quick_code_start = quick_code_offset -
             writer_->oat_header_->GetExecutableOffset() - thumb_offset;
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index fffd005..3fac914 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -676,7 +676,7 @@
     return nullptr;
   }
   codegen->GetAssembler()->cfi().SetEnabled(
-      compiler_driver->GetCompilerOptions().GetGenerateDebugInfo());
+      compiler_driver->GetCompilerOptions().GenerateAnyDebugInfo());
 
   PassObserver pass_observer(graph,
                              codegen.get(),
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 86f51e1..00941ed 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -318,6 +318,11 @@
   UsageError("");
   UsageError("  --no-generate-debug-info: Do not generate debug information for native debugging.");
   UsageError("");
+  UsageError("  --generate-mini-debug-info: Generate minimal amount of LZMA-compressed");
+  UsageError("      debug information necessary to print backtraces. (disabled by default)");
+  UsageError("");
+  UsageError("  --no-generate-mini-debug-info: Do do generated backtrace info.");
+  UsageError("");
   UsageError("  --debuggable: Produce code debuggable with Java debugger.");
   UsageError("");
   UsageError("  --native-debuggable: Produce code debuggable with native debugger (like LLDB).");
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 7b9ce5b..61d4152 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -142,9 +142,7 @@
     text->End();
 
     if (oat_file_->BssSize() != 0) {
-      bss->Start();
-      bss->SetSize(oat_file_->BssSize());
-      bss->End();
+      bss->WriteNoBitsSection(oat_file_->BssSize());
     }
 
     builder_->WriteDynamicSection(elf_file->GetPath());
diff --git a/test/137-cfi/expected.txt b/test/137-cfi/expected.txt
index 6a5618e..8db7853 100644
--- a/test/137-cfi/expected.txt
+++ b/test/137-cfi/expected.txt
@@ -1 +1,2 @@
 JNI_OnLoad called
+JNI_OnLoad called
diff --git a/test/137-cfi/run b/test/137-cfi/run
index 9c567b6..66575fc 100755
--- a/test/137-cfi/run
+++ b/test/137-cfi/run
@@ -14,4 +14,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-exec ${RUN} "$@" -Xcompiler-option --generate-debug-info
+# Test with full DWARF debugging information.
+${RUN} "$@" -Xcompiler-option --generate-debug-info
+
+# Test with minimal compressed debugging information.
+${RUN} "$@" -Xcompiler-option --generate-mini-debug-info