labath updated this revision to Diff 124926. labath added a comment. This rewrites the test in terms on the new lldb-test utility. It should be applied on top of https://reviews.llvm.org/D40636.
While doing that, I noticed a discrepancy in the data presented by the object file interface -- for GetFileSize(), it would return the compressed size, but, when reading the data, it would return the decompressed size. This seemed odd and unwanted. So now I fetch the decompressed size when constructing the Section object, and make sure GetFileSize result matches what the GetSectionData returns. This is slightly odd as well, because now if someone looks at individual section file offsets and sizes, it will seem that multiple sections overlap. While unfortunate, this is a situation that can arise in without the presence of compressed sections (no linker will produce a file like that, but you can certainly hand-craft one), and our elf parser will hapily accept these files. https://reviews.llvm.org/D40616 Files: lit/CMakeLists.txt lit/Modules/compressed-sections.yaml lit/Modules/lit.local.cfg lit/lit.cfg lit/lit.site.cfg.in source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp source/Plugins/ObjectFile/ELF/ObjectFileELF.h tools/lldb-test/lldb-test.cpp 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" 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: 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<llvm::object::Decompressor> + GetSectionDecompressor(const ELFSectionHeaderInfo §); + + llvm::Expected<uint64_t> 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<llvm::object::Decompressor> +ObjectFileELF::GetSectionDecompressor(const ELFSectionHeaderInfo §) { + const uint8_t *start = m_data.PeekData(sect.sh_offset, sect.sh_size); + if (!start) + return llvm::make_error<llvm::StringError>( + "Invalid section file address or size.", + llvm::inconvertibleErrorCode()); + llvm::StringRef data(reinterpret_cast<const char *>(start), sect.sh_size); + + return llvm::object::Decompressor::create( + sect.section_name.GetStringRef(), data, + GetByteOrder() == eByteOrderLittle, GetAddressByteSize() == 8); +} + +llvm::Expected<uint64_t> +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<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(); +} 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: 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/Modules/lit.local.cfg =================================================================== --- /dev/null +++ lit/Modules/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.yaml'] 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/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.
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits