[PATCH] D28105: [DWARF] - Introduce DWARFCompression class.
Rafael Avila de Espindola via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 11 07:34:29 PST 2017
LGTM. This code could use some cleanup, but it is better than what was
there before and allows it to be shared.
George Rimar via Phabricator <reviews at reviews.llvm.org> writes:
> grimar updated this revision to Diff 83933.
> grimar added a comment.
>
> - Addressed Rafael's review comments.
>
>
> https://reviews.llvm.org/D28105
>
> Files:
> include/llvm/Object/Decompressor.h
> lib/DebugInfo/DWARF/DWARFContext.cpp
> lib/Object/CMakeLists.txt
> lib/Object/Decompressor.cpp
>
> Index: lib/Object/Decompressor.cpp
> ===================================================================
> --- lib/Object/Decompressor.cpp
> +++ lib/Object/Decompressor.cpp
> @@ -0,0 +1,102 @@
> +//===-- Decompressor.cpp --------------------------------------------------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/Object/Decompressor.h"
> +#include "llvm/Object/ELFObjectFile.h"
> +#include "llvm/Support/Compression.h"
> +#include "llvm/Support/DataExtractor.h"
> +#include "llvm/Support/Endian.h"
> +#include "llvm/Support/ELF.h"
> +
> +using namespace llvm;
> +using namespace llvm::support::endian;
> +using namespace object;
> +
> +Expected<Decompressor> Decompressor::create(StringRef Name, StringRef Data,
> + bool IsLE, bool Is64Bit) {
> + if (!zlib::isAvailable())
> + return createError("zlib is not available");
> +
> + Decompressor D(Data);
> + Error Err = isGnuStyle(Name) ? D.consumeCompressedGnuHeader()
> + : D.consumeCompressedZLibHeader(Is64Bit, IsLE);
> + if (Err)
> + return std::move(Err);
> + return D;
> +}
> +
> +Decompressor::Decompressor(StringRef Data)
> + : SectionData(Data), DecompressedSize(0) {}
> +
> +Error Decompressor::consumeCompressedGnuHeader() {
> + if (!SectionData.startswith("ZLIB"))
> + return createError("corrupted compressed section header");
> +
> + SectionData = SectionData.substr(4);
> +
> + // Consume uncompressed section size (big-endian 8 bytes).
> + if (SectionData.size() < 8)
> + return createError("corrupted uncompressed section size");
> + DecompressedSize = read64be(SectionData.data());
> + SectionData = SectionData.substr(8);
> +
> + return Error::success();
> +}
> +
> +Error Decompressor::consumeCompressedZLibHeader(bool Is64Bit,
> + bool IsLittleEndian) {
> + using namespace ELF;
> + uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr);
> + if (SectionData.size() < HdrSize)
> + return createError("corrupted compressed section header");
> +
> + DataExtractor Extractor(SectionData, IsLittleEndian, 0);
> + uint32_t Offset = 0;
> + if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word)
> + : sizeof(Elf32_Word)) !=
> + ELFCOMPRESS_ZLIB)
> + return createError("unsupported compression type");
> +
> + // Skip Elf64_Chdr::ch_reserved field.
> + if (Is64Bit)
> + Offset += sizeof(Elf64_Word);
> +
> + DecompressedSize = Extractor.getUnsigned(
> + &Offset, Is64Bit ? sizeof(Elf64_Xword) : sizeof(Elf32_Word));
> + SectionData = SectionData.substr(HdrSize);
> + return Error::success();
> +}
> +
> +bool Decompressor::isGnuStyle(StringRef Name) {
> + return Name.startswith(".zdebug");
> +}
> +
> +bool Decompressor::isCompressed(const object::SectionRef &Section) {
> + StringRef Name;
> + if (std::error_code E = Section.getName(Name))
> + return false;
> + return Section.isCompressed() || isGnuStyle(Name);
> +}
> +
> +bool Decompressor::isCompressedELFSection(uint64_t Flags, StringRef Name) {
> + return (Flags & ELF::SHF_COMPRESSED) || isGnuStyle(Name);
> +}
> +
> +Error Decompressor::decompress(SmallString<32> &Out) {
> + Out.resize(DecompressedSize);
> + return decompress({Out.data(), (size_t)DecompressedSize});
> +}
> +
> +Error Decompressor::decompress(MutableArrayRef<char> Buffer) {
> + size_t Size = Buffer.size();
> + zlib::Status Status = zlib::uncompress(SectionData, Buffer.data(), Size);
> + if (Status != zlib::StatusOK)
> + return createError("decompression failed");
> + return Error::success();
> +}
> Index: lib/Object/CMakeLists.txt
> ===================================================================
> --- lib/Object/CMakeLists.txt
> +++ lib/Object/CMakeLists.txt
> @@ -3,6 +3,7 @@
> ArchiveWriter.cpp
> Binary.cpp
> COFFObjectFile.cpp
> + Decompressor.cpp
> ELF.cpp
> ELFObjectFile.cpp
> Error.cpp
> Index: lib/DebugInfo/DWARF/DWARFContext.cpp
> ===================================================================
> --- lib/DebugInfo/DWARF/DWARFContext.cpp
> +++ lib/DebugInfo/DWARF/DWARFContext.cpp
> @@ -14,6 +14,7 @@
> #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
> #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
> #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
> +#include "llvm/Object/Decompressor.h"
> #include "llvm/Object/MachO.h"
> #include "llvm/Object/RelocVisitor.h"
> #include "llvm/Support/Compression.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,23 @@
> 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 (Decompressor::isCompressed(Section)) {
> + Expected<Decompressor> Decompressor =
> + Decompressor::create(name, data, IsLittleEndian, AddressSize == 8);
> + if (!Decompressor)
> + continue;
> SmallString<32> Out;
> - if (!tryDecompress(name, data, Out, ZLibStyleCompressed, IsLittleEndian,
> - AddressSize == 8))
> + if (auto Err = Decompressor->decompress(Out))
> continue;
> UncompressedSections.emplace_back(std::move(Out));
> data = UncompressedSections.back();
> }
>
> + // Compressed sections names in GNU style starts from ".z",
> + // at this point section is decompressed and we drop compression prefix.
> + name = name.substr(
> + name.find_first_not_of("._z")); // Skip ".", "z" and "_" prefixes.
> +
> StringRef *SectionData =
> StringSwitch<StringRef *>(name)
> .Case("debug_info", &InfoSection.Data)
> Index: include/llvm/Object/Decompressor.h
> ===================================================================
> --- include/llvm/Object/Decompressor.h
> +++ include/llvm/Object/Decompressor.h
> @@ -0,0 +1,64 @@
> +//===-- Decompressor.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_OBJECT_DECOMPRESSOR_H
> +#define LLVM_OBJECT_DECOMPRESSOR_H
> +
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/ADT/SmallString.h"
> +#include "llvm/Object/ObjectFile.h"
> +
> +namespace llvm {
> +namespace object {
> +
> +/// @brief Decompressor helps to handle decompression of compressed sections.
> +class Decompressor {
> +public:
> + /// @brief Create decompressor object.
> + /// @param Name Section name.
> + /// @param Data Section content.
> + /// @param IsLE Flag determines if Data is in little endian form.
> + /// @param Name Flag determines if object is 64 bit.
> + static Expected<Decompressor> create(StringRef Name, StringRef Data,
> + bool IsLE, bool Is64Bit);
> +
> + /// @brief Resize the buffer and uncompress section data into it.
> + /// @param Out Destination buffer.
> + Error decompress(SmallString<32> &Out);
> +
> + /// @brief Uncompress section data to raw buffer provided.
> + /// @param Buffer Destination buffer.
> + Error decompress(MutableArrayRef<char> Buffer);
> +
> + /// @brief Return memory buffer size required for decompression.
> + uint64_t getDecompressedSize() { return DecompressedSize; }
> +
> + /// @brief Return true if section is compressed, including gnu-styled case.
> + static bool isCompressed(const object::SectionRef &Section);
> +
> + /// @brief Return true if section is a ELF compressed one.
> + static bool isCompressedELFSection(uint64_t Flags, StringRef Name);
> +
> + /// @brief Return true if section name matches gnu style compressed one.
> + static bool isGnuStyle(StringRef Name);
> +
> +private:
> + Decompressor(StringRef Data);
> +
> + Error consumeCompressedGnuHeader();
> + Error consumeCompressedZLibHeader(bool Is64Bit, bool IsLittleEndian);
> +
> + StringRef SectionData;
> + uint64_t DecompressedSize;
> +};
> +
> +} // end namespace object
> +} // end namespace llvm
> +
> +#endif // LLVM_OBJECT_DECOMPRESSOR_H
More information about the llvm-commits
mailing list