From e2867bc4a07b942724fa3be95c6c671b196fe1ae Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Fri, 15 Dec 2017 14:23:58 +0000 Subject: [PATCH] ObjectFileELF: Add support for compressed sections Summary: 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. Reviewers: clayborg, zturner Subscribers: emaste, mgorny, aprantl, lldb-commits Differential Revision: https://reviews.llvm.org/D40616 llvm-svn: 320813 --- lldb/include/lldb/Symbol/ObjectFile.h | 9 +++ lldb/lit/CMakeLists.txt | 3 +- lldb/lit/Modules/compressed-sections.yaml | 30 ++++++++++ lldb/lit/Modules/lit.local.cfg | 1 + lldb/lit/lit.cfg | 7 +++ lldb/lit/lit.site.cfg.in | 1 + .../Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 55 +++++++++++++++++++ .../Plugins/ObjectFile/ELF/ObjectFileELF.h | 7 +++ lldb/tools/lldb-test/lldb-test.cpp | 3 +- .../ObjectFile/ELF/TestObjectFileELF.cpp | 3 +- 10 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 lldb/lit/Modules/compressed-sections.yaml create mode 100644 lldb/lit/Modules/lit.local.cfg diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index 0708b7c47f34..3f9250af7e08 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -793,15 +793,24 @@ public: static lldb::DataBufferSP ReadMemory(const lldb::ProcessSP &process_sp, lldb::addr_t addr, size_t byte_size); + // This function returns raw file contents. Do not use it if you want + // transparent decompression of section contents. size_t GetData(lldb::offset_t offset, size_t length, DataExtractor &data) const; + // This function returns raw file contents. Do not use it if you want + // transparent decompression of section contents. size_t CopyData(lldb::offset_t offset, size_t length, void *dst) const; + // This function will transparently decompress section data if the section if + // compressed. virtual size_t ReadSectionData(Section *section, lldb::offset_t section_offset, void *dst, size_t dst_len); + // This function will transparently decompress section data if the section if + // compressed. Note that for compressed section the resulting data size may be + // larger than what Section::GetFileSize reports. virtual size_t ReadSectionData(Section *section, DataExtractor §ion_data); diff --git a/lldb/lit/CMakeLists.txt b/lldb/lit/CMakeLists.txt index 925b833d5943..5488154318a9 100644 --- a/lldb/lit/CMakeLists.txt +++ b/lldb/lit/CMakeLists.txt @@ -22,10 +22,11 @@ configure_lit_site_cfg( set(LLDB_TEST_DEPS LLDBUnitTests lldb + lldb-test ) if(NOT LLDB_BUILT_STANDALONE) - list(APPEND LLDB_TEST_DEPS FileCheck not) + list(APPEND LLDB_TEST_DEPS FileCheck not yaml2obj) endif() # lldb-server is not built on every platform. diff --git a/lldb/lit/Modules/compressed-sections.yaml b/lldb/lit/Modules/compressed-sections.yaml new file mode 100644 index 000000000000..0eabd99f2d6d --- /dev/null +++ b/lldb/lit/Modules/compressed-sections.yaml @@ -0,0 +1,30 @@ +# REQUIRES: zlib +# RUN: yaml2obj %s > %t +# RUN: lldb-test module-sections --contents %t | FileCheck %s +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_386 +Sections: + - Name: .hello_elf + Type: SHT_PROGBITS + Flags: [ SHF_COMPRESSED ] + Content: 010000000800000001000000789c5330700848286898000009c802c1 + - Name: .bogus + Type: SHT_PROGBITS + Flags: [ SHF_COMPRESSED ] + Content: deadbeefbaadf00d + +# CHECK: Name: .hello_elf +# CHECK-NEXT: VM size: 0 +# CHECK-NEXT: File size: 28 +# CHECK-NEXT: Data: +# CHECK-NEXT: 20304050 60708090 + +# CHECK: Name: .bogus +# CHECK-NEXT: VM size: 0 +# CHECK-NEXT: File size: 8 +# CHECK-NEXT: Data: +# CHECK-NEXT: DEADBEEF BAADF00D diff --git a/lldb/lit/Modules/lit.local.cfg b/lldb/lit/Modules/lit.local.cfg new file mode 100644 index 000000000000..8169b9f95e11 --- /dev/null +++ b/lldb/lit/Modules/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.yaml'] diff --git a/lldb/lit/lit.cfg b/lldb/lit/lit.cfg index 51f795313f39..402d03947ca8 100644 --- a/lldb/lit/lit.cfg +++ b/lldb/lit/lit.cfg @@ -9,6 +9,9 @@ import locale import lit.formats import lit.util +def binary_feature(on, feature, off_prefix): + return feature if on else off_prefix + feature + # Configuration file for the 'lit' test runner. # name: The name of this test suite. @@ -81,6 +84,8 @@ if debugserver is not None: config.substitutions.append(('%debugserver', debugserver)) for pattern in [r"\bFileCheck\b", + r"\blldb-test\b", + r"\byaml2obj\b", r"\| \bnot\b"]: tool_match = re.match(r"^(\\)?((\| )?)\W+b([0-9A-Za-z-_]+)\\b\W*$", pattern) @@ -125,6 +130,8 @@ elif re.match(r'gcc', config.cc): elif re.match(r'cl', config.cc): config.available_features.add("compiler-msvc") +config.available_features.add(binary_feature(config.have_zlib, "zlib", "no")) + # llvm-config knows whether it is compiled with asserts (and) # whether we are operating in release/debug mode. import subprocess diff --git a/lldb/lit/lit.site.cfg.in b/lldb/lit/lit.site.cfg.in index 4088bce470fa..2cfa677651a1 100644 --- a/lldb/lit/lit.site.cfg.in +++ b/lldb/lit/lit.site.cfg.in @@ -12,6 +12,7 @@ config.target_triple = "@TARGET_TRIPLE@" config.python_executable = "@PYTHON_EXECUTABLE@" config.cc = "@LLDB_TEST_C_COMPILER@" config.cxx = "@LLDB_TEST_CXX_COMPILER@" +config.have_zlib = @HAVE_LIBZ@ # Support substitution of the tools and libs dirs with user parameters. This is # used when we can't determine the tool dir at configuration time. diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index fc42dde82843..9869a94f06b0 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -23,6 +23,7 @@ #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" @@ -31,6 +32,7 @@ #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" @@ -3460,3 +3462,56 @@ ObjectFile::Strata ObjectFileELF::CalculateStrata() { } return eStrataUnknown; } + +size_t ObjectFileELF::ReadSectionData(Section *section, + lldb::offset_t section_offset, void *dst, + size_t dst_len) { + // If some other objectfile owns this data, pass this to them. + if (section->GetObjectFile() != this) + return section->GetObjectFile()->ReadSectionData(section, section_offset, + dst, dst_len); + + if (!section->Test(SHF_COMPRESSED)) + return ObjectFile::ReadSectionData(section, section_offset, dst, dst_len); + + // For compressed sections we need to read to full data to be able to + // decompress. + DataExtractor data; + ReadSectionData(section, data); + return data.CopyData(section_offset, dst_len, dst); +} + +size_t ObjectFileELF::ReadSectionData(Section *section, + DataExtractor §ion_data) { + // If some other objectfile owns this data, pass this to them. + if (section->GetObjectFile() != this) + return section->GetObjectFile()->ReadSectionData(section, 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(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 result; + } + auto buffer_sp = + std::make_shared(Decompressor->getDecompressedSize(), 0); + if (auto Error = Decompressor->decompress( + {reinterpret_cast(buffer_sp->GetBytes()), + buffer_sp->GetByteSize()})) { + LLDB_LOG(log, "Decompression of section {0} failed: {1}", + section->GetName(), llvm::toString(std::move(Error))); + return result; + } + section_data.SetData(buffer_sp); + return buffer_sp->GetByteSize(); +} diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index e3a267a8d850..2909f4e52e4a 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -140,6 +140,13 @@ public: ObjectFile::Strata CalculateStrata() override; + size_t ReadSectionData(lldb_private::Section *section, + lldb::offset_t section_offset, void *dst, + size_t dst_len) override; + + size_t ReadSectionData(lldb_private::Section *section, + lldb_private::DataExtractor §ion_data) override; + // Returns number of program headers found in the ELF file. size_t GetProgramHeaderCount(); diff --git a/lldb/tools/lldb-test/lldb-test.cpp b/lldb/tools/lldb-test/lldb-test.cpp index 723093dee05c..1fe2f5b63859 100644 --- a/lldb/tools/lldb-test/lldb-test.cpp +++ b/lldb/tools/lldb-test/lldb-test.cpp @@ -89,7 +89,8 @@ static void dumpModules(Debugger &Dbg) { assert(S); Printer.formatLine("Index: {0}", I); Printer.formatLine("Name: {0}", S->GetName().GetStringRef()); - Printer.formatLine("Length: {0}", S->GetByteSize()); + Printer.formatLine("VM size: {0}", S->GetByteSize()); + Printer.formatLine("File size: {0}", S->GetFileSize()); if (opts::module::SectionContents) { DataExtractor Data; diff --git a/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp b/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp index 16fa5f000a98..056799ee9191 100644 --- a/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp +++ b/lldb/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"