Add .gnu_debugdata support.

Update the unwind_info tool to dump all of the sections.

Bug: 23762183

Test: Passes new unit tests.
Change-Id: I8b223bc208a1a2ef06ed333e6d96943c8f273681
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 3a7f7cb..7d38ee0 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -20,6 +20,10 @@
 #include <memory>
 #include <string>
 
+#include <7zCrc.h>
+#include <Xz.h>
+#include <XzCrc64.h>
+
 #include "DwarfDebugFrame.h"
 #include "DwarfEhFrame.h"
 #include "DwarfSection.h"
@@ -35,6 +39,60 @@
   }
 }
 
+Memory* ElfInterface::CreateGnuDebugdataMemory() {
+  if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) {
+    return nullptr;
+  }
+
+  // TODO: Only call these initialization functions once.
+  CrcGenerateTable();
+  Crc64GenerateTable();
+
+  std::vector<uint8_t> src(gnu_debugdata_size_);
+  if (!memory_->Read(gnu_debugdata_offset_, src.data(), gnu_debugdata_size_)) {
+    gnu_debugdata_offset_ = 0;
+    gnu_debugdata_size_ = static_cast<uint64_t>(-1);
+    return nullptr;
+  }
+
+  ISzAlloc alloc;
+  CXzUnpacker state;
+  alloc.Alloc = [](void*, size_t size) { return malloc(size); };
+  alloc.Free = [](void*, void* ptr) { return free(ptr); };
+
+  XzUnpacker_Construct(&state, &alloc);
+
+  std::unique_ptr<MemoryBuffer> dst(new MemoryBuffer);
+  int return_val;
+  size_t src_offset = 0;
+  size_t dst_offset = 0;
+  ECoderStatus status;
+  dst->Resize(5 * gnu_debugdata_size_);
+  do {
+    size_t src_remaining = src.size() - src_offset;
+    size_t dst_remaining = dst->Size() - dst_offset;
+    if (dst_remaining < 2 * gnu_debugdata_size_) {
+      dst->Resize(dst->Size() + 2 * gnu_debugdata_size_);
+      dst_remaining += 2 * gnu_debugdata_size_;
+    }
+    return_val = XzUnpacker_Code(&state, dst->GetPtr(dst_offset), &dst_remaining, &src[src_offset],
+                                 &src_remaining, CODER_FINISH_ANY, &status);
+    src_offset += src_remaining;
+    dst_offset += dst_remaining;
+  } while (return_val == SZ_OK && status == CODER_STATUS_NOT_FINISHED);
+  XzUnpacker_Free(&state);
+  if (return_val != SZ_OK || !XzUnpacker_IsStreamWasFinished(&state)) {
+    gnu_debugdata_offset_ = 0;
+    gnu_debugdata_size_ = static_cast<uint64_t>(-1);
+    return nullptr;
+  }
+
+  // Shrink back down to the exact size.
+  dst->Resize(dst_offset);
+
+  return dst.release();
+}
+
 template <typename AddressType>
 void ElfInterface::InitHeadersWithTemplate() {
   if (eh_frame_offset_ != 0) {