xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1349cc55cSDimitry Andric //===------- DebugObjectManagerPlugin.cpp - JITLink debug objects ---------===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8349cc55cSDimitry Andric //
9349cc55cSDimitry Andric // FIXME: Update Plugin to poke the debug object into a new JITLink section,
10349cc55cSDimitry Andric //        rather than creating a new allocation.
11349cc55cSDimitry Andric //
12349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
13fe6060f1SDimitry Andric 
14fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
15fe6060f1SDimitry Andric 
16fe6060f1SDimitry Andric #include "llvm/ADT/ArrayRef.h"
17fe6060f1SDimitry Andric #include "llvm/ADT/StringMap.h"
18fe6060f1SDimitry Andric #include "llvm/ADT/StringRef.h"
19fe6060f1SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
20fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLinkDylib.h"
21fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
22fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/JITSymbol.h"
23fe6060f1SDimitry Andric #include "llvm/Object/ELFObjectFile.h"
24fe6060f1SDimitry Andric #include "llvm/Object/ObjectFile.h"
25fe6060f1SDimitry Andric #include "llvm/Support/Errc.h"
26fe6060f1SDimitry Andric #include "llvm/Support/MSVCErrorWorkarounds.h"
27fe6060f1SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
28fe6060f1SDimitry Andric #include "llvm/Support/Process.h"
29fe6060f1SDimitry Andric #include "llvm/Support/raw_ostream.h"
30fe6060f1SDimitry Andric 
31fe6060f1SDimitry Andric #include <set>
32fe6060f1SDimitry Andric 
33fe6060f1SDimitry Andric #define DEBUG_TYPE "orc"
34fe6060f1SDimitry Andric 
35fe6060f1SDimitry Andric using namespace llvm::jitlink;
36fe6060f1SDimitry Andric using namespace llvm::object;
37fe6060f1SDimitry Andric 
38fe6060f1SDimitry Andric namespace llvm {
39fe6060f1SDimitry Andric namespace orc {
40fe6060f1SDimitry Andric 
41fe6060f1SDimitry Andric class DebugObjectSection {
42fe6060f1SDimitry Andric public:
43fe6060f1SDimitry Andric   virtual void setTargetMemoryRange(SectionRange Range) = 0;
44fe6060f1SDimitry Andric   virtual void dump(raw_ostream &OS, StringRef Name) {}
4581ad6265SDimitry Andric   virtual ~DebugObjectSection() = default;
46fe6060f1SDimitry Andric };
47fe6060f1SDimitry Andric 
48fe6060f1SDimitry Andric template <typename ELFT>
49fe6060f1SDimitry Andric class ELFDebugObjectSection : public DebugObjectSection {
50fe6060f1SDimitry Andric public:
51fe6060f1SDimitry Andric   // BinaryFormat ELF is not meant as a mutable format. We can only make changes
52fe6060f1SDimitry Andric   // that don't invalidate the file structure.
53fe6060f1SDimitry Andric   ELFDebugObjectSection(const typename ELFT::Shdr *Header)
54fe6060f1SDimitry Andric       : Header(const_cast<typename ELFT::Shdr *>(Header)) {}
55fe6060f1SDimitry Andric 
56fe6060f1SDimitry Andric   void setTargetMemoryRange(SectionRange Range) override;
57fe6060f1SDimitry Andric   void dump(raw_ostream &OS, StringRef Name) override;
58fe6060f1SDimitry Andric 
59fe6060f1SDimitry Andric   Error validateInBounds(StringRef Buffer, const char *Name) const;
60fe6060f1SDimitry Andric 
61fe6060f1SDimitry Andric private:
62fe6060f1SDimitry Andric   typename ELFT::Shdr *Header;
63fe6060f1SDimitry Andric 
64fe6060f1SDimitry Andric   bool isTextOrDataSection() const;
65fe6060f1SDimitry Andric };
66fe6060f1SDimitry Andric 
67fe6060f1SDimitry Andric template <typename ELFT>
68fe6060f1SDimitry Andric void ELFDebugObjectSection<ELFT>::setTargetMemoryRange(SectionRange Range) {
69fe6060f1SDimitry Andric   // Only patch load-addresses for executable and data sections.
7004eeddc0SDimitry Andric   if (isTextOrDataSection())
7104eeddc0SDimitry Andric     Header->sh_addr =
7204eeddc0SDimitry Andric         static_cast<typename ELFT::uint>(Range.getStart().getValue());
73fe6060f1SDimitry Andric }
74fe6060f1SDimitry Andric 
75fe6060f1SDimitry Andric template <typename ELFT>
76fe6060f1SDimitry Andric bool ELFDebugObjectSection<ELFT>::isTextOrDataSection() const {
77fe6060f1SDimitry Andric   switch (Header->sh_type) {
78fe6060f1SDimitry Andric   case ELF::SHT_PROGBITS:
79fe6060f1SDimitry Andric   case ELF::SHT_X86_64_UNWIND:
80fe6060f1SDimitry Andric     return Header->sh_flags & (ELF::SHF_EXECINSTR | ELF::SHF_ALLOC);
81fe6060f1SDimitry Andric   }
82fe6060f1SDimitry Andric   return false;
83fe6060f1SDimitry Andric }
84fe6060f1SDimitry Andric 
85fe6060f1SDimitry Andric template <typename ELFT>
86fe6060f1SDimitry Andric Error ELFDebugObjectSection<ELFT>::validateInBounds(StringRef Buffer,
87fe6060f1SDimitry Andric                                                     const char *Name) const {
88fe6060f1SDimitry Andric   const uint8_t *Start = Buffer.bytes_begin();
89fe6060f1SDimitry Andric   const uint8_t *End = Buffer.bytes_end();
90fe6060f1SDimitry Andric   const uint8_t *HeaderPtr = reinterpret_cast<uint8_t *>(Header);
91fe6060f1SDimitry Andric   if (HeaderPtr < Start || HeaderPtr + sizeof(typename ELFT::Shdr) > End)
92fe6060f1SDimitry Andric     return make_error<StringError>(
93fe6060f1SDimitry Andric         formatv("{0} section header at {1:x16} not within bounds of the "
94fe6060f1SDimitry Andric                 "given debug object buffer [{2:x16} - {3:x16}]",
95fe6060f1SDimitry Andric                 Name, &Header->sh_addr, Start, End),
96fe6060f1SDimitry Andric         inconvertibleErrorCode());
97fe6060f1SDimitry Andric   if (Header->sh_offset + Header->sh_size > Buffer.size())
98fe6060f1SDimitry Andric     return make_error<StringError>(
99fe6060f1SDimitry Andric         formatv("{0} section data [{1:x16} - {2:x16}] not within bounds of "
100fe6060f1SDimitry Andric                 "the given debug object buffer [{3:x16} - {4:x16}]",
101fe6060f1SDimitry Andric                 Name, Start + Header->sh_offset,
102fe6060f1SDimitry Andric                 Start + Header->sh_offset + Header->sh_size, Start, End),
103fe6060f1SDimitry Andric         inconvertibleErrorCode());
104fe6060f1SDimitry Andric   return Error::success();
105fe6060f1SDimitry Andric }
106fe6060f1SDimitry Andric 
107fe6060f1SDimitry Andric template <typename ELFT>
108fe6060f1SDimitry Andric void ELFDebugObjectSection<ELFT>::dump(raw_ostream &OS, StringRef Name) {
109fe6060f1SDimitry Andric   if (auto Addr = static_cast<JITTargetAddress>(Header->sh_addr)) {
110fe6060f1SDimitry Andric     OS << formatv("  {0:x16} {1}\n", Addr, Name);
111fe6060f1SDimitry Andric   } else {
112fe6060f1SDimitry Andric     OS << formatv("                     {0}\n", Name);
113fe6060f1SDimitry Andric   }
114fe6060f1SDimitry Andric }
115fe6060f1SDimitry Andric 
116fe6060f1SDimitry Andric enum class Requirement {
117fe6060f1SDimitry Andric   // Request final target memory load-addresses for all sections.
118fe6060f1SDimitry Andric   ReportFinalSectionLoadAddresses,
119fe6060f1SDimitry Andric };
120fe6060f1SDimitry Andric 
121349cc55cSDimitry Andric /// The plugin creates a debug object from when JITLink starts processing the
122349cc55cSDimitry Andric /// corresponding LinkGraph. It provides access to the pass configuration of
123349cc55cSDimitry Andric /// the LinkGraph and calls the finalization function, once the resulting link
124349cc55cSDimitry Andric /// artifact was emitted.
125fe6060f1SDimitry Andric ///
126fe6060f1SDimitry Andric class DebugObject {
127fe6060f1SDimitry Andric public:
128349cc55cSDimitry Andric   DebugObject(JITLinkMemoryManager &MemMgr, const JITLinkDylib *JD,
129349cc55cSDimitry Andric               ExecutionSession &ES)
130349cc55cSDimitry Andric       : MemMgr(MemMgr), JD(JD), ES(ES) {}
131fe6060f1SDimitry Andric 
132fe6060f1SDimitry Andric   void set(Requirement Req) { Reqs.insert(Req); }
133fe6060f1SDimitry Andric   bool has(Requirement Req) const { return Reqs.count(Req) > 0; }
134fe6060f1SDimitry Andric 
135349cc55cSDimitry Andric   using FinalizeContinuation = std::function<void(Expected<ExecutorAddrRange>)>;
136349cc55cSDimitry Andric 
137fe6060f1SDimitry Andric   void finalizeAsync(FinalizeContinuation OnFinalize);
138fe6060f1SDimitry Andric 
139fe6060f1SDimitry Andric   virtual ~DebugObject() {
140349cc55cSDimitry Andric     if (Alloc) {
141349cc55cSDimitry Andric       std::vector<FinalizedAlloc> Allocs;
142349cc55cSDimitry Andric       Allocs.push_back(std::move(Alloc));
143349cc55cSDimitry Andric       if (Error Err = MemMgr.deallocate(std::move(Allocs)))
144fe6060f1SDimitry Andric         ES.reportError(std::move(Err));
145fe6060f1SDimitry Andric     }
146349cc55cSDimitry Andric   }
147fe6060f1SDimitry Andric 
148fe6060f1SDimitry Andric   virtual void reportSectionTargetMemoryRange(StringRef Name,
149fe6060f1SDimitry Andric                                               SectionRange TargetMem) {}
150fe6060f1SDimitry Andric 
151fe6060f1SDimitry Andric protected:
152349cc55cSDimitry Andric   using InFlightAlloc = JITLinkMemoryManager::InFlightAlloc;
153349cc55cSDimitry Andric   using FinalizedAlloc = JITLinkMemoryManager::FinalizedAlloc;
154fe6060f1SDimitry Andric 
155349cc55cSDimitry Andric   virtual Expected<SimpleSegmentAlloc> finalizeWorkingMemory() = 0;
156349cc55cSDimitry Andric 
157349cc55cSDimitry Andric   JITLinkMemoryManager &MemMgr;
158349cc55cSDimitry Andric   const JITLinkDylib *JD = nullptr;
159fe6060f1SDimitry Andric 
160fe6060f1SDimitry Andric private:
161fe6060f1SDimitry Andric   ExecutionSession &ES;
162fe6060f1SDimitry Andric   std::set<Requirement> Reqs;
163349cc55cSDimitry Andric   FinalizedAlloc Alloc;
164fe6060f1SDimitry Andric };
165fe6060f1SDimitry Andric 
166fe6060f1SDimitry Andric // Finalize working memory and take ownership of the resulting allocation. Start
167fe6060f1SDimitry Andric // copying memory over to the target and pass on the result once we're done.
168fe6060f1SDimitry Andric // Ownership of the allocation remains with us for the rest of our lifetime.
169fe6060f1SDimitry Andric void DebugObject::finalizeAsync(FinalizeContinuation OnFinalize) {
170349cc55cSDimitry Andric   assert(!Alloc && "Cannot finalize more than once");
171fe6060f1SDimitry Andric 
172349cc55cSDimitry Andric   if (auto SimpleSegAlloc = finalizeWorkingMemory()) {
173349cc55cSDimitry Andric     auto ROSeg = SimpleSegAlloc->getSegInfo(MemProt::Read);
174349cc55cSDimitry Andric     ExecutorAddrRange DebugObjRange(ExecutorAddr(ROSeg.Addr),
175349cc55cSDimitry Andric                                     ExecutorAddrDiff(ROSeg.WorkingMem.size()));
176349cc55cSDimitry Andric     SimpleSegAlloc->finalize(
177349cc55cSDimitry Andric         [this, DebugObjRange,
178349cc55cSDimitry Andric          OnFinalize = std::move(OnFinalize)](Expected<FinalizedAlloc> FA) {
179349cc55cSDimitry Andric           if (FA) {
180349cc55cSDimitry Andric             Alloc = std::move(*FA);
181349cc55cSDimitry Andric             OnFinalize(DebugObjRange);
182349cc55cSDimitry Andric           } else
183349cc55cSDimitry Andric             OnFinalize(FA.takeError());
184fe6060f1SDimitry Andric         });
185349cc55cSDimitry Andric   } else
186349cc55cSDimitry Andric     OnFinalize(SimpleSegAlloc.takeError());
187fe6060f1SDimitry Andric }
188fe6060f1SDimitry Andric 
189fe6060f1SDimitry Andric /// The current implementation of ELFDebugObject replicates the approach used in
190fe6060f1SDimitry Andric /// RuntimeDyld: It patches executable and data section headers in the given
191fe6060f1SDimitry Andric /// object buffer with load-addresses of their corresponding sections in target
192fe6060f1SDimitry Andric /// memory.
193fe6060f1SDimitry Andric ///
194fe6060f1SDimitry Andric class ELFDebugObject : public DebugObject {
195fe6060f1SDimitry Andric public:
196fe6060f1SDimitry Andric   static Expected<std::unique_ptr<DebugObject>>
197fe6060f1SDimitry Andric   Create(MemoryBufferRef Buffer, JITLinkContext &Ctx, ExecutionSession &ES);
198fe6060f1SDimitry Andric 
199fe6060f1SDimitry Andric   void reportSectionTargetMemoryRange(StringRef Name,
200fe6060f1SDimitry Andric                                       SectionRange TargetMem) override;
201fe6060f1SDimitry Andric 
202fe6060f1SDimitry Andric   StringRef getBuffer() const { return Buffer->getMemBufferRef().getBuffer(); }
203fe6060f1SDimitry Andric 
204fe6060f1SDimitry Andric protected:
205349cc55cSDimitry Andric   Expected<SimpleSegmentAlloc> finalizeWorkingMemory() override;
206fe6060f1SDimitry Andric 
207fe6060f1SDimitry Andric   template <typename ELFT>
208fe6060f1SDimitry Andric   Error recordSection(StringRef Name,
209fe6060f1SDimitry Andric                       std::unique_ptr<ELFDebugObjectSection<ELFT>> Section);
210fe6060f1SDimitry Andric   DebugObjectSection *getSection(StringRef Name);
211fe6060f1SDimitry Andric 
212fe6060f1SDimitry Andric private:
213fe6060f1SDimitry Andric   template <typename ELFT>
214fe6060f1SDimitry Andric   static Expected<std::unique_ptr<ELFDebugObject>>
215349cc55cSDimitry Andric   CreateArchType(MemoryBufferRef Buffer, JITLinkMemoryManager &MemMgr,
216349cc55cSDimitry Andric                  const JITLinkDylib *JD, ExecutionSession &ES);
217fe6060f1SDimitry Andric 
218fe6060f1SDimitry Andric   static std::unique_ptr<WritableMemoryBuffer>
219fe6060f1SDimitry Andric   CopyBuffer(MemoryBufferRef Buffer, Error &Err);
220fe6060f1SDimitry Andric 
221fe6060f1SDimitry Andric   ELFDebugObject(std::unique_ptr<WritableMemoryBuffer> Buffer,
222349cc55cSDimitry Andric                  JITLinkMemoryManager &MemMgr, const JITLinkDylib *JD,
223349cc55cSDimitry Andric                  ExecutionSession &ES)
224349cc55cSDimitry Andric       : DebugObject(MemMgr, JD, ES), Buffer(std::move(Buffer)) {
225fe6060f1SDimitry Andric     set(Requirement::ReportFinalSectionLoadAddresses);
226fe6060f1SDimitry Andric   }
227fe6060f1SDimitry Andric 
228fe6060f1SDimitry Andric   std::unique_ptr<WritableMemoryBuffer> Buffer;
229fe6060f1SDimitry Andric   StringMap<std::unique_ptr<DebugObjectSection>> Sections;
230fe6060f1SDimitry Andric };
231fe6060f1SDimitry Andric 
232fe6060f1SDimitry Andric static const std::set<StringRef> DwarfSectionNames = {
233fe6060f1SDimitry Andric #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION)        \
234fe6060f1SDimitry Andric   ELF_NAME,
235fe6060f1SDimitry Andric #include "llvm/BinaryFormat/Dwarf.def"
236fe6060f1SDimitry Andric #undef HANDLE_DWARF_SECTION
237fe6060f1SDimitry Andric };
238fe6060f1SDimitry Andric 
239fe6060f1SDimitry Andric static bool isDwarfSection(StringRef SectionName) {
240fe6060f1SDimitry Andric   return DwarfSectionNames.count(SectionName) == 1;
241fe6060f1SDimitry Andric }
242fe6060f1SDimitry Andric 
243fe6060f1SDimitry Andric std::unique_ptr<WritableMemoryBuffer>
244fe6060f1SDimitry Andric ELFDebugObject::CopyBuffer(MemoryBufferRef Buffer, Error &Err) {
245fe6060f1SDimitry Andric   ErrorAsOutParameter _(&Err);
246fe6060f1SDimitry Andric   size_t Size = Buffer.getBufferSize();
247fe6060f1SDimitry Andric   StringRef Name = Buffer.getBufferIdentifier();
248fe6060f1SDimitry Andric   if (auto Copy = WritableMemoryBuffer::getNewUninitMemBuffer(Size, Name)) {
249fe6060f1SDimitry Andric     memcpy(Copy->getBufferStart(), Buffer.getBufferStart(), Size);
250fe6060f1SDimitry Andric     return Copy;
251fe6060f1SDimitry Andric   }
252fe6060f1SDimitry Andric 
253fe6060f1SDimitry Andric   Err = errorCodeToError(make_error_code(errc::not_enough_memory));
254fe6060f1SDimitry Andric   return nullptr;
255fe6060f1SDimitry Andric }
256fe6060f1SDimitry Andric 
257fe6060f1SDimitry Andric template <typename ELFT>
258fe6060f1SDimitry Andric Expected<std::unique_ptr<ELFDebugObject>>
259349cc55cSDimitry Andric ELFDebugObject::CreateArchType(MemoryBufferRef Buffer,
260349cc55cSDimitry Andric                                JITLinkMemoryManager &MemMgr,
261349cc55cSDimitry Andric                                const JITLinkDylib *JD, ExecutionSession &ES) {
262fe6060f1SDimitry Andric   using SectionHeader = typename ELFT::Shdr;
263fe6060f1SDimitry Andric 
264fe6060f1SDimitry Andric   Error Err = Error::success();
265fe6060f1SDimitry Andric   std::unique_ptr<ELFDebugObject> DebugObj(
266349cc55cSDimitry Andric       new ELFDebugObject(CopyBuffer(Buffer, Err), MemMgr, JD, ES));
267fe6060f1SDimitry Andric   if (Err)
268fe6060f1SDimitry Andric     return std::move(Err);
269fe6060f1SDimitry Andric 
270fe6060f1SDimitry Andric   Expected<ELFFile<ELFT>> ObjRef = ELFFile<ELFT>::create(DebugObj->getBuffer());
271fe6060f1SDimitry Andric   if (!ObjRef)
272fe6060f1SDimitry Andric     return ObjRef.takeError();
273fe6060f1SDimitry Andric 
274fe6060f1SDimitry Andric   // TODO: Add support for other architectures.
275fe6060f1SDimitry Andric   uint16_t TargetMachineArch = ObjRef->getHeader().e_machine;
276fe6060f1SDimitry Andric   if (TargetMachineArch != ELF::EM_X86_64)
277fe6060f1SDimitry Andric     return nullptr;
278fe6060f1SDimitry Andric 
279fe6060f1SDimitry Andric   Expected<ArrayRef<SectionHeader>> Sections = ObjRef->sections();
280fe6060f1SDimitry Andric   if (!Sections)
281fe6060f1SDimitry Andric     return Sections.takeError();
282fe6060f1SDimitry Andric 
283fe6060f1SDimitry Andric   bool HasDwarfSection = false;
284fe6060f1SDimitry Andric   for (const SectionHeader &Header : *Sections) {
285fe6060f1SDimitry Andric     Expected<StringRef> Name = ObjRef->getSectionName(Header);
286fe6060f1SDimitry Andric     if (!Name)
287fe6060f1SDimitry Andric       return Name.takeError();
288fe6060f1SDimitry Andric     if (Name->empty())
289fe6060f1SDimitry Andric       continue;
290fe6060f1SDimitry Andric     HasDwarfSection |= isDwarfSection(*Name);
291fe6060f1SDimitry Andric 
292*bdd1243dSDimitry Andric     if (!(Header.sh_flags & ELF::SHF_ALLOC))
293*bdd1243dSDimitry Andric       continue;
294*bdd1243dSDimitry Andric 
295fe6060f1SDimitry Andric     auto Wrapped = std::make_unique<ELFDebugObjectSection<ELFT>>(&Header);
296fe6060f1SDimitry Andric     if (Error Err = DebugObj->recordSection(*Name, std::move(Wrapped)))
297fe6060f1SDimitry Andric       return std::move(Err);
298fe6060f1SDimitry Andric   }
299fe6060f1SDimitry Andric 
300fe6060f1SDimitry Andric   if (!HasDwarfSection) {
301fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "Aborting debug registration for LinkGraph \""
302fe6060f1SDimitry Andric                       << DebugObj->Buffer->getBufferIdentifier()
303fe6060f1SDimitry Andric                       << "\": input object contains no debug info\n");
304fe6060f1SDimitry Andric     return nullptr;
305fe6060f1SDimitry Andric   }
306fe6060f1SDimitry Andric 
307fe6060f1SDimitry Andric   return std::move(DebugObj);
308fe6060f1SDimitry Andric }
309fe6060f1SDimitry Andric 
310fe6060f1SDimitry Andric Expected<std::unique_ptr<DebugObject>>
311fe6060f1SDimitry Andric ELFDebugObject::Create(MemoryBufferRef Buffer, JITLinkContext &Ctx,
312fe6060f1SDimitry Andric                        ExecutionSession &ES) {
313fe6060f1SDimitry Andric   unsigned char Class, Endian;
314fe6060f1SDimitry Andric   std::tie(Class, Endian) = getElfArchType(Buffer.getBuffer());
315fe6060f1SDimitry Andric 
316fe6060f1SDimitry Andric   if (Class == ELF::ELFCLASS32) {
317fe6060f1SDimitry Andric     if (Endian == ELF::ELFDATA2LSB)
318349cc55cSDimitry Andric       return CreateArchType<ELF32LE>(Buffer, Ctx.getMemoryManager(),
319349cc55cSDimitry Andric                                      Ctx.getJITLinkDylib(), ES);
320fe6060f1SDimitry Andric     if (Endian == ELF::ELFDATA2MSB)
321349cc55cSDimitry Andric       return CreateArchType<ELF32BE>(Buffer, Ctx.getMemoryManager(),
322349cc55cSDimitry Andric                                      Ctx.getJITLinkDylib(), ES);
323fe6060f1SDimitry Andric     return nullptr;
324fe6060f1SDimitry Andric   }
325fe6060f1SDimitry Andric   if (Class == ELF::ELFCLASS64) {
326fe6060f1SDimitry Andric     if (Endian == ELF::ELFDATA2LSB)
327349cc55cSDimitry Andric       return CreateArchType<ELF64LE>(Buffer, Ctx.getMemoryManager(),
328349cc55cSDimitry Andric                                      Ctx.getJITLinkDylib(), ES);
329fe6060f1SDimitry Andric     if (Endian == ELF::ELFDATA2MSB)
330349cc55cSDimitry Andric       return CreateArchType<ELF64BE>(Buffer, Ctx.getMemoryManager(),
331349cc55cSDimitry Andric                                      Ctx.getJITLinkDylib(), ES);
332fe6060f1SDimitry Andric     return nullptr;
333fe6060f1SDimitry Andric   }
334fe6060f1SDimitry Andric   return nullptr;
335fe6060f1SDimitry Andric }
336fe6060f1SDimitry Andric 
337349cc55cSDimitry Andric Expected<SimpleSegmentAlloc> ELFDebugObject::finalizeWorkingMemory() {
338fe6060f1SDimitry Andric   LLVM_DEBUG({
339fe6060f1SDimitry Andric     dbgs() << "Section load-addresses in debug object for \""
340fe6060f1SDimitry Andric            << Buffer->getBufferIdentifier() << "\":\n";
341fe6060f1SDimitry Andric     for (const auto &KV : Sections)
342fe6060f1SDimitry Andric       KV.second->dump(dbgs(), KV.first());
343fe6060f1SDimitry Andric   });
344fe6060f1SDimitry Andric 
345fe6060f1SDimitry Andric   // TODO: This works, but what actual alignment requirements do we have?
346349cc55cSDimitry Andric   unsigned PageSize = sys::Process::getPageSizeEstimate();
347fe6060f1SDimitry Andric   size_t Size = Buffer->getBufferSize();
348fe6060f1SDimitry Andric 
349fe6060f1SDimitry Andric   // Allocate working memory for debug object in read-only segment.
350349cc55cSDimitry Andric   auto Alloc = SimpleSegmentAlloc::Create(
351349cc55cSDimitry Andric       MemMgr, JD, {{MemProt::Read, {Size, Align(PageSize)}}});
352349cc55cSDimitry Andric   if (!Alloc)
353349cc55cSDimitry Andric     return Alloc;
354fe6060f1SDimitry Andric 
355fe6060f1SDimitry Andric   // Initialize working memory with a copy of our object buffer.
356349cc55cSDimitry Andric   auto SegInfo = Alloc->getSegInfo(MemProt::Read);
357349cc55cSDimitry Andric   memcpy(SegInfo.WorkingMem.data(), Buffer->getBufferStart(), Size);
358fe6060f1SDimitry Andric   Buffer.reset();
359fe6060f1SDimitry Andric 
360349cc55cSDimitry Andric   return Alloc;
361fe6060f1SDimitry Andric }
362fe6060f1SDimitry Andric 
363fe6060f1SDimitry Andric void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name,
364fe6060f1SDimitry Andric                                                     SectionRange TargetMem) {
365fe6060f1SDimitry Andric   if (auto *DebugObjSection = getSection(Name))
366fe6060f1SDimitry Andric     DebugObjSection->setTargetMemoryRange(TargetMem);
367fe6060f1SDimitry Andric }
368fe6060f1SDimitry Andric 
369fe6060f1SDimitry Andric template <typename ELFT>
370fe6060f1SDimitry Andric Error ELFDebugObject::recordSection(
371fe6060f1SDimitry Andric     StringRef Name, std::unique_ptr<ELFDebugObjectSection<ELFT>> Section) {
372fe6060f1SDimitry Andric   if (Error Err = Section->validateInBounds(this->getBuffer(), Name.data()))
373fe6060f1SDimitry Andric     return Err;
374fe6060f1SDimitry Andric   auto ItInserted = Sections.try_emplace(Name, std::move(Section));
375fe6060f1SDimitry Andric   if (!ItInserted.second)
376*bdd1243dSDimitry Andric     return make_error<StringError>("In " + Buffer->getBufferIdentifier() +
377*bdd1243dSDimitry Andric 				   ", encountered duplicate section \"" +
378*bdd1243dSDimitry Andric 				   Name + "\" while building debug object",
379fe6060f1SDimitry Andric                                    inconvertibleErrorCode());
380fe6060f1SDimitry Andric   return Error::success();
381fe6060f1SDimitry Andric }
382fe6060f1SDimitry Andric 
383fe6060f1SDimitry Andric DebugObjectSection *ELFDebugObject::getSection(StringRef Name) {
384fe6060f1SDimitry Andric   auto It = Sections.find(Name);
385fe6060f1SDimitry Andric   return It == Sections.end() ? nullptr : It->second.get();
386fe6060f1SDimitry Andric }
387fe6060f1SDimitry Andric 
388fe6060f1SDimitry Andric /// Creates a debug object based on the input object file from
389fe6060f1SDimitry Andric /// ObjectLinkingLayerJITLinkContext.
390fe6060f1SDimitry Andric ///
391fe6060f1SDimitry Andric static Expected<std::unique_ptr<DebugObject>>
392fe6060f1SDimitry Andric createDebugObjectFromBuffer(ExecutionSession &ES, LinkGraph &G,
393fe6060f1SDimitry Andric                             JITLinkContext &Ctx, MemoryBufferRef ObjBuffer) {
394fe6060f1SDimitry Andric   switch (G.getTargetTriple().getObjectFormat()) {
395fe6060f1SDimitry Andric   case Triple::ELF:
396fe6060f1SDimitry Andric     return ELFDebugObject::Create(ObjBuffer, Ctx, ES);
397fe6060f1SDimitry Andric 
398fe6060f1SDimitry Andric   default:
399fe6060f1SDimitry Andric     // TODO: Once we add support for other formats, we might want to split this
400fe6060f1SDimitry Andric     // into multiple files.
401fe6060f1SDimitry Andric     return nullptr;
402fe6060f1SDimitry Andric   }
403fe6060f1SDimitry Andric }
404fe6060f1SDimitry Andric 
405fe6060f1SDimitry Andric DebugObjectManagerPlugin::DebugObjectManagerPlugin(
406fe6060f1SDimitry Andric     ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target)
407fe6060f1SDimitry Andric     : ES(ES), Target(std::move(Target)) {}
408fe6060f1SDimitry Andric 
409fe6060f1SDimitry Andric DebugObjectManagerPlugin::~DebugObjectManagerPlugin() = default;
410fe6060f1SDimitry Andric 
411fe6060f1SDimitry Andric void DebugObjectManagerPlugin::notifyMaterializing(
412fe6060f1SDimitry Andric     MaterializationResponsibility &MR, LinkGraph &G, JITLinkContext &Ctx,
413fe6060f1SDimitry Andric     MemoryBufferRef ObjBuffer) {
414fe6060f1SDimitry Andric   std::lock_guard<std::mutex> Lock(PendingObjsLock);
415fe6060f1SDimitry Andric   assert(PendingObjs.count(&MR) == 0 &&
416fe6060f1SDimitry Andric          "Cannot have more than one pending debug object per "
417fe6060f1SDimitry Andric          "MaterializationResponsibility");
418fe6060f1SDimitry Andric 
419fe6060f1SDimitry Andric   if (auto DebugObj = createDebugObjectFromBuffer(ES, G, Ctx, ObjBuffer)) {
420fe6060f1SDimitry Andric     // Not all link artifacts allow debugging.
421fe6060f1SDimitry Andric     if (*DebugObj != nullptr)
422fe6060f1SDimitry Andric       PendingObjs[&MR] = std::move(*DebugObj);
423fe6060f1SDimitry Andric   } else {
424fe6060f1SDimitry Andric     ES.reportError(DebugObj.takeError());
425fe6060f1SDimitry Andric   }
426fe6060f1SDimitry Andric }
427fe6060f1SDimitry Andric 
428fe6060f1SDimitry Andric void DebugObjectManagerPlugin::modifyPassConfig(
429fe6060f1SDimitry Andric     MaterializationResponsibility &MR, LinkGraph &G,
430fe6060f1SDimitry Andric     PassConfiguration &PassConfig) {
431fe6060f1SDimitry Andric   // Not all link artifacts have associated debug objects.
432fe6060f1SDimitry Andric   std::lock_guard<std::mutex> Lock(PendingObjsLock);
433fe6060f1SDimitry Andric   auto It = PendingObjs.find(&MR);
434fe6060f1SDimitry Andric   if (It == PendingObjs.end())
435fe6060f1SDimitry Andric     return;
436fe6060f1SDimitry Andric 
437fe6060f1SDimitry Andric   DebugObject &DebugObj = *It->second;
438fe6060f1SDimitry Andric   if (DebugObj.has(Requirement::ReportFinalSectionLoadAddresses)) {
439fe6060f1SDimitry Andric     PassConfig.PostAllocationPasses.push_back(
440fe6060f1SDimitry Andric         [&DebugObj](LinkGraph &Graph) -> Error {
441fe6060f1SDimitry Andric           for (const Section &GraphSection : Graph.sections())
442fe6060f1SDimitry Andric             DebugObj.reportSectionTargetMemoryRange(GraphSection.getName(),
443fe6060f1SDimitry Andric                                                     SectionRange(GraphSection));
444fe6060f1SDimitry Andric           return Error::success();
445fe6060f1SDimitry Andric         });
446fe6060f1SDimitry Andric   }
447fe6060f1SDimitry Andric }
448fe6060f1SDimitry Andric 
449fe6060f1SDimitry Andric Error DebugObjectManagerPlugin::notifyEmitted(
450fe6060f1SDimitry Andric     MaterializationResponsibility &MR) {
451fe6060f1SDimitry Andric   std::lock_guard<std::mutex> Lock(PendingObjsLock);
452fe6060f1SDimitry Andric   auto It = PendingObjs.find(&MR);
453fe6060f1SDimitry Andric   if (It == PendingObjs.end())
454fe6060f1SDimitry Andric     return Error::success();
455fe6060f1SDimitry Andric 
456fe6060f1SDimitry Andric   // During finalization the debug object is registered with the target.
457fe6060f1SDimitry Andric   // Materialization must wait for this process to finish. Otherwise we might
458fe6060f1SDimitry Andric   // start running code before the debugger processed the corresponding debug
459fe6060f1SDimitry Andric   // info.
460fe6060f1SDimitry Andric   std::promise<MSVCPError> FinalizePromise;
461fe6060f1SDimitry Andric   std::future<MSVCPError> FinalizeErr = FinalizePromise.get_future();
462fe6060f1SDimitry Andric 
463fe6060f1SDimitry Andric   It->second->finalizeAsync(
464349cc55cSDimitry Andric       [this, &FinalizePromise, &MR](Expected<ExecutorAddrRange> TargetMem) {
465fe6060f1SDimitry Andric         // Any failure here will fail materialization.
466fe6060f1SDimitry Andric         if (!TargetMem) {
467fe6060f1SDimitry Andric           FinalizePromise.set_value(TargetMem.takeError());
468fe6060f1SDimitry Andric           return;
469fe6060f1SDimitry Andric         }
470fe6060f1SDimitry Andric         if (Error Err = Target->registerDebugObject(*TargetMem)) {
471fe6060f1SDimitry Andric           FinalizePromise.set_value(std::move(Err));
472fe6060f1SDimitry Andric           return;
473fe6060f1SDimitry Andric         }
474fe6060f1SDimitry Andric 
475fe6060f1SDimitry Andric         // Once our tracking info is updated, notifyEmitted() can return and
476fe6060f1SDimitry Andric         // finish materialization.
477fe6060f1SDimitry Andric         FinalizePromise.set_value(MR.withResourceKeyDo([&](ResourceKey K) {
478fe6060f1SDimitry Andric           assert(PendingObjs.count(&MR) && "We still hold PendingObjsLock");
479fe6060f1SDimitry Andric           std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
480fe6060f1SDimitry Andric           RegisteredObjs[K].push_back(std::move(PendingObjs[&MR]));
481fe6060f1SDimitry Andric           PendingObjs.erase(&MR);
482fe6060f1SDimitry Andric         }));
483fe6060f1SDimitry Andric       });
484fe6060f1SDimitry Andric 
485fe6060f1SDimitry Andric   return FinalizeErr.get();
486fe6060f1SDimitry Andric }
487fe6060f1SDimitry Andric 
488fe6060f1SDimitry Andric Error DebugObjectManagerPlugin::notifyFailed(
489fe6060f1SDimitry Andric     MaterializationResponsibility &MR) {
490fe6060f1SDimitry Andric   std::lock_guard<std::mutex> Lock(PendingObjsLock);
491fe6060f1SDimitry Andric   PendingObjs.erase(&MR);
492fe6060f1SDimitry Andric   return Error::success();
493fe6060f1SDimitry Andric }
494fe6060f1SDimitry Andric 
495*bdd1243dSDimitry Andric void DebugObjectManagerPlugin::notifyTransferringResources(JITDylib &JD,
496*bdd1243dSDimitry Andric                                                            ResourceKey DstKey,
497fe6060f1SDimitry Andric                                                            ResourceKey SrcKey) {
498fe6060f1SDimitry Andric   // Debug objects are stored by ResourceKey only after registration.
499fe6060f1SDimitry Andric   // Thus, pending objects don't need to be updated here.
500fe6060f1SDimitry Andric   std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
501fe6060f1SDimitry Andric   auto SrcIt = RegisteredObjs.find(SrcKey);
502fe6060f1SDimitry Andric   if (SrcIt != RegisteredObjs.end()) {
503fe6060f1SDimitry Andric     // Resources from distinct MaterializationResponsibilitys can get merged
504fe6060f1SDimitry Andric     // after emission, so we can have multiple debug objects per resource key.
505fe6060f1SDimitry Andric     for (std::unique_ptr<DebugObject> &DebugObj : SrcIt->second)
506fe6060f1SDimitry Andric       RegisteredObjs[DstKey].push_back(std::move(DebugObj));
507fe6060f1SDimitry Andric     RegisteredObjs.erase(SrcIt);
508fe6060f1SDimitry Andric   }
509fe6060f1SDimitry Andric }
510fe6060f1SDimitry Andric 
511*bdd1243dSDimitry Andric Error DebugObjectManagerPlugin::notifyRemovingResources(JITDylib &JD,
512*bdd1243dSDimitry Andric                                                         ResourceKey Key) {
513fe6060f1SDimitry Andric   // Removing the resource for a pending object fails materialization, so they
514fe6060f1SDimitry Andric   // get cleaned up in the notifyFailed() handler.
515fe6060f1SDimitry Andric   std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
516fe6060f1SDimitry Andric   RegisteredObjs.erase(Key);
517fe6060f1SDimitry Andric 
518fe6060f1SDimitry Andric   // TODO: Implement unregister notifications.
519fe6060f1SDimitry Andric   return Error::success();
520fe6060f1SDimitry Andric }
521fe6060f1SDimitry Andric 
522fe6060f1SDimitry Andric } // namespace orc
523fe6060f1SDimitry Andric } // namespace llvm
524