[llvm] r323477 - [llvm-objcopy] Add --add-gnu-debuglink

Jake Ehrlich via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 25 14:15:15 PST 2018


Author: jakehehrlich
Date: Thu Jan 25 14:15:14 2018
New Revision: 323477

URL: http://llvm.org/viewvc/llvm-project?rev=323477&view=rev
Log:
[llvm-objcopy] Add --add-gnu-debuglink

This change adds support for --add-gnu-debuglink to llvm-objcopy

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

Added:
    llvm/trunk/test/tools/llvm-objcopy/add-gnu-debuglink.test
Modified:
    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/add-gnu-debuglink.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/add-gnu-debuglink.test?rev=323477&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/add-gnu-debuglink.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/add-gnu-debuglink.test Thu Jan 25 14:15:14 2018
@@ -0,0 +1,27 @@
+# RUN: yaml2obj %s > %t
+# RUN: printf 0000 > %t.blob
+# RUN: llvm-objcopy -add-gnu-debuglink=%t.blob %t %t2
+# RUN: llvm-readobj -sections -section-data %t2 | FileCheck %s
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_X86_64
+
+# CHECK:       Name: .gnu_debuglink
+# CHECK-NEXT:  Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:  Flags [ (0x0)
+# CHECK-NEXT:  ]
+# CHECK-NEXT:  Address: 0x0
+# CHECK-NEXT:  Offset:
+# CHECK-NEXT:  Size: 32
+# CHECK-NEXT:  Link: 0
+# CHECK-NEXT:  Info: 0
+# CHECK-NEXT:  AddressAlignment: 4
+# CHECK-NEXT:  EntrySize: 0
+# CHECK-NEXT:  SectionData (
+# CHECK-NEXT:      0000: 6164642D 676E752D 64656275 676C696E  |add-gnu-debuglin|
+# CHECK-NEXT:      0010: 6B2E7465 73742E74 6D700000 72C49B0C  |k.test.tmp..r...|
+# CHECK-NEXT:  )

Modified: llvm/trunk/tools/llvm-objcopy/Object.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/Object.cpp?rev=323477&r1=323476&r2=323477&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/Object.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/Object.cpp Thu Jan 25 14:15:14 2018
@@ -18,6 +18,7 @@
 #include "llvm/Object/ELFObjectFile.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Path.h"
 #include <algorithm>
 #include <cstddef>
 #include <cstdint>
@@ -343,6 +344,50 @@ void SectionWithStrTab::initialize(Secti
 
 void SectionWithStrTab::finalize() { this->Link = StrTab->Index; }
 
+template <class ELFT>
+void GnuDebugLinkSection<ELFT>::init(StringRef File, StringRef Data) {
+  FileName = sys::path::stem(File);
+  // The format for the .gnu_debuglink starts with the stemmed file name and is
+  // followed by a null terminator and then the CRC32 of the file. The CRC32
+  // should be 4 byte aligned. So we add the FileName size, a 1 for the null
+  // byte, and then finally push the size to alignment and add 4.
+  Size = alignTo(FileName.size() + 1, 4) + 4;
+  // The CRC32 will only be aligned if we align the whole section.
+  Align = 4;
+  Type = ELF::SHT_PROGBITS;
+  Name = ".gnu_debuglink";
+  // For sections not found in segments, OriginalOffset is only used to
+  // establish the order that sections should go in. By using the maximum
+  // possible offset we cause this section to wind up at the end.
+  OriginalOffset = std::numeric_limits<uint64_t>::max();
+  JamCRC crc;
+  crc.update(ArrayRef<char>(Data.data(), Data.size()));
+  // The CRC32 value needs to be complemented because the JamCRC dosn't
+  // finalize the CRC32 value. It also dosn't negate the initial CRC32 value
+  // but it starts by default at 0xFFFFFFFF which is the complement of zero.
+  CRC32 = ~crc.getCRC();
+}
+
+template <class ELFT>
+GnuDebugLinkSection<ELFT>::GnuDebugLinkSection(StringRef File)
+    : FileName(File) {
+  // Read in the file to compute the CRC of it.
+  auto DebugOrErr = MemoryBuffer::getFile(File);
+  if (!DebugOrErr)
+    error("'" + File + "': " + DebugOrErr.getError().message());
+  auto Debug = std::move(*DebugOrErr);
+  init(File, Debug->getBuffer());
+}
+
+template <class ELFT>
+void GnuDebugLinkSection<ELFT>::writeSection(FileOutputBuffer &Out) const {
+  auto Buf = Out.getBufferStart() + Offset;
+  char *File = reinterpret_cast<char *>(Buf);
+  Elf_Word *CRC = reinterpret_cast<Elf_Word *>(Buf + Size - sizeof(Elf_Word));
+  *CRC = CRC32;
+  std::copy(std::begin(FileName), std::end(FileName), File);
+}
+
 // Returns true IFF a section is wholly inside the range of a segment
 static bool sectionWithinSegment(const SectionBase &Section,
                                  const Segment &Segment) {
@@ -718,6 +763,10 @@ void Object<ELFT>::addSection(StringRef
   Sections.push_back(std::move(Sec));
 }
 
+template <class ELFT> void Object<ELFT>::addGnuDebugLink(StringRef File) {
+  Sections.emplace_back(llvm::make_unique<GnuDebugLinkSection<ELFT>>(File));
+}
+
 template <class ELFT> void ELFObject<ELFT>::sortSections() {
   // Put all sections in offset order. Maintain the ordering as closely as
   // possible while meeting that demand however.

Modified: llvm/trunk/tools/llvm-objcopy/Object.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/Object.h?rev=323477&r1=323476&r2=323477&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/Object.h (original)
+++ llvm/trunk/tools/llvm-objcopy/Object.h Thu Jan 25 14:15:14 2018
@@ -16,6 +16,7 @@
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/MC/StringTableBuilder.h"
 #include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/JamCRC.h"
 #include <cstddef>
 #include <cstdint>
 #include <functional>
@@ -345,6 +346,24 @@ public:
   }
 };
 
+template <class ELFT> class GnuDebugLinkSection : public SectionBase {
+private:
+  // Elf_Word is 4-bytes on every format but has the same endianess as the elf
+  // type ELFT. We'll need to write the CRC32 out in the proper endianess so
+  // we'll make sure to use this type.
+  using Elf_Word = typename ELFT::Word;
+
+  StringRef FileName;
+  uint32_t CRC32;
+
+  void init(StringRef File, StringRef Data);
+
+public:
+  // If we add this section from an external source we can use this ctor.
+  GnuDebugLinkSection(StringRef File);
+  void writeSection(FileOutputBuffer &Out) const override;
+};
+
 template <class ELFT> class Object {
 private:
   using SecPtr = std::unique_ptr<SectionBase>;
@@ -389,6 +408,7 @@ public:
   const SectionBase *getSectionHeaderStrTab() const { return SectionNames; }
   void removeSections(std::function<bool(const SectionBase &)> ToRemove);
   void addSection(StringRef SecName, ArrayRef<uint8_t> Data);
+  void addGnuDebugLink(StringRef File);
   virtual size_t totalSize() const = 0;
   virtual void finalize() = 0;
   virtual void write(FileOutputBuffer &Out) const = 0;

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=323477&r1=323476&r2=323477&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp Thu Jan 25 14:15:14 2018
@@ -121,6 +121,10 @@ static cl::opt<bool> LocalizeHidden(
     "localize-hidden",
     cl::desc(
         "Mark all symbols that have hidden or internal visibility as local"));
+static cl::opt<std::string>
+    AddGnuDebugLink("add-gnu-debuglink",
+                    cl::desc("adds a .gnu_debuglink for <debug-file>"),
+                    cl::value_desc("debug-file"));
 
 using SectionPred = std::function<bool(const SectionBase &Sec)>;
 
@@ -318,6 +322,10 @@ template <class ELFT> void CopyBinary(co
     }
   }
 
+  if (!AddGnuDebugLink.empty()) {
+    Obj->addGnuDebugLink(AddGnuDebugLink);
+  }
+
   Obj->finalize();
   WriteObjectFile(*Obj, OutputFilename.getValue());
 }




More information about the llvm-commits mailing list