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