summaryrefslogtreecommitdiffstats
path: root/llvm/tools/llvm-objcopy/Object.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-objcopy/Object.cpp')
-rw-r--r--llvm/tools/llvm-objcopy/Object.cpp49
1 files changed, 49 insertions, 0 deletions
diff --git a/llvm/tools/llvm-objcopy/Object.cpp b/llvm/tools/llvm-objcopy/Object.cpp
index 41c76f863fe..944075d6197 100644
--- a/llvm/tools/llvm-objcopy/Object.cpp
+++ b/llvm/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 <algorithm>
#include <cstddef>
#include <cstdint>
@@ -343,6 +344,50 @@ void SectionWithStrTab::initialize(SectionTableRef SecTable) {
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 SecName, ArrayRef<uint8_t> Data) {
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.
OpenPOWER on IntegriCloud