1*da58b97aSjoerg //===---- DebugObjectManagerPlugin.h - JITLink debug objects ---*- C++ -*-===//
2*da58b97aSjoerg //
3*da58b97aSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*da58b97aSjoerg // See https://llvm.org/LICENSE.txt for license information.
5*da58b97aSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*da58b97aSjoerg //
7*da58b97aSjoerg //===----------------------------------------------------------------------===//
8*da58b97aSjoerg
9*da58b97aSjoerg #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
10*da58b97aSjoerg
11*da58b97aSjoerg #include "llvm/ADT/ArrayRef.h"
12*da58b97aSjoerg #include "llvm/ADT/StringMap.h"
13*da58b97aSjoerg #include "llvm/ADT/StringRef.h"
14*da58b97aSjoerg #include "llvm/BinaryFormat/ELF.h"
15*da58b97aSjoerg #include "llvm/ExecutionEngine/JITLink/JITLinkDylib.h"
16*da58b97aSjoerg #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
17*da58b97aSjoerg #include "llvm/ExecutionEngine/JITSymbol.h"
18*da58b97aSjoerg #include "llvm/Object/ELFObjectFile.h"
19*da58b97aSjoerg #include "llvm/Object/ObjectFile.h"
20*da58b97aSjoerg #include "llvm/Support/Errc.h"
21*da58b97aSjoerg #include "llvm/Support/MSVCErrorWorkarounds.h"
22*da58b97aSjoerg #include "llvm/Support/MemoryBuffer.h"
23*da58b97aSjoerg #include "llvm/Support/Process.h"
24*da58b97aSjoerg #include "llvm/Support/raw_ostream.h"
25*da58b97aSjoerg
26*da58b97aSjoerg #include <set>
27*da58b97aSjoerg
28*da58b97aSjoerg #define DEBUG_TYPE "orc"
29*da58b97aSjoerg
30*da58b97aSjoerg using namespace llvm::jitlink;
31*da58b97aSjoerg using namespace llvm::object;
32*da58b97aSjoerg
33*da58b97aSjoerg namespace llvm {
34*da58b97aSjoerg namespace orc {
35*da58b97aSjoerg
36*da58b97aSjoerg class DebugObjectSection {
37*da58b97aSjoerg public:
38*da58b97aSjoerg virtual void setTargetMemoryRange(SectionRange Range) = 0;
dump(raw_ostream & OS,StringRef Name)39*da58b97aSjoerg virtual void dump(raw_ostream &OS, StringRef Name) {}
~DebugObjectSection()40*da58b97aSjoerg virtual ~DebugObjectSection() {}
41*da58b97aSjoerg };
42*da58b97aSjoerg
43*da58b97aSjoerg template <typename ELFT>
44*da58b97aSjoerg class ELFDebugObjectSection : public DebugObjectSection {
45*da58b97aSjoerg public:
46*da58b97aSjoerg // BinaryFormat ELF is not meant as a mutable format. We can only make changes
47*da58b97aSjoerg // that don't invalidate the file structure.
ELFDebugObjectSection(const typename ELFT::Shdr * Header)48*da58b97aSjoerg ELFDebugObjectSection(const typename ELFT::Shdr *Header)
49*da58b97aSjoerg : Header(const_cast<typename ELFT::Shdr *>(Header)) {}
50*da58b97aSjoerg
51*da58b97aSjoerg void setTargetMemoryRange(SectionRange Range) override;
52*da58b97aSjoerg void dump(raw_ostream &OS, StringRef Name) override;
53*da58b97aSjoerg
54*da58b97aSjoerg Error validateInBounds(StringRef Buffer, const char *Name) const;
55*da58b97aSjoerg
56*da58b97aSjoerg private:
57*da58b97aSjoerg typename ELFT::Shdr *Header;
58*da58b97aSjoerg
59*da58b97aSjoerg bool isTextOrDataSection() const;
60*da58b97aSjoerg };
61*da58b97aSjoerg
62*da58b97aSjoerg template <typename ELFT>
setTargetMemoryRange(SectionRange Range)63*da58b97aSjoerg void ELFDebugObjectSection<ELFT>::setTargetMemoryRange(SectionRange Range) {
64*da58b97aSjoerg // Only patch load-addresses for executable and data sections.
65*da58b97aSjoerg if (isTextOrDataSection()) {
66*da58b97aSjoerg Header->sh_addr = static_cast<typename ELFT::uint>(Range.getStart());
67*da58b97aSjoerg }
68*da58b97aSjoerg }
69*da58b97aSjoerg
70*da58b97aSjoerg template <typename ELFT>
isTextOrDataSection() const71*da58b97aSjoerg bool ELFDebugObjectSection<ELFT>::isTextOrDataSection() const {
72*da58b97aSjoerg switch (Header->sh_type) {
73*da58b97aSjoerg case ELF::SHT_PROGBITS:
74*da58b97aSjoerg case ELF::SHT_X86_64_UNWIND:
75*da58b97aSjoerg return Header->sh_flags & (ELF::SHF_EXECINSTR | ELF::SHF_ALLOC);
76*da58b97aSjoerg }
77*da58b97aSjoerg return false;
78*da58b97aSjoerg }
79*da58b97aSjoerg
80*da58b97aSjoerg template <typename ELFT>
validateInBounds(StringRef Buffer,const char * Name) const81*da58b97aSjoerg Error ELFDebugObjectSection<ELFT>::validateInBounds(StringRef Buffer,
82*da58b97aSjoerg const char *Name) const {
83*da58b97aSjoerg const uint8_t *Start = Buffer.bytes_begin();
84*da58b97aSjoerg const uint8_t *End = Buffer.bytes_end();
85*da58b97aSjoerg const uint8_t *HeaderPtr = reinterpret_cast<uint8_t *>(Header);
86*da58b97aSjoerg if (HeaderPtr < Start || HeaderPtr + sizeof(typename ELFT::Shdr) > End)
87*da58b97aSjoerg return make_error<StringError>(
88*da58b97aSjoerg formatv("{0} section header at {1:x16} not within bounds of the "
89*da58b97aSjoerg "given debug object buffer [{2:x16} - {3:x16}]",
90*da58b97aSjoerg Name, &Header->sh_addr, Start, End),
91*da58b97aSjoerg inconvertibleErrorCode());
92*da58b97aSjoerg if (Header->sh_offset + Header->sh_size > Buffer.size())
93*da58b97aSjoerg return make_error<StringError>(
94*da58b97aSjoerg formatv("{0} section data [{1:x16} - {2:x16}] not within bounds of "
95*da58b97aSjoerg "the given debug object buffer [{3:x16} - {4:x16}]",
96*da58b97aSjoerg Name, Start + Header->sh_offset,
97*da58b97aSjoerg Start + Header->sh_offset + Header->sh_size, Start, End),
98*da58b97aSjoerg inconvertibleErrorCode());
99*da58b97aSjoerg return Error::success();
100*da58b97aSjoerg }
101*da58b97aSjoerg
102*da58b97aSjoerg template <typename ELFT>
dump(raw_ostream & OS,StringRef Name)103*da58b97aSjoerg void ELFDebugObjectSection<ELFT>::dump(raw_ostream &OS, StringRef Name) {
104*da58b97aSjoerg if (auto Addr = static_cast<JITTargetAddress>(Header->sh_addr)) {
105*da58b97aSjoerg OS << formatv(" {0:x16} {1}\n", Addr, Name);
106*da58b97aSjoerg } else {
107*da58b97aSjoerg OS << formatv(" {0}\n", Name);
108*da58b97aSjoerg }
109*da58b97aSjoerg }
110*da58b97aSjoerg
111*da58b97aSjoerg static constexpr sys::Memory::ProtectionFlags ReadOnly =
112*da58b97aSjoerg static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ);
113*da58b97aSjoerg
114*da58b97aSjoerg enum class Requirement {
115*da58b97aSjoerg // Request final target memory load-addresses for all sections.
116*da58b97aSjoerg ReportFinalSectionLoadAddresses,
117*da58b97aSjoerg };
118*da58b97aSjoerg
119*da58b97aSjoerg /// The plugin creates a debug object from JITLinkContext when JITLink starts
120*da58b97aSjoerg /// processing the corresponding LinkGraph. It provides access to the pass
121*da58b97aSjoerg /// configuration of the LinkGraph and calls the finalization function, once
122*da58b97aSjoerg /// the resulting link artifact was emitted.
123*da58b97aSjoerg ///
124*da58b97aSjoerg class DebugObject {
125*da58b97aSjoerg public:
DebugObject(JITLinkContext & Ctx,ExecutionSession & ES)126*da58b97aSjoerg DebugObject(JITLinkContext &Ctx, ExecutionSession &ES) : Ctx(Ctx), ES(ES) {}
127*da58b97aSjoerg
set(Requirement Req)128*da58b97aSjoerg void set(Requirement Req) { Reqs.insert(Req); }
has(Requirement Req) const129*da58b97aSjoerg bool has(Requirement Req) const { return Reqs.count(Req) > 0; }
130*da58b97aSjoerg
131*da58b97aSjoerg using FinalizeContinuation = std::function<void(Expected<sys::MemoryBlock>)>;
132*da58b97aSjoerg void finalizeAsync(FinalizeContinuation OnFinalize);
133*da58b97aSjoerg
~DebugObject()134*da58b97aSjoerg virtual ~DebugObject() {
135*da58b97aSjoerg if (Alloc)
136*da58b97aSjoerg if (Error Err = Alloc->deallocate())
137*da58b97aSjoerg ES.reportError(std::move(Err));
138*da58b97aSjoerg }
139*da58b97aSjoerg
reportSectionTargetMemoryRange(StringRef Name,SectionRange TargetMem)140*da58b97aSjoerg virtual void reportSectionTargetMemoryRange(StringRef Name,
141*da58b97aSjoerg SectionRange TargetMem) {}
142*da58b97aSjoerg
143*da58b97aSjoerg protected:
144*da58b97aSjoerg using Allocation = JITLinkMemoryManager::Allocation;
145*da58b97aSjoerg
146*da58b97aSjoerg virtual Expected<std::unique_ptr<Allocation>>
147*da58b97aSjoerg finalizeWorkingMemory(JITLinkContext &Ctx) = 0;
148*da58b97aSjoerg
149*da58b97aSjoerg private:
150*da58b97aSjoerg JITLinkContext &Ctx;
151*da58b97aSjoerg ExecutionSession &ES;
152*da58b97aSjoerg std::set<Requirement> Reqs;
153*da58b97aSjoerg std::unique_ptr<Allocation> Alloc{nullptr};
154*da58b97aSjoerg };
155*da58b97aSjoerg
156*da58b97aSjoerg // Finalize working memory and take ownership of the resulting allocation. Start
157*da58b97aSjoerg // copying memory over to the target and pass on the result once we're done.
158*da58b97aSjoerg // Ownership of the allocation remains with us for the rest of our lifetime.
finalizeAsync(FinalizeContinuation OnFinalize)159*da58b97aSjoerg void DebugObject::finalizeAsync(FinalizeContinuation OnFinalize) {
160*da58b97aSjoerg assert(Alloc == nullptr && "Cannot finalize more than once");
161*da58b97aSjoerg
162*da58b97aSjoerg auto AllocOrErr = finalizeWorkingMemory(Ctx);
163*da58b97aSjoerg if (!AllocOrErr)
164*da58b97aSjoerg OnFinalize(AllocOrErr.takeError());
165*da58b97aSjoerg Alloc = std::move(*AllocOrErr);
166*da58b97aSjoerg
167*da58b97aSjoerg Alloc->finalizeAsync([this, OnFinalize](Error Err) {
168*da58b97aSjoerg if (Err)
169*da58b97aSjoerg OnFinalize(std::move(Err));
170*da58b97aSjoerg else
171*da58b97aSjoerg OnFinalize(sys::MemoryBlock(
172*da58b97aSjoerg jitTargetAddressToPointer<void *>(Alloc->getTargetMemory(ReadOnly)),
173*da58b97aSjoerg Alloc->getWorkingMemory(ReadOnly).size()));
174*da58b97aSjoerg });
175*da58b97aSjoerg }
176*da58b97aSjoerg
177*da58b97aSjoerg /// The current implementation of ELFDebugObject replicates the approach used in
178*da58b97aSjoerg /// RuntimeDyld: It patches executable and data section headers in the given
179*da58b97aSjoerg /// object buffer with load-addresses of their corresponding sections in target
180*da58b97aSjoerg /// memory.
181*da58b97aSjoerg ///
182*da58b97aSjoerg class ELFDebugObject : public DebugObject {
183*da58b97aSjoerg public:
184*da58b97aSjoerg static Expected<std::unique_ptr<DebugObject>>
185*da58b97aSjoerg Create(MemoryBufferRef Buffer, JITLinkContext &Ctx, ExecutionSession &ES);
186*da58b97aSjoerg
187*da58b97aSjoerg void reportSectionTargetMemoryRange(StringRef Name,
188*da58b97aSjoerg SectionRange TargetMem) override;
189*da58b97aSjoerg
getBuffer() const190*da58b97aSjoerg StringRef getBuffer() const { return Buffer->getMemBufferRef().getBuffer(); }
191*da58b97aSjoerg
192*da58b97aSjoerg protected:
193*da58b97aSjoerg Expected<std::unique_ptr<Allocation>>
194*da58b97aSjoerg finalizeWorkingMemory(JITLinkContext &Ctx) override;
195*da58b97aSjoerg
196*da58b97aSjoerg template <typename ELFT>
197*da58b97aSjoerg Error recordSection(StringRef Name,
198*da58b97aSjoerg std::unique_ptr<ELFDebugObjectSection<ELFT>> Section);
199*da58b97aSjoerg DebugObjectSection *getSection(StringRef Name);
200*da58b97aSjoerg
201*da58b97aSjoerg private:
202*da58b97aSjoerg template <typename ELFT>
203*da58b97aSjoerg static Expected<std::unique_ptr<ELFDebugObject>>
204*da58b97aSjoerg CreateArchType(MemoryBufferRef Buffer, JITLinkContext &Ctx,
205*da58b97aSjoerg ExecutionSession &ES);
206*da58b97aSjoerg
207*da58b97aSjoerg static std::unique_ptr<WritableMemoryBuffer>
208*da58b97aSjoerg CopyBuffer(MemoryBufferRef Buffer, Error &Err);
209*da58b97aSjoerg
ELFDebugObject(std::unique_ptr<WritableMemoryBuffer> Buffer,JITLinkContext & Ctx,ExecutionSession & ES)210*da58b97aSjoerg ELFDebugObject(std::unique_ptr<WritableMemoryBuffer> Buffer,
211*da58b97aSjoerg JITLinkContext &Ctx, ExecutionSession &ES)
212*da58b97aSjoerg : DebugObject(Ctx, ES), Buffer(std::move(Buffer)) {
213*da58b97aSjoerg set(Requirement::ReportFinalSectionLoadAddresses);
214*da58b97aSjoerg }
215*da58b97aSjoerg
216*da58b97aSjoerg std::unique_ptr<WritableMemoryBuffer> Buffer;
217*da58b97aSjoerg StringMap<std::unique_ptr<DebugObjectSection>> Sections;
218*da58b97aSjoerg };
219*da58b97aSjoerg
220*da58b97aSjoerg static const std::set<StringRef> DwarfSectionNames = {
221*da58b97aSjoerg #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION) \
222*da58b97aSjoerg ELF_NAME,
223*da58b97aSjoerg #include "llvm/BinaryFormat/Dwarf.def"
224*da58b97aSjoerg #undef HANDLE_DWARF_SECTION
225*da58b97aSjoerg };
226*da58b97aSjoerg
isDwarfSection(StringRef SectionName)227*da58b97aSjoerg static bool isDwarfSection(StringRef SectionName) {
228*da58b97aSjoerg return DwarfSectionNames.count(SectionName) == 1;
229*da58b97aSjoerg }
230*da58b97aSjoerg
231*da58b97aSjoerg std::unique_ptr<WritableMemoryBuffer>
CopyBuffer(MemoryBufferRef Buffer,Error & Err)232*da58b97aSjoerg ELFDebugObject::CopyBuffer(MemoryBufferRef Buffer, Error &Err) {
233*da58b97aSjoerg ErrorAsOutParameter _(&Err);
234*da58b97aSjoerg size_t Size = Buffer.getBufferSize();
235*da58b97aSjoerg StringRef Name = Buffer.getBufferIdentifier();
236*da58b97aSjoerg if (auto Copy = WritableMemoryBuffer::getNewUninitMemBuffer(Size, Name)) {
237*da58b97aSjoerg memcpy(Copy->getBufferStart(), Buffer.getBufferStart(), Size);
238*da58b97aSjoerg return Copy;
239*da58b97aSjoerg }
240*da58b97aSjoerg
241*da58b97aSjoerg Err = errorCodeToError(make_error_code(errc::not_enough_memory));
242*da58b97aSjoerg return nullptr;
243*da58b97aSjoerg }
244*da58b97aSjoerg
245*da58b97aSjoerg template <typename ELFT>
246*da58b97aSjoerg Expected<std::unique_ptr<ELFDebugObject>>
CreateArchType(MemoryBufferRef Buffer,JITLinkContext & Ctx,ExecutionSession & ES)247*da58b97aSjoerg ELFDebugObject::CreateArchType(MemoryBufferRef Buffer, JITLinkContext &Ctx,
248*da58b97aSjoerg ExecutionSession &ES) {
249*da58b97aSjoerg using SectionHeader = typename ELFT::Shdr;
250*da58b97aSjoerg
251*da58b97aSjoerg Error Err = Error::success();
252*da58b97aSjoerg std::unique_ptr<ELFDebugObject> DebugObj(
253*da58b97aSjoerg new ELFDebugObject(CopyBuffer(Buffer, Err), Ctx, ES));
254*da58b97aSjoerg if (Err)
255*da58b97aSjoerg return std::move(Err);
256*da58b97aSjoerg
257*da58b97aSjoerg Expected<ELFFile<ELFT>> ObjRef = ELFFile<ELFT>::create(DebugObj->getBuffer());
258*da58b97aSjoerg if (!ObjRef)
259*da58b97aSjoerg return ObjRef.takeError();
260*da58b97aSjoerg
261*da58b97aSjoerg // TODO: Add support for other architectures.
262*da58b97aSjoerg uint16_t TargetMachineArch = ObjRef->getHeader().e_machine;
263*da58b97aSjoerg if (TargetMachineArch != ELF::EM_X86_64)
264*da58b97aSjoerg return nullptr;
265*da58b97aSjoerg
266*da58b97aSjoerg Expected<ArrayRef<SectionHeader>> Sections = ObjRef->sections();
267*da58b97aSjoerg if (!Sections)
268*da58b97aSjoerg return Sections.takeError();
269*da58b97aSjoerg
270*da58b97aSjoerg bool HasDwarfSection = false;
271*da58b97aSjoerg for (const SectionHeader &Header : *Sections) {
272*da58b97aSjoerg Expected<StringRef> Name = ObjRef->getSectionName(Header);
273*da58b97aSjoerg if (!Name)
274*da58b97aSjoerg return Name.takeError();
275*da58b97aSjoerg if (Name->empty())
276*da58b97aSjoerg continue;
277*da58b97aSjoerg HasDwarfSection |= isDwarfSection(*Name);
278*da58b97aSjoerg
279*da58b97aSjoerg auto Wrapped = std::make_unique<ELFDebugObjectSection<ELFT>>(&Header);
280*da58b97aSjoerg if (Error Err = DebugObj->recordSection(*Name, std::move(Wrapped)))
281*da58b97aSjoerg return std::move(Err);
282*da58b97aSjoerg }
283*da58b97aSjoerg
284*da58b97aSjoerg if (!HasDwarfSection) {
285*da58b97aSjoerg LLVM_DEBUG(dbgs() << "Aborting debug registration for LinkGraph \""
286*da58b97aSjoerg << DebugObj->Buffer->getBufferIdentifier()
287*da58b97aSjoerg << "\": input object contains no debug info\n");
288*da58b97aSjoerg return nullptr;
289*da58b97aSjoerg }
290*da58b97aSjoerg
291*da58b97aSjoerg return std::move(DebugObj);
292*da58b97aSjoerg }
293*da58b97aSjoerg
294*da58b97aSjoerg Expected<std::unique_ptr<DebugObject>>
Create(MemoryBufferRef Buffer,JITLinkContext & Ctx,ExecutionSession & ES)295*da58b97aSjoerg ELFDebugObject::Create(MemoryBufferRef Buffer, JITLinkContext &Ctx,
296*da58b97aSjoerg ExecutionSession &ES) {
297*da58b97aSjoerg unsigned char Class, Endian;
298*da58b97aSjoerg std::tie(Class, Endian) = getElfArchType(Buffer.getBuffer());
299*da58b97aSjoerg
300*da58b97aSjoerg if (Class == ELF::ELFCLASS32) {
301*da58b97aSjoerg if (Endian == ELF::ELFDATA2LSB)
302*da58b97aSjoerg return CreateArchType<ELF32LE>(Buffer, Ctx, ES);
303*da58b97aSjoerg if (Endian == ELF::ELFDATA2MSB)
304*da58b97aSjoerg return CreateArchType<ELF32BE>(Buffer, Ctx, ES);
305*da58b97aSjoerg return nullptr;
306*da58b97aSjoerg }
307*da58b97aSjoerg if (Class == ELF::ELFCLASS64) {
308*da58b97aSjoerg if (Endian == ELF::ELFDATA2LSB)
309*da58b97aSjoerg return CreateArchType<ELF64LE>(Buffer, Ctx, ES);
310*da58b97aSjoerg if (Endian == ELF::ELFDATA2MSB)
311*da58b97aSjoerg return CreateArchType<ELF64BE>(Buffer, Ctx, ES);
312*da58b97aSjoerg return nullptr;
313*da58b97aSjoerg }
314*da58b97aSjoerg return nullptr;
315*da58b97aSjoerg }
316*da58b97aSjoerg
317*da58b97aSjoerg Expected<std::unique_ptr<DebugObject::Allocation>>
finalizeWorkingMemory(JITLinkContext & Ctx)318*da58b97aSjoerg ELFDebugObject::finalizeWorkingMemory(JITLinkContext &Ctx) {
319*da58b97aSjoerg LLVM_DEBUG({
320*da58b97aSjoerg dbgs() << "Section load-addresses in debug object for \""
321*da58b97aSjoerg << Buffer->getBufferIdentifier() << "\":\n";
322*da58b97aSjoerg for (const auto &KV : Sections)
323*da58b97aSjoerg KV.second->dump(dbgs(), KV.first());
324*da58b97aSjoerg });
325*da58b97aSjoerg
326*da58b97aSjoerg // TODO: This works, but what actual alignment requirements do we have?
327*da58b97aSjoerg unsigned Alignment = sys::Process::getPageSizeEstimate();
328*da58b97aSjoerg JITLinkMemoryManager &MemMgr = Ctx.getMemoryManager();
329*da58b97aSjoerg const JITLinkDylib *JD = Ctx.getJITLinkDylib();
330*da58b97aSjoerg size_t Size = Buffer->getBufferSize();
331*da58b97aSjoerg
332*da58b97aSjoerg // Allocate working memory for debug object in read-only segment.
333*da58b97aSjoerg JITLinkMemoryManager::SegmentsRequestMap SingleReadOnlySegment;
334*da58b97aSjoerg SingleReadOnlySegment[ReadOnly] =
335*da58b97aSjoerg JITLinkMemoryManager::SegmentRequest(Alignment, Size, 0);
336*da58b97aSjoerg
337*da58b97aSjoerg auto AllocOrErr = MemMgr.allocate(JD, SingleReadOnlySegment);
338*da58b97aSjoerg if (!AllocOrErr)
339*da58b97aSjoerg return AllocOrErr.takeError();
340*da58b97aSjoerg
341*da58b97aSjoerg // Initialize working memory with a copy of our object buffer.
342*da58b97aSjoerg // TODO: Use our buffer as working memory directly.
343*da58b97aSjoerg std::unique_ptr<Allocation> Alloc = std::move(*AllocOrErr);
344*da58b97aSjoerg MutableArrayRef<char> WorkingMem = Alloc->getWorkingMemory(ReadOnly);
345*da58b97aSjoerg memcpy(WorkingMem.data(), Buffer->getBufferStart(), Size);
346*da58b97aSjoerg Buffer.reset();
347*da58b97aSjoerg
348*da58b97aSjoerg return std::move(Alloc);
349*da58b97aSjoerg }
350*da58b97aSjoerg
reportSectionTargetMemoryRange(StringRef Name,SectionRange TargetMem)351*da58b97aSjoerg void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name,
352*da58b97aSjoerg SectionRange TargetMem) {
353*da58b97aSjoerg if (auto *DebugObjSection = getSection(Name))
354*da58b97aSjoerg DebugObjSection->setTargetMemoryRange(TargetMem);
355*da58b97aSjoerg }
356*da58b97aSjoerg
357*da58b97aSjoerg template <typename ELFT>
recordSection(StringRef Name,std::unique_ptr<ELFDebugObjectSection<ELFT>> Section)358*da58b97aSjoerg Error ELFDebugObject::recordSection(
359*da58b97aSjoerg StringRef Name, std::unique_ptr<ELFDebugObjectSection<ELFT>> Section) {
360*da58b97aSjoerg if (Error Err = Section->validateInBounds(this->getBuffer(), Name.data()))
361*da58b97aSjoerg return Err;
362*da58b97aSjoerg auto ItInserted = Sections.try_emplace(Name, std::move(Section));
363*da58b97aSjoerg if (!ItInserted.second)
364*da58b97aSjoerg return make_error<StringError>("Duplicate section",
365*da58b97aSjoerg inconvertibleErrorCode());
366*da58b97aSjoerg return Error::success();
367*da58b97aSjoerg }
368*da58b97aSjoerg
getSection(StringRef Name)369*da58b97aSjoerg DebugObjectSection *ELFDebugObject::getSection(StringRef Name) {
370*da58b97aSjoerg auto It = Sections.find(Name);
371*da58b97aSjoerg return It == Sections.end() ? nullptr : It->second.get();
372*da58b97aSjoerg }
373*da58b97aSjoerg
374*da58b97aSjoerg /// Creates a debug object based on the input object file from
375*da58b97aSjoerg /// ObjectLinkingLayerJITLinkContext.
376*da58b97aSjoerg ///
377*da58b97aSjoerg static Expected<std::unique_ptr<DebugObject>>
createDebugObjectFromBuffer(ExecutionSession & ES,LinkGraph & G,JITLinkContext & Ctx,MemoryBufferRef ObjBuffer)378*da58b97aSjoerg createDebugObjectFromBuffer(ExecutionSession &ES, LinkGraph &G,
379*da58b97aSjoerg JITLinkContext &Ctx, MemoryBufferRef ObjBuffer) {
380*da58b97aSjoerg switch (G.getTargetTriple().getObjectFormat()) {
381*da58b97aSjoerg case Triple::ELF:
382*da58b97aSjoerg return ELFDebugObject::Create(ObjBuffer, Ctx, ES);
383*da58b97aSjoerg
384*da58b97aSjoerg default:
385*da58b97aSjoerg // TODO: Once we add support for other formats, we might want to split this
386*da58b97aSjoerg // into multiple files.
387*da58b97aSjoerg return nullptr;
388*da58b97aSjoerg }
389*da58b97aSjoerg }
390*da58b97aSjoerg
DebugObjectManagerPlugin(ExecutionSession & ES,std::unique_ptr<DebugObjectRegistrar> Target)391*da58b97aSjoerg DebugObjectManagerPlugin::DebugObjectManagerPlugin(
392*da58b97aSjoerg ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target)
393*da58b97aSjoerg : ES(ES), Target(std::move(Target)) {}
394*da58b97aSjoerg
395*da58b97aSjoerg DebugObjectManagerPlugin::~DebugObjectManagerPlugin() = default;
396*da58b97aSjoerg
notifyMaterializing(MaterializationResponsibility & MR,LinkGraph & G,JITLinkContext & Ctx,MemoryBufferRef ObjBuffer)397*da58b97aSjoerg void DebugObjectManagerPlugin::notifyMaterializing(
398*da58b97aSjoerg MaterializationResponsibility &MR, LinkGraph &G, JITLinkContext &Ctx,
399*da58b97aSjoerg MemoryBufferRef ObjBuffer) {
400*da58b97aSjoerg std::lock_guard<std::mutex> Lock(PendingObjsLock);
401*da58b97aSjoerg assert(PendingObjs.count(&MR) == 0 &&
402*da58b97aSjoerg "Cannot have more than one pending debug object per "
403*da58b97aSjoerg "MaterializationResponsibility");
404*da58b97aSjoerg
405*da58b97aSjoerg if (auto DebugObj = createDebugObjectFromBuffer(ES, G, Ctx, ObjBuffer)) {
406*da58b97aSjoerg // Not all link artifacts allow debugging.
407*da58b97aSjoerg if (*DebugObj != nullptr)
408*da58b97aSjoerg PendingObjs[&MR] = std::move(*DebugObj);
409*da58b97aSjoerg } else {
410*da58b97aSjoerg ES.reportError(DebugObj.takeError());
411*da58b97aSjoerg }
412*da58b97aSjoerg }
413*da58b97aSjoerg
modifyPassConfig(MaterializationResponsibility & MR,LinkGraph & G,PassConfiguration & PassConfig)414*da58b97aSjoerg void DebugObjectManagerPlugin::modifyPassConfig(
415*da58b97aSjoerg MaterializationResponsibility &MR, LinkGraph &G,
416*da58b97aSjoerg PassConfiguration &PassConfig) {
417*da58b97aSjoerg // Not all link artifacts have associated debug objects.
418*da58b97aSjoerg std::lock_guard<std::mutex> Lock(PendingObjsLock);
419*da58b97aSjoerg auto It = PendingObjs.find(&MR);
420*da58b97aSjoerg if (It == PendingObjs.end())
421*da58b97aSjoerg return;
422*da58b97aSjoerg
423*da58b97aSjoerg DebugObject &DebugObj = *It->second;
424*da58b97aSjoerg if (DebugObj.has(Requirement::ReportFinalSectionLoadAddresses)) {
425*da58b97aSjoerg PassConfig.PostAllocationPasses.push_back(
426*da58b97aSjoerg [&DebugObj](LinkGraph &Graph) -> Error {
427*da58b97aSjoerg for (const Section &GraphSection : Graph.sections())
428*da58b97aSjoerg DebugObj.reportSectionTargetMemoryRange(GraphSection.getName(),
429*da58b97aSjoerg SectionRange(GraphSection));
430*da58b97aSjoerg return Error::success();
431*da58b97aSjoerg });
432*da58b97aSjoerg }
433*da58b97aSjoerg }
434*da58b97aSjoerg
notifyEmitted(MaterializationResponsibility & MR)435*da58b97aSjoerg Error DebugObjectManagerPlugin::notifyEmitted(
436*da58b97aSjoerg MaterializationResponsibility &MR) {
437*da58b97aSjoerg std::lock_guard<std::mutex> Lock(PendingObjsLock);
438*da58b97aSjoerg auto It = PendingObjs.find(&MR);
439*da58b97aSjoerg if (It == PendingObjs.end())
440*da58b97aSjoerg return Error::success();
441*da58b97aSjoerg
442*da58b97aSjoerg // During finalization the debug object is registered with the target.
443*da58b97aSjoerg // Materialization must wait for this process to finish. Otherwise we might
444*da58b97aSjoerg // start running code before the debugger processed the corresponding debug
445*da58b97aSjoerg // info.
446*da58b97aSjoerg std::promise<MSVCPError> FinalizePromise;
447*da58b97aSjoerg std::future<MSVCPError> FinalizeErr = FinalizePromise.get_future();
448*da58b97aSjoerg
449*da58b97aSjoerg It->second->finalizeAsync(
450*da58b97aSjoerg [this, &FinalizePromise, &MR](Expected<sys::MemoryBlock> TargetMem) {
451*da58b97aSjoerg // Any failure here will fail materialization.
452*da58b97aSjoerg if (!TargetMem) {
453*da58b97aSjoerg FinalizePromise.set_value(TargetMem.takeError());
454*da58b97aSjoerg return;
455*da58b97aSjoerg }
456*da58b97aSjoerg if (Error Err = Target->registerDebugObject(*TargetMem)) {
457*da58b97aSjoerg FinalizePromise.set_value(std::move(Err));
458*da58b97aSjoerg return;
459*da58b97aSjoerg }
460*da58b97aSjoerg
461*da58b97aSjoerg // Once our tracking info is updated, notifyEmitted() can return and
462*da58b97aSjoerg // finish materialization.
463*da58b97aSjoerg FinalizePromise.set_value(MR.withResourceKeyDo([&](ResourceKey K) {
464*da58b97aSjoerg assert(PendingObjs.count(&MR) && "We still hold PendingObjsLock");
465*da58b97aSjoerg std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
466*da58b97aSjoerg RegisteredObjs[K].push_back(std::move(PendingObjs[&MR]));
467*da58b97aSjoerg PendingObjs.erase(&MR);
468*da58b97aSjoerg }));
469*da58b97aSjoerg });
470*da58b97aSjoerg
471*da58b97aSjoerg return FinalizeErr.get();
472*da58b97aSjoerg }
473*da58b97aSjoerg
notifyFailed(MaterializationResponsibility & MR)474*da58b97aSjoerg Error DebugObjectManagerPlugin::notifyFailed(
475*da58b97aSjoerg MaterializationResponsibility &MR) {
476*da58b97aSjoerg std::lock_guard<std::mutex> Lock(PendingObjsLock);
477*da58b97aSjoerg PendingObjs.erase(&MR);
478*da58b97aSjoerg return Error::success();
479*da58b97aSjoerg }
480*da58b97aSjoerg
notifyTransferringResources(ResourceKey DstKey,ResourceKey SrcKey)481*da58b97aSjoerg void DebugObjectManagerPlugin::notifyTransferringResources(ResourceKey DstKey,
482*da58b97aSjoerg ResourceKey SrcKey) {
483*da58b97aSjoerg // Debug objects are stored by ResourceKey only after registration.
484*da58b97aSjoerg // Thus, pending objects don't need to be updated here.
485*da58b97aSjoerg std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
486*da58b97aSjoerg auto SrcIt = RegisteredObjs.find(SrcKey);
487*da58b97aSjoerg if (SrcIt != RegisteredObjs.end()) {
488*da58b97aSjoerg // Resources from distinct MaterializationResponsibilitys can get merged
489*da58b97aSjoerg // after emission, so we can have multiple debug objects per resource key.
490*da58b97aSjoerg for (std::unique_ptr<DebugObject> &DebugObj : SrcIt->second)
491*da58b97aSjoerg RegisteredObjs[DstKey].push_back(std::move(DebugObj));
492*da58b97aSjoerg RegisteredObjs.erase(SrcIt);
493*da58b97aSjoerg }
494*da58b97aSjoerg }
495*da58b97aSjoerg
notifyRemovingResources(ResourceKey Key)496*da58b97aSjoerg Error DebugObjectManagerPlugin::notifyRemovingResources(ResourceKey Key) {
497*da58b97aSjoerg // Removing the resource for a pending object fails materialization, so they
498*da58b97aSjoerg // get cleaned up in the notifyFailed() handler.
499*da58b97aSjoerg std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
500*da58b97aSjoerg RegisteredObjs.erase(Key);
501*da58b97aSjoerg
502*da58b97aSjoerg // TODO: Implement unregister notifications.
503*da58b97aSjoerg return Error::success();
504*da58b97aSjoerg }
505*da58b97aSjoerg
506*da58b97aSjoerg } // namespace orc
507*da58b97aSjoerg } // namespace llvm
508