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