Index: lit/CMakeLists.txt =================================================================== --- lit/CMakeLists.txt +++ lit/CMakeLists.txt @@ -22,10 +22,11 @@ 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. Index: lit/Modules/compressed-sections.yaml =================================================================== --- /dev/null +++ lit/Modules/compressed-sections.yaml @@ -0,0 +1,23 @@ +# REQUIRES: zlib +# RUN: yaml2obj %s > %t +# RUN: lldb-test module %t | FileCheck %s +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_386 +Sections: + - Name: .hello_elf +# CHECK: Section 1 +# CHECK: Name: .hello_elf + Type: SHT_PROGBITS + Flags: [ SHF_COMPRESSED ] + Content: 010000000800000001000000789c5330700848286898000009c802c1 +# CHECK: File size: 8 +# CHECK: Data: 2030405060708090 + - Name: .bogus +# CHECK-NOT: .bogus + Type: SHT_PROGBITS + Flags: [ SHF_COMPRESSED ] + Content: deadbeefbaadf00d Index: lit/Modules/lit.local.cfg =================================================================== --- /dev/null +++ lit/Modules/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.yaml'] Index: lit/lit.cfg =================================================================== --- lit/lit.cfg +++ lit/lit.cfg @@ -9,6 +9,9 @@ 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 @@ 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'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 Index: lit/lit.site.cfg.in =================================================================== --- lit/lit.site.cfg.in +++ lit/lit.site.cfg.in @@ -12,6 +12,7 @@ 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. Index: source/Plugins/ObjectFile/ELF/ObjectFileELF.h =================================================================== --- source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -21,6 +21,7 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-private.h" +#include "llvm/Object/Decompressor.h" #include "ELFHeader.h" @@ -140,6 +141,9 @@ ObjectFile::Strata CalculateStrata() 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(); @@ -244,6 +248,11 @@ /// Returns the number of headers parsed. size_t ParseSectionHeaders(); + llvm::Expected + GetSectionDecompressor(const ELFSectionHeaderInfo §); + + llvm::Expected GetSectionFileSize(const ELFSectionHeaderInfo §); + static void ParseARMAttributes(lldb_private::DataExtractor &data, uint64_t length, lldb_private::ArchSpec &arch_spec); Index: source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp =================================================================== --- source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ 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" @@ -1814,7 +1815,38 @@ return 0; } +llvm::Expected +ObjectFileELF::GetSectionDecompressor(const ELFSectionHeaderInfo §) { + const uint8_t *start = m_data.PeekData(sect.sh_offset, sect.sh_size); + if (!start) + return llvm::make_error( + "Invalid section file address or size.", + llvm::inconvertibleErrorCode()); + llvm::StringRef data(reinterpret_cast(start), sect.sh_size); + + return llvm::object::Decompressor::create( + sect.section_name.GetStringRef(), data, + GetByteOrder() == eByteOrderLittle, GetAddressByteSize() == 8); +} + +llvm::Expected +ObjectFileELF::GetSectionFileSize(const ELFSectionHeaderInfo §) { + if (sect.sh_type == SHT_NOBITS) + return 0; + + if (!(sect.sh_flags & SHF_COMPRESSED)) + return sect.sh_size; + + auto Decompressor = GetSectionDecompressor(sect); + if (!Decompressor) + return Decompressor.takeError(); + + return Decompressor->getDecompressedSize(); +} + void ObjectFileELF::CreateSections(SectionList &unified_section_list) { + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES); + if (!m_sections_ap.get() && ParseSectionHeaders()) { m_sections_ap.reset(new SectionList()); @@ -1829,8 +1861,12 @@ const ELFSectionHeaderInfo &header = *I; ConstString &name = I->section_name; - const uint64_t file_size = - header.sh_type == SHT_NOBITS ? 0 : header.sh_size; + auto file_size = GetSectionFileSize(header); + if (!file_size) { + LLDB_LOG(log, "Ignoring section {0}: {1}", name, + llvm::toString(file_size.takeError())); + continue; + } const uint64_t vm_size = header.sh_flags & SHF_ALLOC ? header.sh_size : 0; static ConstString g_sect_name_text(".text"); @@ -2018,7 +2054,7 @@ addr, // VM address. vm_size, // VM size in bytes of this section. header.sh_offset, // Offset of this section in the file. - file_size, // Size of the section as found in the file. + *file_size, // Size of the section as found in the file. log2align, // Alignment of the section header.sh_flags, // Flags for this section. target_bytes_size)); // Number of host bytes per target byte @@ -3452,3 +3488,32 @@ } return eStrataUnknown; } + +size_t ObjectFileELF::ReadSectionData(Section *section, + DataExtractor §ion_data) { + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES); + + if (section->GetObjectFile() != this) + return section->GetObjectFile()->ReadSectionData(section, section_data); + if (section->GetFileSize() == 0) + return 0; + if (!section->Test(SHF_COMPRESSED)) + return ObjectFile::ReadSectionData(section, section_data); + + const ELFSectionHeaderInfo *info = GetSectionHeaderByIndex(section->GetID()); + // Decompressor construction checked in GetSectionFileSize. Only valid + // sections are created. + auto Decompressor = llvm::cantFail(GetSectionDecompressor(*info)); + 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 0; + } + + section_data.SetData(buffer_sp); + return buffer_sp->GetByteSize(); +} Index: tools/lldb-test/lldb-test.cpp =================================================================== --- tools/lldb-test/lldb-test.cpp +++ tools/lldb-test/lldb-test.cpp @@ -47,12 +47,16 @@ assert(S); llvm::outs() << " Section " << I << "\n"; llvm::outs() << " Name: " << S->GetName().GetStringRef() << "\n"; - llvm::outs() << " Length: " << S->GetByteSize() << "\n"; + llvm::outs() << " VM size: " << S->GetByteSize() << "\n"; + llvm::outs() << " File size: " << S->GetFileSize() << "\n"; - lldb::offset_t Offset = 0; DataExtractor Data; S->GetSectionData(Data); - llvm::outs() << " Data: " << Data.GetCStr(&Offset) << "\n\n"; + llvm::outs() << " Data: "; + for (const uint8_t *B = Data.GetDataStart(); B < Data.GetDataEnd(); ++B) + llvm::outs() << llvm::hexdigit(*B >> 4, true) + << llvm::hexdigit(*B & 0xf, true); + llvm::outs() << "\n\n"; } } } 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"