Index: include/llvm/Object/COFF.h =================================================================== --- include/llvm/Object/COFF.h +++ include/llvm/Object/COFF.h @@ -694,6 +694,7 @@ std::error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const override; uint64_t getSectionAlignment(DataRefImpl Sec) const override; + bool isSectionCompressed(DataRefImpl Sec) const override; bool isSectionText(DataRefImpl Sec) const override; bool isSectionData(DataRefImpl Sec) const override; bool isSectionBSS(DataRefImpl Sec) const override; Index: include/llvm/Object/ELFObjectFile.h =================================================================== --- include/llvm/Object/ELFObjectFile.h +++ include/llvm/Object/ELFObjectFile.h @@ -222,6 +222,7 @@ std::error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const override; uint64_t getSectionAlignment(DataRefImpl Sec) const override; + bool isSectionCompressed(DataRefImpl Sec) const override; bool isSectionText(DataRefImpl Sec) const override; bool isSectionData(DataRefImpl Sec) const override; bool isSectionBSS(DataRefImpl Sec) const override; @@ -584,6 +585,11 @@ } template +bool ELFObjectFile::isSectionCompressed(DataRefImpl Sec) const { + return getSection(Sec)->sh_flags & ELF::SHF_COMPRESSED; +} + +template bool ELFObjectFile::isSectionText(DataRefImpl Sec) const { return getSection(Sec)->sh_flags & ELF::SHF_EXECINSTR; } Index: include/llvm/Object/MachO.h =================================================================== --- include/llvm/Object/MachO.h +++ include/llvm/Object/MachO.h @@ -222,6 +222,7 @@ std::error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const override; uint64_t getSectionAlignment(DataRefImpl Sec) const override; + bool isSectionCompressed(DataRefImpl Sec) const override; bool isSectionText(DataRefImpl Sec) const override; bool isSectionData(DataRefImpl Sec) const override; bool isSectionBSS(DataRefImpl Sec) const override; Index: include/llvm/Object/ObjectFile.h =================================================================== --- include/llvm/Object/ObjectFile.h +++ include/llvm/Object/ObjectFile.h @@ -89,6 +89,7 @@ /// @brief Get the alignment of this section as the actual value (not log 2). uint64_t getAlignment() const; + bool isCompressed() const; bool isText() const; bool isData() const; bool isBSS() const; @@ -214,6 +215,7 @@ virtual std::error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const = 0; virtual uint64_t getSectionAlignment(DataRefImpl Sec) const = 0; + virtual bool isSectionCompressed(DataRefImpl Sec) const = 0; virtual bool isSectionText(DataRefImpl Sec) const = 0; virtual bool isSectionData(DataRefImpl Sec) const = 0; virtual bool isSectionBSS(DataRefImpl Sec) const = 0; @@ -380,6 +382,10 @@ return OwningObject->getSectionAlignment(SectionPimpl); } +inline bool SectionRef::isCompressed() const { + return OwningObject->isSectionCompressed(SectionPimpl); +} + inline bool SectionRef::isText() const { return OwningObject->isSectionText(SectionPimpl); } Index: lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFContext.cpp +++ lib/DebugInfo/DWARF/DWARFContext.cpp @@ -15,6 +15,7 @@ #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Dwarf.h" +#include "llvm/Support/ELF.h" #include "llvm/Support/Format.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" @@ -590,8 +591,8 @@ return InliningInfo; } -static bool consumeCompressedDebugSectionHeader(StringRef &data, - uint64_t &OriginalSize) { +static bool consumeCompressedGnuHeader(StringRef &data, + uint64_t &OriginalSize) { // Consume "ZLIB" prefix. if (!data.startswith("ZLIB")) return false; @@ -606,6 +607,50 @@ return true; } +static bool consumeCompressedZLibHeader(StringRef &Data, uint64_t &OriginalSize, + bool IsLE, bool Is64Bit) { + using namespace ELF; + uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr); + if (Data.size() < HdrSize) + return false; + + DataExtractor Extractor(Data, IsLE, 0); + uint32_t Offset = 0; + if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word) + : sizeof(Elf32_Word)) != + ELFCOMPRESS_ZLIB) + return false; + + // Skip Elf64_Chdr::ch_reserved field. + if (Is64Bit) + Offset += sizeof(Elf64_Word); + + OriginalSize = Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Xword) + : sizeof(Elf32_Word)); + Data = Data.substr(HdrSize); + return true; +} + +static bool tryDecompress(StringRef &Name, StringRef &Data, + SmallString<32> &Out, bool ZLibStyle, bool IsLE, + bool Is64Bit) { + if (!zlib::isAvailable()) + return false; + + uint64_t OriginalSize; + bool Result = + ZLibStyle ? consumeCompressedZLibHeader(Data, OriginalSize, IsLE, Is64Bit) + : consumeCompressedGnuHeader(Data, OriginalSize); + + if (!Result || zlib::uncompress(Data, Out, OriginalSize) != zlib::StatusOK) + return false; + + // gnu-style names are started from "z", consume that. + if (!ZLibStyle) + Name = Name.substr(1); + return true; +} + DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L) : IsLittleEndian(Obj.isLittleEndian()), @@ -631,20 +676,13 @@ name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes. - // Check if debug info section is compressed with zlib. - if (name.startswith("zdebug_")) { - uint64_t OriginalSize; - if (!zlib::isAvailable() || - !consumeCompressedDebugSectionHeader(data, OriginalSize)) + bool ZLibStyleCompressed = Section.isCompressed(); + if (ZLibStyleCompressed || name.startswith("zdebug_")) { + SmallString<32> Out; + if (!tryDecompress(name, data, Out, ZLibStyleCompressed, IsLittleEndian, + AddressSize == 8)) continue; - UncompressedSections.resize(UncompressedSections.size() + 1); - if (zlib::uncompress(data, UncompressedSections.back(), OriginalSize) != - zlib::StatusOK) { - UncompressedSections.pop_back(); - continue; - } - // Make data point to uncompressed section contents and save its contents. - name = name.substr(1); + UncompressedSections.emplace_back(std::move(Out)); data = UncompressedSections.back(); } Index: lib/Object/COFFObjectFile.cpp =================================================================== --- lib/Object/COFFObjectFile.cpp +++ lib/Object/COFFObjectFile.cpp @@ -292,6 +292,10 @@ return Sec->getAlignment(); } +bool COFFObjectFile::isSectionCompressed(DataRefImpl Sec) const { + return false; +} + bool COFFObjectFile::isSectionText(DataRefImpl Ref) const { const coff_section *Sec = toSec(Ref); return Sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE; Index: lib/Object/MachOObjectFile.cpp =================================================================== --- lib/Object/MachOObjectFile.cpp +++ lib/Object/MachOObjectFile.cpp @@ -653,6 +653,10 @@ return uint64_t(1) << Align; } +bool MachOObjectFile::isSectionCompressed(DataRefImpl Sec) const { + return false; +} + bool MachOObjectFile::isSectionText(DataRefImpl Sec) const { uint32_t Flags = getSectionFlags(this, Sec); return Flags & MachO::S_ATTR_PURE_INSTRUCTIONS; Index: test/DebugInfo/Inputs/dwarfdump-test-zlib.cc =================================================================== --- test/DebugInfo/Inputs/dwarfdump-test-zlib.cc +++ test/DebugInfo/Inputs/dwarfdump-test-zlib.cc @@ -16,9 +16,9 @@ return f(2, 3); } -// Built with Clang 3.2 and ld.gold linker: +// Built with Clang 3.9 and GNU gold (GNU Binutils for Ubuntu 2.26) 1.11: // $ mkdir -p /tmp/dbginfo // $ cp dwarfdump-test-zlib.cc /tmp/dbginfo // $ cd /tmp/dbginfo -// $ clang++ -g dwarfdump-test-zlib.cc -Wl,--compress-debug-sections=zlib \ -// -o +// $ clang++ -g dwarfdump-test-zlib.cc -Wl,--compress-debug-sections=zlib -o dwarfdump-test-zlib.elf-x86-64 +// $ clang++ -g dwarfdump-test-zlib.cc -Wl,--compress-debug-sections=zlib-gnu -o dwarfdump-test-zlibgnu.elf-x86-64 Index: test/DebugInfo/dwarfdump-zlib.test =================================================================== --- test/DebugInfo/dwarfdump-zlib.test +++ test/DebugInfo/dwarfdump-zlib.test @@ -1,6 +1,12 @@ REQUIRES: zlib RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test-zlib.elf-x86-64 | FileCheck %s +RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test-zlibgnu.elf-x86-64 | FileCheck %s CHECK: .debug_abbrev contents + +// Dump content of a little section to check that both zlib and zlib gnu styles do +// the decompression correctly and result is the same. This and above also checks +// that sections names are properly shown in zlib-gnu style (without additional 'z' prefix). CHECK: .debug_info contents +CHECK: 0x00000000: Compile Unit: length = 0x00000144 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x00000148)