[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