Index: include/llvm/DebugInfo/DWARF/DWARFCompression.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFCompression.h +++ include/llvm/DebugInfo/DWARF/DWARFCompression.h @@ -0,0 +1,60 @@ +//===-- DWARFCompression.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===/ + +#ifndef LLVM_LIB_DEBUGINFO_DWARFCOMPRESSION_H +#define LLVM_LIB_DEBUGINFO_DWARFCOMPRESSION_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Object/ObjectFile.h" + +namespace llvm { + +/// DWARFCompression +/// This class helps to handle decompression of compressed debug sections. +class DWARFCompression { +public: + DWARFCompression(StringRef Name, StringRef Data, bool IsLE, bool Is64Bit); + + /// Methods resized the buffer and uncompress section data into it. + bool uncompress(SmallString<32> &Out); + + /// Methods uncompresses section data to raw buffer provided. + bool uncompress(char *Buffer, size_t Size); + + /// Used to get text representation of error if any happened. + StringRef getErrorMessage() { return ErrorMsg; } + + /// Returns if section is compressed, including gnu-styled case. + static bool isCompressed(const object::SectionRef &Section); + + /// Using section name and flags returns if section is a ELF compressed one. + static bool isCompressedELFSection(uint64_t Flags, StringRef Name); + + /// Returns if section name is matches gnu style compressed one. + static bool isGnuStyle(StringRef Name); + + /// Contains memory buffer size required for decompression. + uint64_t UncompressedSize; + +private: + void consumeCompressedGnuHeader(); + void consumeCompressedZLibHeader(); + void setError(StringRef Error); + + StringRef SectionName; + StringRef SectionData; + StringRef ErrorMsg; + bool IsLittleEndian; + bool Is64Bit; +}; + +} // end namespace llvm + +#endif // LLVM_LIB_DEBUGINFO_DWARFCOMPRESSION_H Index: lib/DebugInfo/DWARF/CMakeLists.txt =================================================================== --- lib/DebugInfo/DWARF/CMakeLists.txt +++ lib/DebugInfo/DWARF/CMakeLists.txt @@ -2,6 +2,7 @@ DWARFAbbreviationDeclaration.cpp DWARFAcceleratorTable.cpp DWARFCompileUnit.cpp + DWARFCompression.cpp DWARFContext.cpp DWARFDebugAbbrev.cpp DWARFDebugArangeSet.cpp Index: lib/DebugInfo/DWARF/DWARFCompression.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFCompression.cpp +++ lib/DebugInfo/DWARF/DWARFCompression.cpp @@ -0,0 +1,106 @@ +//===-- DWARFContext.cpp --------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFCompression.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/ELF.h" + +using namespace llvm; + +DWARFCompression::DWARFCompression(StringRef Name, StringRef Data, bool IsLE, + bool Is64Bit) + : SectionName(Name), SectionData(Data), IsLittleEndian(IsLE), + Is64Bit(Is64Bit), UncompressedSize(0) { + if (!zlib::isAvailable()) { + setError("zlib is not available"); + return; + } + + if (isGnuStyle(SectionName)) + consumeCompressedGnuHeader(); + else + consumeCompressedZLibHeader(); +} + +void DWARFCompression::setError(StringRef Error) { ErrorMsg = Error; } + +void DWARFCompression::consumeCompressedGnuHeader() { + if (!SectionData.startswith("ZLIB")) { + setError("corrupted compressed section header"); + return; + } + SectionData = SectionData.substr(4); + + // Consume uncompressed section size (big-endian 8 bytes). + DataExtractor extractor(SectionData, false, 8); + uint32_t Offset = 0; + uint64_t Size = extractor.getU64(&Offset); + if (Offset == 0) { + setError("corrupted uncompressed section size"); + return; + } + UncompressedSize = Size; + SectionData = SectionData.substr(Offset); +} + +void DWARFCompression::consumeCompressedZLibHeader() { + using namespace ELF; + uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr); + if (SectionData.size() < HdrSize) { + setError("corrupted compressed section header"); + return; + } + + DataExtractor Extractor(SectionData, IsLittleEndian, 0); + uint32_t Offset = 0; + if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word) + : sizeof(Elf32_Word)) != + ELFCOMPRESS_ZLIB) { + setError("unsupported compression type"); + return; + } + + // Skip Elf64_Chdr::ch_reserved field. + if (Is64Bit) + Offset += sizeof(Elf64_Word); + + UncompressedSize = Extractor.getUnsigned( + &Offset, Is64Bit ? sizeof(Elf64_Xword) : sizeof(Elf32_Word)); + SectionData = SectionData.substr(HdrSize); +} + +bool DWARFCompression::isGnuStyle(StringRef Name) { + return Name.startswith(".zdebug"); +} + +bool DWARFCompression::isCompressed(const object::SectionRef &Section) { + StringRef Name; + Section.getName(Name); + return Section.isCompressed() || isGnuStyle(Name); +} + +bool DWARFCompression::isCompressedELFSection(uint64_t Flags, StringRef Name) { + return (Flags & ELF::SHF_COMPRESSED) || isGnuStyle(Name); +} + +bool DWARFCompression::uncompress(SmallString<32> &Out) { + if (!ErrorMsg.empty()) + return false; + Out.resize(UncompressedSize); + return uncompress(Out.data(), (size_t)UncompressedSize); +} + +bool DWARFCompression::uncompress(char *Buffer, size_t Size) { + bool Ret = zlib::uncompress(SectionData, Buffer, Size) == zlib::StatusOK; + if (!Ret) + setError("error uncompressing section"); + return Ret; +} Index: lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFContext.cpp +++ lib/DebugInfo/DWARF/DWARFContext.cpp @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" +#include "llvm/DebugInfo/DWARF/DWARFCompression.h" #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" #include "llvm/Object/MachO.h" #include "llvm/Object/RelocVisitor.h" @@ -577,66 +578,6 @@ return InliningInfo; } -static bool consumeCompressedGnuHeader(StringRef &data, - uint64_t &OriginalSize) { - // Consume "ZLIB" prefix. - if (!data.startswith("ZLIB")) - return false; - data = data.substr(4); - // Consume uncompressed section size (big-endian 8 bytes). - DataExtractor extractor(data, false, 8); - uint32_t Offset = 0; - OriginalSize = extractor.getU64(&Offset); - if (Offset == 0) - return false; - data = data.substr(Offset); - 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()), @@ -660,18 +601,19 @@ if (!L || !L->getLoadedSectionContents(*RelocatedSection,data)) Section.getContents(data); - name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes. - - bool ZLibStyleCompressed = Section.isCompressed(); - if (ZLibStyleCompressed || name.startswith("zdebug_")) { + if (DWARFCompression::isCompressed(Section)) { + DWARFCompression Decompressor(name, data, IsLittleEndian, + AddressSize == 8); SmallString<32> Out; - if (!tryDecompress(name, data, Out, ZLibStyleCompressed, IsLittleEndian, - AddressSize == 8)) + if (!Decompressor.uncompress(Out)) continue; UncompressedSections.emplace_back(std::move(Out)); data = UncompressedSections.back(); } + name = name.substr( + name.find_first_not_of("._z")); // Skip ".", "z" and "_" prefixes. + StringRef *SectionData = StringSwitch(name) .Case("debug_info", &InfoSection.Data)