[llvm] r341607 - [llvm-objcopy] Dwarf .debug section compression support (zlib, zlib-gnu).

Puyan Lotfi via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 6 16:59:51 PDT 2018


Author: zer0
Date: Thu Sep  6 16:59:50 2018
New Revision: 341607

URL: http://llvm.org/viewvc/llvm-project?rev=341607&view=rev
Log:
[llvm-objcopy] Dwarf .debug section compression support (zlib, zlib-gnu).

  Second Attempt. Alignment issues resolved. zlib::isAvailable() detected.

  Usage:

  llvm-objcopy --compress-debug-sections=zlib foo.o
  llvm-objcopy --compress-debug-sections=zlib-gnu foo.o

  In both cases the debug section contents is compressed with zlib. In the GNU
  style case the header is the "ZLIB" magic string followed by the uint64 big-
  endian decompressed size. In the non-GNU mode the header is the
  Elf(32|64)_Chdr.

  Decompression support is coming soon.

  Differential Revision: https://reviews.llvm.org/D49678

Added:
    llvm/trunk/test/tools/llvm-objcopy/Inputs/compress-debug-sections.yaml
    llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-default-gnu.test
    llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-default.test
    llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-invalid-format.test
    llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-zlib-gnu.test
    llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-zlib.test
Modified:
    llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td
    llvm/trunk/tools/llvm-objcopy/Object.cpp
    llvm/trunk/tools/llvm-objcopy/Object.h
    llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp

Added: llvm/trunk/test/tools/llvm-objcopy/Inputs/compress-debug-sections.yaml
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/Inputs/compress-debug-sections.yaml?rev=341607&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/Inputs/compress-debug-sections.yaml (added)
+++ llvm/trunk/test/tools/llvm-objcopy/Inputs/compress-debug-sections.yaml Thu Sep  6 16:59:50 2018
@@ -0,0 +1,21 @@
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .debug_foo
+    Type:            SHT_PROGBITS
+    Content:         0000000000000000
+  - Name:            .notdebug_foo
+    Type:            SHT_PROGBITS
+    Content:         0000000000000000
+  - Name:            .rela.debug_foo
+    Type:            SHT_RELA
+    Info:            .debug_foo
+    Relocations:
+      - Offset:          0x1
+        Symbol:          .debug_foo
+        Type:            R_X86_64_32
+...

Added: llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-default-gnu.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-default-gnu.test?rev=341607&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-default-gnu.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-default-gnu.test Thu Sep  6 16:59:50 2018
@@ -0,0 +1,9 @@
+# REQUIRES: zlib
+
+# RUN: yaml2obj %p/Inputs/compress-debug-sections.yaml -o %t.o
+# RUN: llvm-objcopy --compress-debug-sections --compress-debug-sections=zlib-gnu %t.o %t-compressed.o
+# RUN: llvm-objdump -s %t-compressed.o | FileCheck %s
+
+# CHECK: .zdebug_foo:
+# CHECK: ZLIB
+

Added: llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-default.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-default.test?rev=341607&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-default.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-default.test Thu Sep  6 16:59:50 2018
@@ -0,0 +1,13 @@
+# REQUIRES: zlib
+
+# RUN: yaml2obj %p/Inputs/compress-debug-sections.yaml -o %t.o
+# RUN: llvm-objcopy --compress-debug-sections %t.o %t-compressed.o
+# RUN: llvm-readobj -s %t-compressed.o | FileCheck %s
+
+# CHECK: Name: .debug_foo
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_COMPRESSED
+# CHECK-NEXT: ]
+# CHECK-NOT: Name: .debug_foo
+

Added: llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-invalid-format.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-invalid-format.test?rev=341607&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-invalid-format.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-invalid-format.test Thu Sep  6 16:59:50 2018
@@ -0,0 +1,5 @@
+# RUN: yaml2obj %p/Inputs/compress-debug-sections.yaml -o %t.o
+# RUN: not llvm-objcopy --compress-debug-sections=zlib-fake %t.o 2>&1 | FileCheck %s
+
+# CHECK: Invalid or unsupported --compress-debug-sections format: zlib-fake.
+

Added: llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-zlib-gnu.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-zlib-gnu.test?rev=341607&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-zlib-gnu.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-zlib-gnu.test Thu Sep  6 16:59:50 2018
@@ -0,0 +1,49 @@
+# REQUIRES: zlib
+
+# RUN: yaml2obj %p/Inputs/compress-debug-sections.yaml -o %t.o
+# RUN: llvm-objcopy --compress-debug-sections=zlib-gnu %t.o %t-compressed.o
+
+# RUN: llvm-objdump -s %t.o -section=.debug_foo | FileCheck %s
+# RUN: llvm-objdump -s %t-compressed.o | FileCheck %s --check-prefix=CHECK-COMPRESSED
+# RUN: llvm-readobj -relocations -s %t-compressed.o | FileCheck %s --check-prefix=CHECK-FLAGS
+
+# CHECK: .debug_foo:
+
+# CHECK-COMPRESSED: .zdebug_foo:
+# CHECK-COMPRESSED: ZLIB
+# CHECK-COMPRESSED: .notdebug_foo:
+
+# CHECK-FLAGS-NOT: Name: .debug_foo
+# CHECK-FLAGS: Index: 1
+# CHECK-FLAGS-NEXT: Name: .zdebug_foo
+# CHECK-FLAGS-NEXT: Type: SHT_PROGBITS
+# CHECK-FLAGS-NEXT: Flags [
+# CHECK-FLAGS-NEXT: ]
+# CHECK-FLAGS-NEXT: Address:
+# CHECK-FLAGS-NEXT: Offset:
+# CHECK-FLAGS-NEXT: Size: 23
+
+# CHECK-FLAGS: Name: .notdebug_foo
+# CHECK-FLAGS-NEXT: Type: SHT_PROGBITS
+# CHECK-FLAGS-NEXT: Flags [
+# CHECK-FLAGS-NEXT: ]
+# CHECK-FLAGS-NEXT: Address:
+# CHECK-FLAGS-NEXT: Offset:
+# CHECK-FLAGS-NEXT: Size: 8
+
+# CHECK-FLAGS: Name: .rela.debug_foo
+# CHECK-FLAGS-NEXT: Type: SHT_RELA
+# CHECK-FLAGS-NEXT: Flags [
+# CHECK-FLAGS-NEXT: ]
+# CHECK-FLAGS-NEXT: Address:
+# CHECK-FLAGS-NEXT: Offset:
+# CHECK-FLAGS-NEXT: Size:
+# CHECK-FLAGS-NEXT: Link:
+# CHECK-FLAGS-NEXT: Info: 1
+
+# CHECK-FLAGS: Relocations [
+# CHECK-FLAGS-NEXT:   .rela.debug_foo {
+# CHECK-FLAGS-NEXT:     0x1 R_X86_64_32 - 0x0
+# CHECK-FLAGS-NEXT:   }
+# CHECK-FLAGS-NEXT: ]
+

Added: llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-zlib.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-zlib.test?rev=341607&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-zlib.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/compress-debug-sections-zlib.test Thu Sep  6 16:59:50 2018
@@ -0,0 +1,49 @@
+# REQUIRES: zlib
+
+# RUN: yaml2obj %p/Inputs/compress-debug-sections.yaml -o %t.o
+# RUN: llvm-objcopy --compress-debug-sections=zlib %t.o %t-compressed.o
+
+# RUN: llvm-objdump -s %t.o -section=.debug_foo | FileCheck %s
+# RUN: llvm-objdump -s %t-compressed.o | FileCheck %s --check-prefix=CHECK-COMPRESSED
+# RUN: llvm-readobj -relocations -s %t-compressed.o | FileCheck %s --check-prefix=CHECK-FLAGS
+
+# CHECK: .debug_foo:
+
+# CHECK-COMPRESSED: .debug_foo:
+# CHECK-COMPRESSED: .notdebug_foo:
+
+# CHECK-FLAGS: Index: 1
+# CHECK-FLAGS-NEXT: Name: .debug_foo
+# CHECK-FLAGS-NEXT: Type: SHT_PROGBITS
+# CHECK-FLAGS-NEXT: Flags [
+# CHECK-FLAGS-NEXT: SHF_COMPRESSED
+# CHECK-FLAGS-NEXT: ]
+# CHECK-FLAGS-NEXT: Address:
+# CHECK-FLAGS-NEXT: Offset:
+# CHECK-FLAGS-NEXT: Size: 35
+# CHECK-FLAGS-NOT: Name: .debug_foo
+
+# CHECK-FLAGS: Name: .notdebug_foo
+# CHECK-FLAGS-NEXT: Type: SHT_PROGBITS
+# CHECK-FLAGS-NEXT: Flags [
+# CHECK-FLAGS-NEXT: ]
+# CHECK-FLAGS-NEXT: Address:
+# CHECK-FLAGS-NEXT: Offset:
+# CHECK-FLAGS-NEXT: Size: 8
+
+# CHECK-FLAGS: Name: .rela.debug_foo
+# CHECK-FLAGS-NEXT: Type: SHT_RELA
+# CHECK-FLAGS-NEXT: Flags [
+# CHECK-FLAGS-NEXT: ]
+# CHECK-FLAGS-NEXT: Address:
+# CHECK-FLAGS-NEXT: Offset:
+# CHECK-FLAGS-NEXT: Size:
+# CHECK-FLAGS-NEXT: Link:
+# CHECK-FLAGS-NEXT: Info: 1
+
+# CHECK-FLAGS: Relocations [
+# CHECK-FLAGS-NEXT:   .rela.debug_foo {
+# CHECK-FLAGS-NEXT:     0x1 R_X86_64_32 - 0x0
+# CHECK-FLAGS-NEXT:   }
+# CHECK-FLAGS-NEXT: ]
+

Modified: llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td?rev=341607&r1=341606&r2=341607&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td (original)
+++ llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td Thu Sep  6 16:59:50 2018
@@ -17,6 +17,12 @@ def I : JoinedOrSeparate<[ "-" ], "I">,
 defm output_target : Eq<"output-target">,
                      HelpText<"Format of the output file">,
                      Values<"binary">;
+def compress_debug_sections : Flag<["--", "-"], "compress-debug-sections">;
+def compress_debug_sections_eq : Joined<["--", "-"], "compress-debug-sections=">,
+                                 MetaVarName<"[ zlib | zlib-gnu ]">,
+                                 HelpText<"Compress DWARF debug sections using "
+                                          "specified style. Supported styles: "
+                                          "'zlib-gnu' and 'zlib'">;
 def O : JoinedOrSeparate<["-"], "O">,
         Alias<output_target>;
 defm split_dwo : Eq<"split-dwo">,

Modified: llvm/trunk/tools/llvm-objcopy/Object.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/Object.cpp?rev=341607&r1=341606&r2=341607&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/Object.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/Object.cpp Thu Sep  6 16:59:50 2018
@@ -15,7 +15,9 @@
 #include "llvm/ADT/Twine.h"
 #include "llvm/ADT/iterator_range.h"
 #include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCTargetOptions.h"
 #include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/Compression.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FileOutputBuffer.h"
 #include "llvm/Support/Path.h"
@@ -138,6 +140,76 @@ void OwnedDataSection::accept(SectionVis
   Visitor.visit(*this);
 }
 
+void BinarySectionWriter::visit(const CompressedSection &Sec) {
+  error("Cannot write compressed section '" + Sec.Name + "' ");
+}
+
+template <class ELFT>
+void ELFSectionWriter<ELFT>::visit(const CompressedSection &Sec) {
+  uint8_t *Buf = Out.getBufferStart();
+  Buf += Sec.Offset;
+
+  if (Sec.CompressionType == DebugCompressionType::None) {
+    std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), Buf);
+    return;
+  }
+
+  if (Sec.CompressionType == DebugCompressionType::GNU) {
+    ArrayRef<uint8_t> Magic = {'Z', 'L', 'I', 'B'};
+    std::copy(Magic.begin(), Magic.end(), Buf);
+    Buf += Magic.size();
+    const uint64_t DecompressedSize =
+        support::endian::read64be(&Sec.DecompressedSize);
+    memcpy(Buf, &DecompressedSize, sizeof(DecompressedSize));
+    Buf += sizeof(DecompressedSize);
+  } else {
+    Elf_Chdr_Impl<ELFT> Chdr;
+    Chdr.ch_type = ELF::ELFCOMPRESS_ZLIB;
+    Chdr.ch_size = Sec.DecompressedSize;
+    Chdr.ch_addralign = Sec.DecompressedAlign;
+    memcpy(Buf, &Chdr, sizeof(Chdr));
+    Buf += sizeof(Chdr);
+  }
+
+  std::copy(Sec.CompressedData.begin(), Sec.CompressedData.end(), Buf);
+}
+
+CompressedSection::CompressedSection(const SectionBase &Sec,
+                                     DebugCompressionType CompressionType)
+    : SectionBase(Sec), CompressionType(CompressionType),
+      DecompressedSize(Sec.OriginalData.size()), DecompressedAlign(Sec.Align) {
+
+  if (!zlib::isAvailable()) {
+    CompressionType = DebugCompressionType::None;
+    return;
+  }
+
+  if (Error E = zlib::compress(
+          StringRef(reinterpret_cast<const char *>(OriginalData.data()),
+                    OriginalData.size()),
+          CompressedData))
+    reportError(Name, std::move(E));
+
+  size_t ChdrSize;
+  if (CompressionType == DebugCompressionType::GNU) {
+    Name = ".z" + Sec.Name.substr(1);
+    ChdrSize = sizeof("ZLIB") - 1 + sizeof(uint64_t);
+  } else {
+    Flags |= ELF::SHF_COMPRESSED;
+    ChdrSize =
+        std::max(std::max(sizeof(object::Elf_Chdr_Impl<object::ELF64LE>),
+                          sizeof(object::Elf_Chdr_Impl<object::ELF64BE>)),
+                 std::max(sizeof(object::Elf_Chdr_Impl<object::ELF32LE>),
+                          sizeof(object::Elf_Chdr_Impl<object::ELF32BE>)));
+  }
+  Size = ChdrSize + CompressedData.size();
+  Align = 8;
+}
+
+void CompressedSection::accept(SectionVisitor &Visitor) const {
+  Visitor.visit(*this);
+}
+
 void StringTableSection::addString(StringRef Name) {
   StrTabBuilder.add(Name);
   Size = StrTabBuilder.getSize();

Modified: llvm/trunk/tools/llvm-objcopy/Object.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/Object.h?rev=341607&r1=341606&r2=341607&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/Object.h (original)
+++ llvm/trunk/tools/llvm-objcopy/Object.h Thu Sep  6 16:59:50 2018
@@ -26,6 +26,7 @@
 #include <vector>
 
 namespace llvm {
+enum class DebugCompressionType;
 namespace objcopy {
 
 class Buffer;
@@ -39,6 +40,7 @@ class DynamicRelocationSection;
 class GnuDebugLinkSection;
 class GroupSection;
 class SectionIndexSection;
+class CompressedSection;
 class Segment;
 class Object;
 struct Symbol;
@@ -86,6 +88,7 @@ public:
   virtual void visit(const GnuDebugLinkSection &Sec) = 0;
   virtual void visit(const GroupSection &Sec) = 0;
   virtual void visit(const SectionIndexSection &Sec) = 0;
+  virtual void visit(const CompressedSection &Sec) = 0;
 };
 
 class SectionWriter : public SectionVisitor {
@@ -104,6 +107,7 @@ public:
   virtual void visit(const GnuDebugLinkSection &Sec) override = 0;
   virtual void visit(const GroupSection &Sec) override = 0;
   virtual void visit(const SectionIndexSection &Sec) override = 0;
+  virtual void visit(const CompressedSection &Sec) override = 0;
 
   explicit SectionWriter(Buffer &Buf) : Out(Buf) {}
 };
@@ -122,6 +126,7 @@ public:
   void visit(const GnuDebugLinkSection &Sec) override;
   void visit(const GroupSection &Sec) override;
   void visit(const SectionIndexSection &Sec) override;
+  void visit(const CompressedSection &Sec) override;
 
   explicit ELFSectionWriter(Buffer &Buf) : SectionWriter(Buf) {}
 };
@@ -139,6 +144,7 @@ public:
   void visit(const GnuDebugLinkSection &Sec) override;
   void visit(const GroupSection &Sec) override;
   void visit(const SectionIndexSection &Sec) override;
+  void visit(const CompressedSection &Sec) override;
 
   explicit BinarySectionWriter(Buffer &Buf) : SectionWriter(Buf) {}
 };
@@ -246,7 +252,7 @@ public:
 
 class SectionBase {
 public:
-  StringRef Name;
+  std::string Name;
   Segment *ParentSegment = nullptr;
   uint64_t HeaderOffset;
   uint64_t OriginalOffset = std::numeric_limits<uint64_t>::max();
@@ -265,6 +271,9 @@ public:
   uint64_t Type = ELF::SHT_NULL;
   ArrayRef<uint8_t> OriginalData;
 
+  SectionBase() = default;
+  SectionBase(const SectionBase &) = default;
+
   virtual ~SectionBase() = default;
 
   virtual void initialize(SectionTableRef SecTable);
@@ -341,7 +350,7 @@ class OwnedDataSection : public SectionB
 public:
   OwnedDataSection(StringRef SecName, ArrayRef<uint8_t> Data)
       : Data(std::begin(Data), std::end(Data)) {
-    Name = SecName;
+    Name = SecName.str();
     Type = ELF::SHT_PROGBITS;
     Size = Data.size();
     OriginalOffset = std::numeric_limits<uint64_t>::max();
@@ -350,6 +359,20 @@ public:
   void accept(SectionVisitor &Sec) const override;
 };
 
+class CompressedSection : public SectionBase {
+  MAKE_SEC_WRITER_FRIEND
+
+  DebugCompressionType CompressionType;
+  uint64_t DecompressedSize;
+  uint64_t DecompressedAlign;
+  SmallVector<char, 128> CompressedData;
+
+public:
+  CompressedSection(const SectionBase &Sec,
+                    DebugCompressionType CompressionType);
+  void accept(SectionVisitor &Visitor) const override;
+};
+
 // There are two types of string tables that can exist, dynamic and not dynamic.
 // In the dynamic case the string table is allocated. Changing a dynamic string
 // table would mean altering virtual addresses and thus the memory image. So

Modified: llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp?rev=341607&r1=341606&r2=341607&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp Thu Sep  6 16:59:50 2018
@@ -17,6 +17,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCTargetOptions.h"
 #include "llvm/Object/Archive.h"
 #include "llvm/Object/ArchiveWriter.h"
 #include "llvm/Object/Binary.h"
@@ -29,6 +30,7 @@
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Compiler.h"
+#include "llvm/Support/Compression.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/ErrorOr.h"
@@ -176,6 +178,7 @@ struct CopyConfig {
   bool StripSections = false;
   bool StripUnneeded = false;
   bool Weaken = false;
+  DebugCompressionType CompressionType = DebugCompressionType::None;
 };
 
 // Configuration for the overall invocation of this tool. When invoked as
@@ -298,12 +301,12 @@ static SectionRename parseRenameSectionV
 }
 
 static bool isDebugSection(const SectionBase &Sec) {
-  return Sec.Name.startswith(".debug") || Sec.Name.startswith(".zdebug") ||
-         Sec.Name == ".gdb_index";
+  return StringRef(Sec.Name).startswith(".debug") ||
+         StringRef(Sec.Name).startswith(".zdebug") || Sec.Name == ".gdb_index";
 }
 
 static bool isDWOSection(const SectionBase &Sec) {
-  return Sec.Name.endswith(".dwo");
+  return StringRef(Sec.Name).endswith(".dwo");
 }
 
 static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
@@ -413,6 +416,49 @@ static Error dumpSectionToFile(StringRef
                                  object_error::parse_failed);
 }
 
+static bool isCompressed(const SectionBase &Section) {
+  ArrayRef<uint8_t> GnuPrefix = {'Z', 'L', 'I', 'B'};
+  return StringRef(Section.Name).startswith(".zdebug") ||
+         (Section.OriginalData.size() > strlen("ZLIB") &&
+          std::equal(GnuPrefix.begin(), GnuPrefix.end(),
+                     Section.OriginalData.data())) ||
+         (Section.Flags & ELF::SHF_COMPRESSED);
+}
+
+static bool isCompressable(const SectionBase &Section) {
+  return !isCompressed(Section) && isDebugSection(Section) &&
+         Section.Name != ".gdb_index";
+}
+
+static void compressSections(const CopyConfig &Config, Object &Obj,
+                             SectionPred &RemovePred) {
+  SmallVector<SectionBase *, 13> ToCompress;
+  SmallVector<RelocationSection *, 13> RelocationSections;
+  for (auto &Sec : Obj.sections()) {
+    if (RelocationSection *R = dyn_cast<RelocationSection>(&Sec)) {
+      if (isCompressable(*R->getSection()))
+        RelocationSections.push_back(R);
+      continue;
+    }
+
+    if (isCompressable(Sec))
+      ToCompress.push_back(&Sec);
+  }
+
+  for (SectionBase *S : ToCompress) {
+    CompressedSection &CS =
+        Obj.addSection<CompressedSection>(*S, Config.CompressionType);
+
+    for (RelocationSection *RS : RelocationSections) {
+      if (RS->getSection() == S)
+        RS->setSection(&CS);
+    }
+  }
+
+  RemovePred = [RemovePred](const SectionBase &Sec) {
+    return isCompressable(Sec) || RemovePred(Sec);
+  };
+}
 // This function handles the high level operations of GNU objcopy including
 // handling command line options. It's important to outline certain properties
 // we expect to hold of the command line operations. Any operation that "keeps"
@@ -572,7 +618,7 @@ static void handleArgs(const CopyConfig
         return true;
       if (&Sec == Obj.SectionNames)
         return false;
-      if (Sec.Name.startswith(".gnu.warning"))
+      if (StringRef(Sec.Name).startswith(".gnu.warning"))
         return false;
       return (Sec.Flags & SHF_ALLOC) == 0;
     };
@@ -624,6 +670,9 @@ static void handleArgs(const CopyConfig
     };
   }
 
+  if (Config.CompressionType != DebugCompressionType::None)
+    compressSections(Config, Obj, RemovePred);
+
   Obj.removeSections(RemovePred);
 
   if (!Config.SectionsToRename.empty()) {
@@ -868,6 +917,25 @@ static DriverConfig parseObjcopyOptions(
     Config.BinaryArch = getMachineInfo(BinaryArch);
   }
 
+  if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
+                                      OBJCOPY_compress_debug_sections_eq)) {
+    Config.CompressionType = DebugCompressionType::Z;
+
+    if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) {
+      Config.CompressionType =
+          StringSwitch<DebugCompressionType>(
+              InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq))
+              .Case("zlib-gnu", DebugCompressionType::GNU)
+              .Case("zlib", DebugCompressionType::Z)
+              .Default(DebugCompressionType::None);
+      if (Config.CompressionType == DebugCompressionType::None)
+        error("Invalid or unsupported --compress-debug-sections format: " +
+              InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq));
+      if (!zlib::isAvailable())
+        error("LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress.");
+    }
+  }
+
   Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
   Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
   Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);




More information about the llvm-commits mailing list