labath created this revision.
Herald added subscribers: aprantl, mgorny, emaste.

We use the llvm decompressor to decompress SHF_COMPRESSED sections. This enables
us to read data from debug info sections, which are sometimes compressed,
particuarly in the split-dwarf case.  This functionality is only available if
llvm is compiled with zlib support.


https://reviews.llvm.org/D40616

Files:
  source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
  source/Plugins/ObjectFile/ELF/ObjectFileELF.h
  unittests/ObjectFile/ELF/CMakeLists.txt
  unittests/ObjectFile/ELF/Inputs/compressed-sections.yaml
  unittests/ObjectFile/ELF/TestObjectFileELF.cpp

Index: unittests/ObjectFile/ELF/TestObjectFileELF.cpp
===================================================================
--- unittests/ObjectFile/ELF/TestObjectFileELF.cpp
+++ unittests/ObjectFile/ELF/TestObjectFileELF.cpp
@@ -10,12 +10,13 @@
 
 #include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
 #include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h"
+#include "TestingSupport/TestUtilities.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/ModuleSpec.h"
 #include "lldb/Core/Section.h"
 #include "lldb/Host/HostInfo.h"
-#include "TestingSupport/TestUtilities.h"
 #include "llvm/ADT/Optional.h"
+#include "llvm/Support/Compression.h"
 #include "llvm/Support/FileUtilities.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Program.h"
@@ -97,3 +98,42 @@
   ASSERT_NE(nullptr, start);
   EXPECT_EQ(text_sp, start->GetAddress().GetSection());
 }
+
+TEST_F(ObjectFileELFTest, CompressedSections) {
+  if (!llvm::zlib::isAvailable()) {
+    GTEST_LOG_(WARNING)
+        << "Test skipped because the decompression library is not available.";
+    return;
+  }
+  std::string yaml = GetInputFilePath("compressed-sections.yaml");
+  llvm::SmallString<128> obj;
+  ASSERT_NO_ERROR(llvm::sys::fs::createTemporaryFile(
+      "compressed-sections-%%%%%%", "obj", obj));
+
+  llvm::FileRemover remover(obj);
+  const char *args[] = {YAML2OBJ, yaml.c_str(), nullptr};
+  llvm::StringRef obj_ref = obj;
+  const llvm::Optional<llvm::StringRef> redirects[] = {llvm::None, obj_ref,
+                                                       llvm::None};
+  ASSERT_EQ(0, llvm::sys::ExecuteAndWait(YAML2OBJ, args, nullptr, redirects));
+  uint64_t size;
+  ASSERT_NO_ERROR(llvm::sys::fs::file_size(obj, size));
+  ASSERT_GT(size, 0u);
+
+  ModuleSpec spec{FileSpec(obj, false)};
+  spec.GetSymbolFileSpec().SetFile(obj, false);
+  auto module_sp = std::make_shared<Module>(spec);
+  SectionList *list = module_sp->GetSectionList();
+  ASSERT_NE(nullptr, list);
+
+  auto hello_elf_sp = list->FindSectionByName(ConstString(".hello_elf"));
+  ASSERT_NE(nullptr, hello_elf_sp);
+  DataExtractor data;
+  ASSERT_EQ(9u, hello_elf_sp->GetSectionData(data));
+  offset_t offset = 0;
+  EXPECT_STREQ("Hello ELF", data.GetCStr(&offset));
+
+  auto bogus_sp = list->FindSectionByName(ConstString(".bogus"));
+  ASSERT_NE(nullptr, bogus_sp);
+  EXPECT_EQ(0u, bogus_sp->GetByteSize());
+}
Index: unittests/ObjectFile/ELF/Inputs/compressed-sections.yaml
===================================================================
--- /dev/null
+++ unittests/ObjectFile/ELF/Inputs/compressed-sections.yaml
@@ -0,0 +1,15 @@
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_386
+Sections:
+  - Name:            .hello_elf
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_COMPRESSED ]
+    Content:         010000000900000001000000789cf348cdc9c95770f57103000f8d02ec
+  - Name:            .bogus
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_COMPRESSED ]
+    Content:         deadbeefbaadf00d
Index: unittests/ObjectFile/ELF/CMakeLists.txt
===================================================================
--- unittests/ObjectFile/ELF/CMakeLists.txt
+++ unittests/ObjectFile/ELF/CMakeLists.txt
@@ -14,5 +14,6 @@
 
 set(test_inputs
   sections-resolve-consistently.yaml
+  compressed-sections.yaml
   )
 add_unittest_inputs(ObjectFileELFTests "${test_inputs}")
Index: source/Plugins/ObjectFile/ELF/ObjectFileELF.h
===================================================================
--- source/Plugins/ObjectFile/ELF/ObjectFileELF.h
+++ source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -140,6 +140,9 @@
 
   ObjectFile::Strata CalculateStrata() override;
 
+  size_t ReadSectionData(lldb_private::Section *section,
+                         lldb_private::DataExtractor &section_data) override;
+
   // Returns number of program headers found in the ELF file.
   size_t GetProgramHeaderCount();
 
Index: source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
===================================================================
--- source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -23,14 +23,16 @@
 #include "lldb/Target/SectionLoadList.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/DataBufferHeap.h"
 #include "lldb/Utility/DataBufferLLVM.h"
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/Status.h"
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/Timer.h"
 
 #include "llvm/ADT/PointerUnion.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Object/Decompressor.h"
 #include "llvm/Support/ARMBuildAttributes.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -3452,3 +3454,35 @@
   }
   return eStrataUnknown;
 }
+
+size_t ObjectFileELF::ReadSectionData(Section *section,
+                                      DataExtractor &section_data) {
+  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES);
+
+  size_t result = ObjectFile::ReadSectionData(section, section_data);
+  if (result == 0 || !section->Test(SHF_COMPRESSED))
+    return result;
+  auto Decompressor = llvm::object::Decompressor::create(
+      section->GetName().GetStringRef(),
+      {reinterpret_cast<const char *>(section_data.GetDataStart()),
+       section_data.GetByteSize()},
+      GetByteOrder() == eByteOrderLittle, GetAddressByteSize() == 8);
+  if (!Decompressor) {
+    LLDB_LOG(log, "Unable to initialize decompressor for section {0}: {1}",
+             section->GetName(), llvm::toString(Decompressor.takeError()));
+    return 0;
+  }
+
+  auto buffer_sp =
+      std::make_shared<DataBufferHeap>(Decompressor->getDecompressedSize(), 0);
+  if (auto Error = Decompressor->decompress(
+          {reinterpret_cast<char *>(buffer_sp->GetBytes()),
+           buffer_sp->GetByteSize()})) {
+    LLDB_LOG(log, "Decompression of section {0} failed: {1}",
+             section->GetName(), llvm::toString(std::move(Error)));
+    return 0;
+  }
+
+  section_data.SetData(buffer_sp);
+  return buffer_sp->GetByteSize();
+}
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to