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 §ion_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,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" @@ -3452,3 +3454,35 @@ } return eStrataUnknown; } + +size_t ObjectFileELF::ReadSectionData(Section *section, + DataExtractor §ion_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 0; + } + + 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: 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: 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/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 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(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()); +}