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 
159*7d18cd93SStefan Gränitz   StringRef getBuffer() const { return Buffer->getMemBufferRef().getBuffer(); }
160*7d18cd93SStefan Gränitz 
161ef238923SStefan Gränitz protected:
162ef238923SStefan Gränitz   Expected<std::unique_ptr<Allocation>>
163ef238923SStefan Gränitz   finalizeWorkingMemory(JITLinkContext &Ctx) override;
164ef238923SStefan Gränitz 
165ef238923SStefan Gränitz   Error recordSection(StringRef Name,
166ef238923SStefan Gränitz                       std::unique_ptr<DebugObjectSection> Section);
167ef238923SStefan Gränitz   DebugObjectSection *getSection(StringRef Name);
168ef238923SStefan Gränitz 
169ef238923SStefan Gränitz private:
170ef238923SStefan Gränitz   template <typename ELFT>
171ef238923SStefan Gränitz   static Expected<std::unique_ptr<ELFDebugObject>>
172ef238923SStefan Gränitz   CreateArchType(MemoryBufferRef Buffer, JITLinkContext &Ctx);
173ef238923SStefan Gränitz 
174*7d18cd93SStefan Gränitz   static std::unique_ptr<WritableMemoryBuffer>
175*7d18cd93SStefan Gränitz   CopyBuffer(MemoryBufferRef Buffer, Error &Err);
176ef238923SStefan Gränitz 
177ef238923SStefan Gränitz   ELFDebugObject(std::unique_ptr<WritableMemoryBuffer> Buffer,
178ef238923SStefan Gränitz                  JITLinkContext &Ctx)
179ef238923SStefan Gränitz       : DebugObject(Ctx), Buffer(std::move(Buffer)) {
180ef238923SStefan Gränitz     set(Requirement::ReportFinalSectionLoadAddresses);
181ef238923SStefan Gränitz   }
182ef238923SStefan Gränitz 
183ef238923SStefan Gränitz   std::unique_ptr<WritableMemoryBuffer> Buffer;
184ef238923SStefan Gränitz   StringMap<std::unique_ptr<DebugObjectSection>> Sections;
185ef238923SStefan Gränitz };
186ef238923SStefan Gränitz 
187ef238923SStefan Gränitz static const std::set<StringRef> DwarfSectionNames = {
188ef238923SStefan Gränitz #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION)        \
189ef238923SStefan Gränitz   ELF_NAME,
190ef238923SStefan Gränitz #include "llvm/BinaryFormat/Dwarf.def"
191ef238923SStefan Gränitz #undef HANDLE_DWARF_SECTION
192ef238923SStefan Gränitz };
193ef238923SStefan Gränitz 
194ef238923SStefan Gränitz static bool isDwarfSection(StringRef SectionName) {
195ef238923SStefan Gränitz   return DwarfSectionNames.count(SectionName) == 1;
196ef238923SStefan Gränitz }
197ef238923SStefan Gränitz 
198*7d18cd93SStefan Gränitz std::unique_ptr<WritableMemoryBuffer>
199*7d18cd93SStefan Gränitz ELFDebugObject::CopyBuffer(MemoryBufferRef Buffer, Error &Err) {
200*7d18cd93SStefan Gränitz   ErrorAsOutParameter _(&Err);
201ef238923SStefan Gränitz   size_t Size = Buffer.getBufferSize();
202ef238923SStefan Gränitz   StringRef Name = Buffer.getBufferIdentifier();
203*7d18cd93SStefan Gränitz   if (auto Copy = WritableMemoryBuffer::getNewUninitMemBuffer(Size, Name)) {
204ef238923SStefan Gränitz     memcpy(Copy->getBufferStart(), Buffer.getBufferStart(), Size);
205*7d18cd93SStefan Gränitz     return Copy;
206*7d18cd93SStefan Gränitz   }
207*7d18cd93SStefan Gränitz 
208*7d18cd93SStefan Gränitz   Err = errorCodeToError(make_error_code(errc::not_enough_memory));
209*7d18cd93SStefan Gränitz   return nullptr;
210ef238923SStefan Gränitz }
211ef238923SStefan Gränitz 
212ef238923SStefan Gränitz template <typename ELFT>
213ef238923SStefan Gränitz Expected<std::unique_ptr<ELFDebugObject>>
214ef238923SStefan Gränitz ELFDebugObject::CreateArchType(MemoryBufferRef Buffer, JITLinkContext &Ctx) {
215ef238923SStefan Gränitz   using SectionHeader = typename ELFT::Shdr;
216ef238923SStefan Gränitz 
217*7d18cd93SStefan Gränitz   Error Err = Error::success();
218*7d18cd93SStefan Gränitz   std::unique_ptr<ELFDebugObject> DebugObj(
219*7d18cd93SStefan Gränitz       new ELFDebugObject(CopyBuffer(Buffer, Err), Ctx));
220*7d18cd93SStefan Gränitz   if (Err)
221*7d18cd93SStefan Gränitz     return std::move(Err);
222*7d18cd93SStefan Gränitz 
223*7d18cd93SStefan Gränitz   Expected<ELFFile<ELFT>> ObjRef = ELFFile<ELFT>::create(DebugObj->getBuffer());
224ef238923SStefan Gränitz   if (!ObjRef)
225ef238923SStefan Gränitz     return ObjRef.takeError();
226ef238923SStefan Gränitz 
227ef238923SStefan Gränitz   // TODO: Add support for other architectures.
228ef238923SStefan Gränitz   uint16_t TargetMachineArch = ObjRef->getHeader().e_machine;
229ef238923SStefan Gränitz   if (TargetMachineArch != ELF::EM_X86_64)
230ef238923SStefan Gränitz     return nullptr;
231ef238923SStefan Gränitz 
232ef238923SStefan Gränitz   Expected<ArrayRef<SectionHeader>> Sections = ObjRef->sections();
233ef238923SStefan Gränitz   if (!Sections)
234ef238923SStefan Gränitz     return Sections.takeError();
235ef238923SStefan Gränitz 
236ef238923SStefan Gränitz   bool HasDwarfSection = false;
237ef238923SStefan Gränitz   for (const SectionHeader &Header : *Sections) {
238ef238923SStefan Gränitz     Expected<StringRef> Name = ObjRef->getSectionName(Header);
239ef238923SStefan Gränitz     if (!Name)
240ef238923SStefan Gränitz       return Name.takeError();
241ef238923SStefan Gränitz     if (Name->empty())
242ef238923SStefan Gränitz       continue;
243ef238923SStefan Gränitz     HasDwarfSection |= isDwarfSection(*Name);
244ef238923SStefan Gränitz 
245ef238923SStefan Gränitz     auto Wrapped = std::make_unique<ELFDebugObjectSection<ELFT>>(&Header);
246ef238923SStefan Gränitz     if (Error Err = DebugObj->recordSection(*Name, std::move(Wrapped)))
247ef238923SStefan Gränitz       return std::move(Err);
248ef238923SStefan Gränitz   }
249ef238923SStefan Gränitz 
250ef238923SStefan Gränitz   if (!HasDwarfSection) {
251ef238923SStefan Gränitz     LLVM_DEBUG(dbgs() << "Aborting debug registration for LinkGraph \""
252ef238923SStefan Gränitz                       << DebugObj->Buffer->getBufferIdentifier()
253ef238923SStefan Gränitz                       << "\": input object contains no debug info\n");
254ef238923SStefan Gränitz     return nullptr;
255ef238923SStefan Gränitz   }
256ef238923SStefan Gränitz 
257ef238923SStefan Gränitz   return std::move(DebugObj);
258ef238923SStefan Gränitz }
259ef238923SStefan Gränitz 
260ef238923SStefan Gränitz Expected<std::unique_ptr<DebugObject>>
261ef238923SStefan Gränitz ELFDebugObject::Create(MemoryBufferRef Buffer, JITLinkContext &Ctx) {
262ef238923SStefan Gränitz   unsigned char Class, Endian;
263ef238923SStefan Gränitz   std::tie(Class, Endian) = getElfArchType(Buffer.getBuffer());
264ef238923SStefan Gränitz 
265ef238923SStefan Gränitz   if (Class == ELF::ELFCLASS32) {
266ef238923SStefan Gränitz     if (Endian == ELF::ELFDATA2LSB)
267ef238923SStefan Gränitz       return CreateArchType<ELF32LE>(Buffer, Ctx);
268ef238923SStefan Gränitz     if (Endian == ELF::ELFDATA2MSB)
269ef238923SStefan Gränitz       return CreateArchType<ELF32BE>(Buffer, Ctx);
270ef238923SStefan Gränitz     return nullptr;
271ef238923SStefan Gränitz   }
272ef238923SStefan Gränitz   if (Class == ELF::ELFCLASS64) {
273ef238923SStefan Gränitz     if (Endian == ELF::ELFDATA2LSB)
274ef238923SStefan Gränitz       return CreateArchType<ELF64LE>(Buffer, Ctx);
275ef238923SStefan Gränitz     if (Endian == ELF::ELFDATA2MSB)
276ef238923SStefan Gränitz       return CreateArchType<ELF64BE>(Buffer, Ctx);
277ef238923SStefan Gränitz     return nullptr;
278ef238923SStefan Gränitz   }
279ef238923SStefan Gränitz   return nullptr;
280ef238923SStefan Gränitz }
281ef238923SStefan Gränitz 
282ef238923SStefan Gränitz Expected<std::unique_ptr<DebugObject::Allocation>>
283ef238923SStefan Gränitz ELFDebugObject::finalizeWorkingMemory(JITLinkContext &Ctx) {
284ef238923SStefan Gränitz   LLVM_DEBUG({
285ef238923SStefan Gränitz     dbgs() << "Section load-addresses in debug object for \""
286ef238923SStefan Gränitz            << Buffer->getBufferIdentifier() << "\":\n";
287ef238923SStefan Gränitz     for (const auto &KV : Sections)
288ef238923SStefan Gränitz       KV.second->dump(dbgs(), KV.first());
289ef238923SStefan Gränitz   });
290ef238923SStefan Gränitz 
291ef238923SStefan Gränitz   // TODO: This works, but what actual alignment requirements do we have?
292ef238923SStefan Gränitz   unsigned Alignment = sys::Process::getPageSizeEstimate();
293ef238923SStefan Gränitz   JITLinkMemoryManager &MemMgr = Ctx.getMemoryManager();
294ef238923SStefan Gränitz   const JITLinkDylib *JD = Ctx.getJITLinkDylib();
295ef238923SStefan Gränitz   size_t Size = Buffer->getBufferSize();
296ef238923SStefan Gränitz 
297ef238923SStefan Gränitz   // Allocate working memory for debug object in read-only segment.
298a747e35cSStefan Gränitz   JITLinkMemoryManager::SegmentsRequestMap SingleReadOnlySegment;
299a747e35cSStefan Gränitz   SingleReadOnlySegment[ReadOnly] =
300a747e35cSStefan Gränitz       JITLinkMemoryManager::SegmentRequest(Alignment, Size, 0);
301a747e35cSStefan Gränitz 
302a747e35cSStefan Gränitz   auto AllocOrErr = MemMgr.allocate(JD, SingleReadOnlySegment);
303ef238923SStefan Gränitz   if (!AllocOrErr)
304ef238923SStefan Gränitz     return AllocOrErr.takeError();
305ef238923SStefan Gränitz 
306ef238923SStefan Gränitz   // Initialize working memory with a copy of our object buffer.
307ef238923SStefan Gränitz   // TODO: Use our buffer as working memory directly.
308ef238923SStefan Gränitz   std::unique_ptr<Allocation> Alloc = std::move(*AllocOrErr);
309ef238923SStefan Gränitz   MutableArrayRef<char> WorkingMem = Alloc->getWorkingMemory(ReadOnly);
310ef238923SStefan Gränitz   memcpy(WorkingMem.data(), Buffer->getBufferStart(), Size);
311ef238923SStefan Gränitz   Buffer.reset();
312ef238923SStefan Gränitz 
313ef238923SStefan Gränitz   return std::move(Alloc);
314ef238923SStefan Gränitz }
315ef238923SStefan Gränitz 
316ef238923SStefan Gränitz void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name,
317ef238923SStefan Gränitz                                                     SectionRange TargetMem) {
318ef238923SStefan Gränitz   if (auto *DebugObjSection = getSection(Name))
319ef238923SStefan Gränitz     DebugObjSection->setTargetMemoryRange(TargetMem);
320ef238923SStefan Gränitz }
321ef238923SStefan Gränitz 
322ef238923SStefan Gränitz Error ELFDebugObject::recordSection(
323ef238923SStefan Gränitz     StringRef Name, std::unique_ptr<DebugObjectSection> Section) {
324ef238923SStefan Gränitz   auto ItInserted = Sections.try_emplace(Name, std::move(Section));
325ef238923SStefan Gränitz   if (!ItInserted.second)
326ef238923SStefan Gränitz     return make_error<StringError>("Duplicate section",
327ef238923SStefan Gränitz                                    inconvertibleErrorCode());
328ef238923SStefan Gränitz   return Error::success();
329ef238923SStefan Gränitz }
330ef238923SStefan Gränitz 
331ef238923SStefan Gränitz DebugObjectSection *ELFDebugObject::getSection(StringRef Name) {
332ef238923SStefan Gränitz   auto It = Sections.find(Name);
333ef238923SStefan Gränitz   return It == Sections.end() ? nullptr : It->second.get();
334ef238923SStefan Gränitz }
335ef238923SStefan Gränitz 
336ef238923SStefan Gränitz static ResourceKey getResourceKey(MaterializationResponsibility &MR) {
337ef238923SStefan Gränitz   ResourceKey Key;
338ef238923SStefan Gränitz   if (auto Err = MR.withResourceKeyDo([&](ResourceKey K) { Key = K; })) {
339ef238923SStefan Gränitz     MR.getExecutionSession().reportError(std::move(Err));
340ef238923SStefan Gränitz     return ResourceKey{};
341ef238923SStefan Gränitz   }
342ef238923SStefan Gränitz   assert(Key && "Invalid key");
343ef238923SStefan Gränitz   return Key;
344ef238923SStefan Gränitz }
345ef238923SStefan Gränitz 
346ef238923SStefan Gränitz /// Creates a debug object based on the input object file from
347ef238923SStefan Gränitz /// ObjectLinkingLayerJITLinkContext.
348ef238923SStefan Gränitz ///
349ef238923SStefan Gränitz static Expected<std::unique_ptr<DebugObject>>
350ef238923SStefan Gränitz createDebugObjectFromBuffer(LinkGraph &G, JITLinkContext &Ctx,
351ef238923SStefan Gränitz                             MemoryBufferRef ObjBuffer) {
352ef238923SStefan Gränitz   switch (G.getTargetTriple().getObjectFormat()) {
353ef238923SStefan Gränitz   case Triple::ELF:
354ef238923SStefan Gränitz     return ELFDebugObject::Create(ObjBuffer, Ctx);
355ef238923SStefan Gränitz 
356ef238923SStefan Gränitz   default:
357ef238923SStefan Gränitz     // TODO: Once we add support for other formats, we might want to split this
358ef238923SStefan Gränitz     // into multiple files.
359ef238923SStefan Gränitz     return nullptr;
360ef238923SStefan Gränitz   }
361ef238923SStefan Gränitz }
362ef238923SStefan Gränitz 
363ef238923SStefan Gränitz DebugObjectManagerPlugin::DebugObjectManagerPlugin(
364ef238923SStefan Gränitz     ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target)
365ef238923SStefan Gränitz     : ES(ES), Target(std::move(Target)) {}
366ef238923SStefan Gränitz 
367ef238923SStefan Gränitz DebugObjectManagerPlugin::~DebugObjectManagerPlugin() {}
368ef238923SStefan Gränitz 
369ef238923SStefan Gränitz void DebugObjectManagerPlugin::notifyMaterializing(
370ef238923SStefan Gränitz     MaterializationResponsibility &MR, LinkGraph &G, JITLinkContext &Ctx,
371ef238923SStefan Gränitz     MemoryBufferRef ObjBuffer) {
372ef238923SStefan Gränitz   assert(PendingObjs.count(getResourceKey(MR)) == 0 &&
373ef238923SStefan Gränitz          "Cannot have more than one pending debug object per "
374ef238923SStefan Gränitz          "MaterializationResponsibility");
375ef238923SStefan Gränitz 
376ef238923SStefan Gränitz   std::lock_guard<std::mutex> Lock(PendingObjsLock);
377ef238923SStefan Gränitz   if (auto DebugObj = createDebugObjectFromBuffer(G, Ctx, ObjBuffer)) {
378ef238923SStefan Gränitz     // Not all link artifacts allow debugging.
379ef238923SStefan Gränitz     if (*DebugObj != nullptr) {
380ef238923SStefan Gränitz       ResourceKey Key = getResourceKey(MR);
381ef238923SStefan Gränitz       PendingObjs[Key] = std::move(*DebugObj);
382ef238923SStefan Gränitz     }
383ef238923SStefan Gränitz   } else {
384ef238923SStefan Gränitz     ES.reportError(DebugObj.takeError());
385ef238923SStefan Gränitz   }
386ef238923SStefan Gränitz }
387ef238923SStefan Gränitz 
388ef238923SStefan Gränitz void DebugObjectManagerPlugin::modifyPassConfig(
389ef238923SStefan Gränitz     MaterializationResponsibility &MR, const Triple &TT,
390ef238923SStefan Gränitz     PassConfiguration &PassConfig) {
391ef238923SStefan Gränitz   // Not all link artifacts have associated debug objects.
392ef238923SStefan Gränitz   std::lock_guard<std::mutex> Lock(PendingObjsLock);
393ef238923SStefan Gränitz   auto It = PendingObjs.find(getResourceKey(MR));
394ef238923SStefan Gränitz   if (It == PendingObjs.end())
395ef238923SStefan Gränitz     return;
396ef238923SStefan Gränitz 
397ef238923SStefan Gränitz   DebugObject &DebugObj = *It->second;
398ef238923SStefan Gränitz   if (DebugObj.has(Requirement::ReportFinalSectionLoadAddresses)) {
399ef238923SStefan Gränitz     PassConfig.PostAllocationPasses.push_back(
400ef238923SStefan Gränitz         [&DebugObj](LinkGraph &Graph) -> Error {
401ef238923SStefan Gränitz           for (const Section &GraphSection : Graph.sections())
402ef238923SStefan Gränitz             DebugObj.reportSectionTargetMemoryRange(GraphSection.getName(),
403ef238923SStefan Gränitz                                                     SectionRange(GraphSection));
404ef238923SStefan Gränitz           return Error::success();
405ef238923SStefan Gränitz         });
406ef238923SStefan Gränitz   }
407ef238923SStefan Gränitz }
408ef238923SStefan Gränitz 
409ef238923SStefan Gränitz Error DebugObjectManagerPlugin::notifyEmitted(
410ef238923SStefan Gränitz     MaterializationResponsibility &MR) {
411ef238923SStefan Gränitz   ResourceKey Key = getResourceKey(MR);
412ef238923SStefan Gränitz 
413ef238923SStefan Gränitz   std::lock_guard<std::mutex> Lock(PendingObjsLock);
414ef238923SStefan Gränitz   auto It = PendingObjs.find(Key);
415ef238923SStefan Gränitz   if (It == PendingObjs.end())
416ef238923SStefan Gränitz     return Error::success();
417ef238923SStefan Gränitz 
418ef238923SStefan Gränitz   DebugObject *UnownedDebugObj = It->second.release();
419ef238923SStefan Gränitz   PendingObjs.erase(It);
420ef238923SStefan Gränitz 
421ef238923SStefan Gränitz   // FIXME: We released ownership of the DebugObject, so we can easily capture
422ef238923SStefan Gränitz   // the raw pointer in the continuation function, which re-owns it immediately.
423ef238923SStefan Gränitz   if (UnownedDebugObj)
424ef238923SStefan Gränitz     UnownedDebugObj->finalizeAsync(
425ef238923SStefan Gränitz         [this, Key, UnownedDebugObj](Expected<sys::MemoryBlock> TargetMem) {
426ef238923SStefan Gränitz           std::unique_ptr<DebugObject> ReownedDebugObj(UnownedDebugObj);
427ef238923SStefan Gränitz           if (!TargetMem) {
428ef238923SStefan Gränitz             ES.reportError(TargetMem.takeError());
429ef238923SStefan Gränitz             return;
430ef238923SStefan Gränitz           }
431ef238923SStefan Gränitz           if (Error Err = Target->registerDebugObject(*TargetMem)) {
432ef238923SStefan Gränitz             ES.reportError(std::move(Err));
433ef238923SStefan Gränitz             return;
434ef238923SStefan Gränitz           }
435ef238923SStefan Gränitz 
436ef238923SStefan Gränitz           std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
437ef238923SStefan Gränitz           RegisteredObjs[Key].push_back(std::move(ReownedDebugObj));
438ef238923SStefan Gränitz         });
439ef238923SStefan Gränitz 
440ef238923SStefan Gränitz   return Error::success();
441ef238923SStefan Gränitz }
442ef238923SStefan Gränitz 
443ef238923SStefan Gränitz Error DebugObjectManagerPlugin::notifyFailed(
444ef238923SStefan Gränitz     MaterializationResponsibility &MR) {
445ef238923SStefan Gränitz   std::lock_guard<std::mutex> Lock(PendingObjsLock);
446ef238923SStefan Gränitz   PendingObjs.erase(getResourceKey(MR));
447ef238923SStefan Gränitz   return Error::success();
448ef238923SStefan Gränitz }
449ef238923SStefan Gränitz 
450ef238923SStefan Gränitz void DebugObjectManagerPlugin::notifyTransferringResources(ResourceKey DstKey,
451ef238923SStefan Gränitz                                                            ResourceKey SrcKey) {
452ef238923SStefan Gränitz   {
453ef238923SStefan Gränitz     std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
454ef238923SStefan Gränitz     auto SrcIt = RegisteredObjs.find(SrcKey);
455ef238923SStefan Gränitz     if (SrcIt != RegisteredObjs.end()) {
456ef238923SStefan Gränitz       // Resources from distinct MaterializationResponsibilitys can get merged
457ef238923SStefan Gränitz       // after emission, so we can have multiple debug objects per resource key.
458ef238923SStefan Gränitz       for (std::unique_ptr<DebugObject> &DebugObj : SrcIt->second)
459ef238923SStefan Gränitz         RegisteredObjs[DstKey].push_back(std::move(DebugObj));
460ef238923SStefan Gränitz       RegisteredObjs.erase(SrcIt);
461ef238923SStefan Gränitz     }
462ef238923SStefan Gränitz   }
463ef238923SStefan Gränitz   {
464ef238923SStefan Gränitz     std::lock_guard<std::mutex> Lock(PendingObjsLock);
465ef238923SStefan Gränitz     auto SrcIt = PendingObjs.find(SrcKey);
466ef238923SStefan Gränitz     if (SrcIt != PendingObjs.end()) {
467ef238923SStefan Gränitz       assert(PendingObjs.count(DstKey) == 0 &&
468ef238923SStefan Gränitz              "Cannot have more than one pending debug object per "
469ef238923SStefan Gränitz              "MaterializationResponsibility");
470ef238923SStefan Gränitz       PendingObjs[DstKey] = std::move(SrcIt->second);
471ef238923SStefan Gränitz       PendingObjs.erase(SrcIt);
472ef238923SStefan Gränitz     }
473ef238923SStefan Gränitz   }
474ef238923SStefan Gränitz }
475ef238923SStefan Gränitz 
476ef238923SStefan Gränitz Error DebugObjectManagerPlugin::notifyRemovingResources(ResourceKey K) {
477ef238923SStefan Gränitz   {
478ef238923SStefan Gränitz     std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
479ef238923SStefan Gränitz     RegisteredObjs.erase(K);
480ef238923SStefan Gränitz     // TODO: Implement unregister notifications.
481ef238923SStefan Gränitz   }
482ef238923SStefan Gränitz   std::lock_guard<std::mutex> Lock(PendingObjsLock);
483ef238923SStefan Gränitz   PendingObjs.erase(K);
484ef238923SStefan Gränitz 
485ef238923SStefan Gränitz   return Error::success();
486ef238923SStefan Gränitz }
487ef238923SStefan Gränitz 
488ef238923SStefan Gränitz } // namespace orc
489ef238923SStefan Gränitz } // namespace llvm
490