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