diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt --- a/lldb/test/CMakeLists.txt +++ b/lldb/test/CMakeLists.txt @@ -165,6 +165,7 @@ LLDB_ENABLE_LUA LLDB_ENABLE_LZMA LLVM_ENABLE_ZLIB + LLVM_ENABLE_ZSTD LLVM_ENABLE_SHARED_LIBS LLDB_HAS_LIBCXX LLDB_USE_SYSTEM_DEBUGSERVER diff --git a/lldb/test/Shell/ObjectFile/ELF/compressed-sections-zstd.yaml b/lldb/test/Shell/ObjectFile/ELF/compressed-sections-zstd.yaml new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/ObjectFile/ELF/compressed-sections-zstd.yaml @@ -0,0 +1,45 @@ +# REQUIRES: zstd +# RUN: yaml2obj %s -o %t +# RUN: lldb-test object-file --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: 02000000080000000100000028B52FFD20084100002030405060708090 + - Name: .bogus + Type: SHT_PROGBITS + Flags: [ SHF_COMPRESSED ] + Content: deadbeefbaadf00d +## The legacy .zdebug format is not supported. + - Name: .zdebug_info + Type: SHT_PROGBITS + Content: 5A4C49420000000000000008789c5330700848286898000009c802c1 + +# CHECK: Name: .hello_elf +# CHECK-NEXT: Type: regular +# CHECK: VM address: 0 +# CHECK-NEXT: VM size: 0 +# CHECK-NEXT: File size: 29 +# CHECK-NEXT: Data: ( +# CHECK-NEXT: 20304050 60708090 +# CHECK-NEXT: ) + +# CHECK: Name: .bogus +# CHECK-NEXT: Type: regular +# CHECK: VM address: 0 +# CHECK-NEXT: VM size: 0 +# CHECK-NEXT: File size: 8 +# CHECK-NEXT: Data: () + +# CHECK: Name: .zdebug_info +# CHECK: regular +# CHECK: File size: 28 +# CHECK: Data: ( +# CHECK-NEXT: 5A4C4942 00000000 00000008 789C5330 70084828 68980000 09C802C1 +# CHECK-NEXT: ) diff --git a/lldb/test/Shell/lit.site.cfg.py.in b/lldb/test/Shell/lit.site.cfg.py.in --- a/lldb/test/Shell/lit.site.cfg.py.in +++ b/lldb/test/Shell/lit.site.cfg.py.in @@ -16,6 +16,7 @@ config.target_triple = "@LLVM_TARGET_TRIPLE@" config.python_executable = "@Python3_EXECUTABLE@" config.have_zlib = @LLVM_ENABLE_ZLIB@ +config.have_zstd = @LLVM_ENABLE_ZSTD@ config.lldb_enable_lzma = @LLDB_ENABLE_LZMA@ config.host_triple = "@LLVM_HOST_TRIPLE@" config.lldb_bitness = 64 if @LLDB_IS_64_BITS@ else 32 diff --git a/llvm/include/llvm/Object/Decompressor.h b/llvm/include/llvm/Object/Decompressor.h --- a/llvm/include/llvm/Object/Decompressor.h +++ b/llvm/include/llvm/Object/Decompressor.h @@ -11,6 +11,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Error.h" namespace llvm { @@ -44,10 +45,11 @@ private: Decompressor(StringRef Data); - Error consumeCompressedZLibHeader(bool Is64Bit, bool IsLittleEndian); + Error consumeCompressedSectionHeader(bool Is64Bit, bool IsLittleEndian); StringRef SectionData; uint64_t DecompressedSize; + llvm::DebugCompressionType CompressionType = llvm::DebugCompressionType::None; }; } // end namespace object diff --git a/llvm/include/llvm/Support/Compression.h b/llvm/include/llvm/Support/Compression.h --- a/llvm/include/llvm/Support/Compression.h +++ b/llvm/include/llvm/Support/Compression.h @@ -121,6 +121,11 @@ Error decompress(DebugCompressionType T, ArrayRef Input, SmallVectorImpl &Output, size_t UncompressedSize); +Error decompress(Format F, ArrayRef Input, uint8_t *Output, + size_t &UncompressedSize); +Error decompress(DebugCompressionType T, ArrayRef Input, + uint8_t *Output, size_t &UncompressedSize); + } // End of namespace compression } // End of namespace llvm diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp --- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -505,12 +505,18 @@ if (Error E = Obj.removeSections(ELFConfig.AllowBrokenLinks, RemovePred)) return E; + const ElfType OutputElfType = + getOutputElfType(Config.OutputArch.value_or(MachineInfo())); + const bool Is64Bit = + OutputElfType == ELFT_ELF64LE || OutputElfType == ELFT_ELF64BE; if (Config.CompressionType != DebugCompressionType::None) { + if (Error Err = replaceDebugSections( Obj, isCompressable, - [&Config, &Obj](const SectionBase *S) -> Expected { + [&Config, &Obj, + Is64Bit](const SectionBase *S) -> Expected { return &Obj.addSection( - CompressedSection(*S, Config.CompressionType)); + CompressedSection(*S, Config.CompressionType, Is64Bit)); })) return Err; } else if (Config.DecompressDebugSections) { diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h --- a/llvm/lib/ObjCopy/ELF/ELFObject.h +++ b/llvm/lib/ObjCopy/ELF/ELFObject.h @@ -537,6 +537,7 @@ MAKE_SEC_WRITER_FRIEND uint32_t ChType = 0; + bool Is64Bits; DebugCompressionType CompressionType; uint64_t DecompressedSize; uint64_t DecompressedAlign; @@ -544,9 +545,10 @@ public: CompressedSection(const SectionBase &Sec, - DebugCompressionType CompressionType); + DebugCompressionType CompressionType, bool Is64Bits); CompressedSection(ArrayRef CompressedData, uint32_t ChType, - uint64_t DecompressedSize, uint64_t DecompressedAlign); + uint64_t DecompressedSize, uint64_t DecompressedAlign, + bool Is64Bits); uint64_t getDecompressedSize() const { return DecompressedSize; } uint64_t getDecompressedAlign() const { return DecompressedAlign; } diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp --- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp @@ -527,26 +527,28 @@ } CompressedSection::CompressedSection(const SectionBase &Sec, - DebugCompressionType CompressionType) - : SectionBase(Sec), CompressionType(CompressionType), + DebugCompressionType CompressionType, + bool Is64Bits) + : SectionBase(Sec), Is64Bits(Is64Bits), CompressionType(CompressionType), DecompressedSize(Sec.OriginalData.size()), DecompressedAlign(Sec.Align) { compression::compress(compression::Params(CompressionType), OriginalData, CompressedData); Flags |= ELF::SHF_COMPRESSED; size_t ChdrSize = - std::max(std::max(sizeof(object::Elf_Chdr_Impl), - sizeof(object::Elf_Chdr_Impl)), - std::max(sizeof(object::Elf_Chdr_Impl), - sizeof(object::Elf_Chdr_Impl))); + Is64Bits ? std::max(sizeof(object::Elf_Chdr_Impl), + sizeof(object::Elf_Chdr_Impl)) + : std::max(sizeof(object::Elf_Chdr_Impl), + sizeof(object::Elf_Chdr_Impl)); Size = ChdrSize + CompressedData.size(); Align = 8; } CompressedSection::CompressedSection(ArrayRef CompressedData, uint32_t ChType, uint64_t DecompressedSize, - uint64_t DecompressedAlign) - : ChType(ChType), CompressionType(DebugCompressionType::None), + uint64_t DecompressedAlign, bool Is64Bits) + : ChType(ChType), Is64Bits(Is64Bits), + CompressionType(DebugCompressionType::None), DecompressedSize(DecompressedSize), DecompressedAlign(DecompressedAlign) { OriginalData = CompressedData; } @@ -1724,8 +1726,9 @@ if (!(Shdr.sh_flags & ELF::SHF_COMPRESSED)) return Obj.addSection
(*Data); auto *Chdr = reinterpret_cast *>(Data->data()); - return Obj.addSection(CompressedSection( - *Data, Chdr->ch_type, Chdr->ch_size, Chdr->ch_addralign)); + return Obj.addSection( + CompressedSection(*Data, Chdr->ch_type, Chdr->ch_size, + Chdr->ch_addralign, ELFT::Is64Bits)); } } } diff --git a/llvm/lib/Object/Decompressor.cpp b/llvm/lib/Object/Decompressor.cpp --- a/llvm/lib/Object/Decompressor.cpp +++ b/llvm/lib/Object/Decompressor.cpp @@ -14,16 +14,15 @@ #include "llvm/Support/Endian.h" using namespace llvm; +using namespace llvm::compression; using namespace llvm::support::endian; using namespace object; Expected Decompressor::create(StringRef Name, StringRef Data, bool IsLE, bool Is64Bit) { - if (!compression::zlib::isAvailable()) - return createError("zlib is not available"); Decompressor D(Data); - if (Error Err = D.consumeCompressedZLibHeader(Is64Bit, IsLE)) + if (Error Err = D.consumeCompressedSectionHeader(Is64Bit, IsLE)) return std::move(Err); return D; } @@ -31,8 +30,8 @@ Decompressor::Decompressor(StringRef Data) : SectionData(Data), DecompressedSize(0) {} -Error Decompressor::consumeCompressedZLibHeader(bool Is64Bit, - bool IsLittleEndian) { +Error Decompressor::consumeCompressedSectionHeader(bool Is64Bit, + bool IsLittleEndian) { using namespace ELF; uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr); if (SectionData.size() < HdrSize) @@ -40,10 +39,25 @@ DataExtractor Extractor(SectionData, IsLittleEndian, 0); uint64_t Offset = 0; - if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word) - : sizeof(Elf32_Word)) != - ELFCOMPRESS_ZLIB) + uint64_t ELFCompressionSchemeId = Extractor.getUnsigned( + &Offset, Is64Bit ? sizeof(Elf64_Word) : sizeof(Elf32_Word)); + + if (ELFCompressionSchemeId == ELFCOMPRESS_ZLIB) + CompressionType = llvm::DebugCompressionType::Z; + if (ELFCompressionSchemeId == ELFCOMPRESS_ZSTD) + CompressionType = llvm::DebugCompressionType::Zstd; + + if (CompressionType == llvm::DebugCompressionType::None) return createError("unsupported compression type"); + if (llvm::compression::getReasonIfUnsupported( + compression::formatFor(CompressionType)) != nullptr) { + switch (compression::formatFor(CompressionType)) { + case llvm::compression::Format::Zstd: + return createError("zstd is not available"); + default: + return createError("zlib is not available"); + } + } // Skip Elf64_Chdr::ch_reserved field. if (Is64Bit) @@ -57,6 +71,7 @@ Error Decompressor::decompress(MutableArrayRef Buffer) { size_t Size = Buffer.size(); - return compression::zlib::uncompress(arrayRefFromStringRef(SectionData), - Buffer.data(), Size); + return compression::decompress(compression::formatFor(CompressionType), + arrayRefFromStringRef(SectionData), + Buffer.data(), Size); } diff --git a/llvm/lib/Support/Compression.cpp b/llvm/lib/Support/Compression.cpp --- a/llvm/lib/Support/Compression.cpp +++ b/llvm/lib/Support/Compression.cpp @@ -73,6 +73,22 @@ return decompress(formatFor(T), Input, Output, UncompressedSize); } +Error compression::decompress(compression::Format F, ArrayRef Input, + uint8_t *Output, size_t &UncompressedSize) { + switch (F) { + case compression::Format::Zlib: + return zlib::uncompress(Input, Output, UncompressedSize); + case compression::Format::Zstd: + return zstd::uncompress(Input, Output, UncompressedSize); + } + llvm_unreachable(""); +} + +Error compression::decompress(DebugCompressionType T, ArrayRef Input, + uint8_t *Output, size_t &UncompressedSize) { + return decompress(formatFor(T), Input, Output, UncompressedSize); +} + #if LLVM_ENABLE_ZLIB static StringRef convertZlibCodeToString(int Code) {