From: Jake Ehrlich Date: Thu, 25 Jan 2018 22:15:14 +0000 (+0000) Subject: [llvm-objcopy] Add --add-gnu-debuglink X-Git-Tag: android-x86-7.1-r4~5825 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=f0c7c0917c43e858d7aa5ab5e54d7a00d1498ebd;p=android-x86%2Fexternal-llvm.git [llvm-objcopy] Add --add-gnu-debuglink This change adds support for --add-gnu-debuglink to llvm-objcopy Differential Revision: https://reviews.llvm.org/D41731 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@323477 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/test/tools/llvm-objcopy/add-gnu-debuglink.test b/test/tools/llvm-objcopy/add-gnu-debuglink.test new file mode 100644 index 00000000000..c858640ffa2 --- /dev/null +++ b/test/tools/llvm-objcopy/add-gnu-debuglink.test @@ -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: ) diff --git a/tools/llvm-objcopy/Object.cpp b/tools/llvm-objcopy/Object.cpp index 41c76f863fe..944075d6197 100644 --- a/tools/llvm-objcopy/Object.cpp +++ b/tools/llvm-objcopy/Object.cpp @@ -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 #include #include @@ -343,6 +344,50 @@ void SectionWithStrTab::initialize(SectionTableRef SecTable) { void SectionWithStrTab::finalize() { this->Link = StrTab->Index; } +template +void GnuDebugLinkSection::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::max(); + JamCRC crc; + crc.update(ArrayRef(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 +GnuDebugLinkSection::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 +void GnuDebugLinkSection::writeSection(FileOutputBuffer &Out) const { + auto Buf = Out.getBufferStart() + Offset; + char *File = reinterpret_cast(Buf); + Elf_Word *CRC = reinterpret_cast(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::addSection(StringRef SecName, ArrayRef Data) { Sections.push_back(std::move(Sec)); } +template void Object::addGnuDebugLink(StringRef File) { + Sections.emplace_back(llvm::make_unique>(File)); +} + template void ELFObject::sortSections() { // Put all sections in offset order. Maintain the ordering as closely as // possible while meeting that demand however. diff --git a/tools/llvm-objcopy/Object.h b/tools/llvm-objcopy/Object.h index 17ea6c9413b..6ac7edd32ae 100644 --- a/tools/llvm-objcopy/Object.h +++ b/tools/llvm-objcopy/Object.h @@ -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 #include #include @@ -345,6 +346,24 @@ public: } }; +template 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 Object { private: using SecPtr = std::unique_ptr; @@ -389,6 +408,7 @@ public: const SectionBase *getSectionHeaderStrTab() const { return SectionNames; } void removeSections(std::function ToRemove); void addSection(StringRef SecName, ArrayRef Data); + void addGnuDebugLink(StringRef File); virtual size_t totalSize() const = 0; virtual void finalize() = 0; virtual void write(FileOutputBuffer &Out) const = 0; diff --git a/tools/llvm-objcopy/llvm-objcopy.cpp b/tools/llvm-objcopy/llvm-objcopy.cpp index eb1d0de90d5..0b09184497d 100644 --- a/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/tools/llvm-objcopy/llvm-objcopy.cpp @@ -121,6 +121,10 @@ static cl::opt LocalizeHidden( "localize-hidden", cl::desc( "Mark all symbols that have hidden or internal visibility as local")); +static cl::opt + AddGnuDebugLink("add-gnu-debuglink", + cl::desc("adds a .gnu_debuglink for "), + cl::value_desc("debug-file")); using SectionPred = std::function; @@ -318,6 +322,10 @@ template void CopyBinary(const ELFObjectFile &ObjFile) { } } + if (!AddGnuDebugLink.empty()) { + Obj->addGnuDebugLink(AddGnuDebugLink); + } + Obj->finalize(); WriteObjectFile(*Obj, OutputFilename.getValue()); }