Use zlib to uncompress debug sections in DWARF parser.
authorAlexey Samsonov <samsonov@google.com>
Tue, 23 Apr 2013 10:17:34 +0000 (10:17 +0000)
committerAlexey Samsonov <samsonov@google.com>
Tue, 23 Apr 2013 10:17:34 +0000 (10:17 +0000)
This makes llvm-dwarfdump and llvm-symbolizer understand
debug info sections compressed by ld.gold linker.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@180088 91177308-0d34-0410-b5e6-96231b3b80d8

cmake/config-ix.cmake
lib/DebugInfo/DWARFContext.cpp
lib/DebugInfo/DWARFContext.h
test/DebugInfo/Inputs/dwarfdump-test-zlib.cc [new file with mode: 0644]
test/DebugInfo/Inputs/dwarfdump-test-zlib.elf-x86-64 [new file with mode: 0755]
test/DebugInfo/dwarfdump-zlib.test [new file with mode: 0644]
test/Makefile
test/lit.cfg
test/lit.site.cfg.in

index c426f41f5c9f80eaf837203aaf0c1976bffe5873..7c4285a299b25fc532523b33987caa1fcc86a33b 100755 (executable)
@@ -105,7 +105,11 @@ if( NOT PURE_WINDOWS )
   endif()
   check_library_exists(dl dlopen "" HAVE_LIBDL)
   check_library_exists(rt clock_gettime "" HAVE_LIBRT)
-  check_library_exists(z compress2 "" HAVE_LIBZ)
+  if (LLVM_ENABLE_ZLIB)
+    check_library_exists(z compress2 "" HAVE_LIBZ)
+  else()
+    set(HAVE_LIBZ 0)
+  endif()
 endif()
 
 # function checks
index 74a8c36d7aba3fbb747374034ed4e746a0d853f2..1e13731361a0d78da1fb9ea540de4b46de5c571c 100644 (file)
@@ -10,6 +10,8 @@
 #include "DWARFContext.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compression.h"
 #include "llvm/Support/Dwarf.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/Path.h"
@@ -483,6 +485,22 @@ DIInliningInfo DWARFContext::getInliningInfoForAddress(uint64_t Address,
   return InliningInfo;
 }
 
+static bool consumeCompressedDebugSectionHeader(StringRef &data,
+                                                uint64_t &OriginalSize) {
+  // Consume "ZLIB" prefix.
+  if (!data.startswith("ZLIB"))
+    return false;
+  data = data.substr(4);
+  // Consume uncompressed section size (big-endian 8 bytes).
+  DataExtractor extractor(data, false, 8);
+  uint32_t Offset = 0;
+  OriginalSize = extractor.getU64(&Offset);
+  if (Offset == 0)
+    return false;
+  data = data.substr(Offset);
+  return true;
+}
+
 DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) :
   IsLittleEndian(Obj->isLittleEndian()),
   AddressSize(Obj->getBytesInAddress()) {
@@ -497,6 +515,22 @@ DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) :
 
     name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes.
 
+    // Check if debug info section is compressed with zlib.
+    if (name.startswith("zdebug_")) {
+      uint64_t OriginalSize;
+      if (!zlib::isAvailable() ||
+          !consumeCompressedDebugSectionHeader(data, OriginalSize))
+        continue;
+      OwningPtr<MemoryBuffer> UncompressedSection;
+      if (zlib::uncompress(data, UncompressedSection, OriginalSize) !=
+          zlib::StatusOK)
+        continue;
+      // Make data point to uncompressed section contents and save its contents.
+      name = name.substr(1);
+      data = UncompressedSection->getBuffer();
+      UncompressedSections.push_back(UncompressedSection.take());
+    }
+
     StringRef *Section = StringSwitch<StringRef*>(name)
         .Case("debug_info", &InfoSection)
         .Case("debug_abbrev", &AbbrevSection)
@@ -584,4 +618,8 @@ DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) :
   }
 }
 
+DWARFContextInMemory::~DWARFContextInMemory() {
+  DeleteContainerPointers(UncompressedSections);
+}
+
 void DWARFContextInMemory::anchor() { }
index 37b272993f378cb51b6d08228c989517ab7cec31..78c18e61680a70128cceacbfe9d32f2468545bfe 100644 (file)
@@ -161,8 +161,11 @@ class DWARFContextInMemory : public DWARFContext {
   StringRef RangeDWOSection;
   StringRef AddrSection;
 
+  SmallVector<MemoryBuffer*, 4> UncompressedSections;
+
 public:
   DWARFContextInMemory(object::ObjectFile *);
+  ~DWARFContextInMemory();
   virtual bool isLittleEndian() const { return IsLittleEndian; }
   virtual uint8_t getAddressSize() const { return AddressSize; }
   virtual const RelocAddrMap &infoRelocMap() const { return InfoRelocMap; }
diff --git a/test/DebugInfo/Inputs/dwarfdump-test-zlib.cc b/test/DebugInfo/Inputs/dwarfdump-test-zlib.cc
new file mode 100644 (file)
index 0000000..260c3c4
--- /dev/null
@@ -0,0 +1,24 @@
+class DummyClass {
+  int a_;
+ public:
+  DummyClass(int a) : a_(a) {}
+  int add(int b) {
+    return a_ + b;
+  }
+};
+
+int f(int a, int b) {
+  DummyClass c(a);
+  return c.add(b);
+}
+
+int main() {
+  return f(2, 3);
+}
+
+// Built with Clang 3.2 and ld.gold linker:
+// $ mkdir -p /tmp/dbginfo
+// $ cp dwarfdump-test-zlib.cc /tmp/dbginfo
+// $ cd /tmp/dbginfo
+// $ clang++ -g dwarfdump-test-zlib.cc -Wl,--compress-debug-sections=zlib \
+//   -o <output>
diff --git a/test/DebugInfo/Inputs/dwarfdump-test-zlib.elf-x86-64 b/test/DebugInfo/Inputs/dwarfdump-test-zlib.elf-x86-64
new file mode 100755 (executable)
index 0000000..16b3153
Binary files /dev/null and b/test/DebugInfo/Inputs/dwarfdump-test-zlib.elf-x86-64 differ
diff --git a/test/DebugInfo/dwarfdump-zlib.test b/test/DebugInfo/dwarfdump-zlib.test
new file mode 100644 (file)
index 0000000..8ce2cf7
--- /dev/null
@@ -0,0 +1,12 @@
+REQUIRES: zlib
+
+RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test-zlib.elf-x86-64  \
+RUN:   | FileCheck %s -check-prefix FULLDUMP
+RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test-zlib.elf-x86-64  \
+RUN:   --address=0x400559 --functions | FileCheck %s -check-prefix MAIN
+
+FULLDUMP: .debug_abbrev contents
+FULLDUMP: .debug_info contents
+
+MAIN: main
+MAIN-NEXT: /tmp/dbginfo{{[/\\]}}dwarfdump-test-zlib.cc:16
index 8d05c57f8624cf70660420435a3757da9bd67808..2213319df8116faf5e217968226f32d55d96fdfd 100644 (file)
@@ -141,6 +141,7 @@ lit.site.cfg: FORCE
        @$(ECHOPATH) s=@LLVM_BINDINGS@=$(BINDINGS_TO_BUILD)=g >> lit.tmp
        @$(ECHOPATH) s=@HOST_OS@=$(HOST_OS)=g >> lit.tmp
        @$(ECHOPATH) s=@HOST_ARCH@=$(HOST_ARCH)=g >> lit.tmp
+       @$(ECHOPATH) s=@HAVE_LIBZ@=$(HAVE_LIBZ)=g >> lit.tmp
        @sed -f lit.tmp $(PROJ_SRC_DIR)/lit.site.cfg.in > $@
        @-rm -f lit.tmp
 
index ea91f45754d6750f8b2062e0cf9abd34ec3c4715..b423c6e80b7998745c1e43b2cfee4ba9e7ce356f 100644 (file)
@@ -268,6 +268,9 @@ if (config.llvm_use_sanitizer == "Memory" or
 if not 'hexagon' in config.target_triple:
     config.available_features.add("object-emission")
 
+if config.have_zlib == "1":
+    config.available_features.add("zlib")
+
 # llc knows whether he is compiled with -DNDEBUG.
 import subprocess
 try:
index 8024b24fcde75171d2e3c09f8b516a0aca2e0f2d..3a680b2812675f31cb49d7c6f8308c6c76c1d6a2 100644 (file)
@@ -19,6 +19,7 @@ config.host_os = "@HOST_OS@"
 config.host_arch = "@HOST_ARCH@"
 config.llvm_use_intel_jitevents = "@LLVM_USE_INTEL_JITEVENTS@"
 config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@"
+config.have_zlib = "@HAVE_LIBZ@"
 
 # Support substitution of the tools_dir with user parameters. This is
 # used when we can't determine the tool dir at configuration time.