xref: /llvm-project/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp (revision a747e35c3ec371fce1f36424986b6b40ee2f25a9)
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   JITLinkMemoryManager::SegmentsRequestMap SingleReadOnlySegment;
296   SingleReadOnlySegment[ReadOnly] =
297       JITLinkMemoryManager::SegmentRequest(Alignment, Size, 0);
298 
299   auto AllocOrErr = MemMgr.allocate(JD, SingleReadOnlySegment);
300   if (!AllocOrErr)
301     return AllocOrErr.takeError();
302 
303   // Initialize working memory with a copy of our object buffer.
304   // TODO: Use our buffer as working memory directly.
305   std::unique_ptr<Allocation> Alloc = std::move(*AllocOrErr);
306   MutableArrayRef<char> WorkingMem = Alloc->getWorkingMemory(ReadOnly);
307   memcpy(WorkingMem.data(), Buffer->getBufferStart(), Size);
308   Buffer.reset();
309 
310   return std::move(Alloc);
311 }
312 
313 void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name,
314                                                     SectionRange TargetMem) {
315   if (auto *DebugObjSection = getSection(Name))
316     DebugObjSection->setTargetMemoryRange(TargetMem);
317 }
318 
319 Error ELFDebugObject::recordSection(
320     StringRef Name, std::unique_ptr<DebugObjectSection> Section) {
321   auto ItInserted = Sections.try_emplace(Name, std::move(Section));
322   if (!ItInserted.second)
323     return make_error<StringError>("Duplicate section",
324                                    inconvertibleErrorCode());
325   return Error::success();
326 }
327 
328 DebugObjectSection *ELFDebugObject::getSection(StringRef Name) {
329   auto It = Sections.find(Name);
330   return It == Sections.end() ? nullptr : It->second.get();
331 }
332 
333 static ResourceKey getResourceKey(MaterializationResponsibility &MR) {
334   ResourceKey Key;
335   if (auto Err = MR.withResourceKeyDo([&](ResourceKey K) { Key = K; })) {
336     MR.getExecutionSession().reportError(std::move(Err));
337     return ResourceKey{};
338   }
339   assert(Key && "Invalid key");
340   return Key;
341 }
342 
343 /// Creates a debug object based on the input object file from
344 /// ObjectLinkingLayerJITLinkContext.
345 ///
346 static Expected<std::unique_ptr<DebugObject>>
347 createDebugObjectFromBuffer(LinkGraph &G, JITLinkContext &Ctx,
348                             MemoryBufferRef ObjBuffer) {
349   switch (G.getTargetTriple().getObjectFormat()) {
350   case Triple::ELF:
351     return ELFDebugObject::Create(ObjBuffer, Ctx);
352 
353   default:
354     // TODO: Once we add support for other formats, we might want to split this
355     // into multiple files.
356     return nullptr;
357   }
358 }
359 
360 DebugObjectManagerPlugin::DebugObjectManagerPlugin(
361     ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target)
362     : ES(ES), Target(std::move(Target)) {}
363 
364 DebugObjectManagerPlugin::~DebugObjectManagerPlugin() {}
365 
366 void DebugObjectManagerPlugin::notifyMaterializing(
367     MaterializationResponsibility &MR, LinkGraph &G, JITLinkContext &Ctx,
368     MemoryBufferRef ObjBuffer) {
369   assert(PendingObjs.count(getResourceKey(MR)) == 0 &&
370          "Cannot have more than one pending debug object per "
371          "MaterializationResponsibility");
372 
373   std::lock_guard<std::mutex> Lock(PendingObjsLock);
374   if (auto DebugObj = createDebugObjectFromBuffer(G, Ctx, ObjBuffer)) {
375     // Not all link artifacts allow debugging.
376     if (*DebugObj != nullptr) {
377       ResourceKey Key = getResourceKey(MR);
378       PendingObjs[Key] = std::move(*DebugObj);
379     }
380   } else {
381     ES.reportError(DebugObj.takeError());
382   }
383 }
384 
385 void DebugObjectManagerPlugin::modifyPassConfig(
386     MaterializationResponsibility &MR, const Triple &TT,
387     PassConfiguration &PassConfig) {
388   // Not all link artifacts have associated debug objects.
389   std::lock_guard<std::mutex> Lock(PendingObjsLock);
390   auto It = PendingObjs.find(getResourceKey(MR));
391   if (It == PendingObjs.end())
392     return;
393 
394   DebugObject &DebugObj = *It->second;
395   if (DebugObj.has(Requirement::ReportFinalSectionLoadAddresses)) {
396     PassConfig.PostAllocationPasses.push_back(
397         [&DebugObj](LinkGraph &Graph) -> Error {
398           for (const Section &GraphSection : Graph.sections())
399             DebugObj.reportSectionTargetMemoryRange(GraphSection.getName(),
400                                                     SectionRange(GraphSection));
401           return Error::success();
402         });
403   }
404 }
405 
406 Error DebugObjectManagerPlugin::notifyEmitted(
407     MaterializationResponsibility &MR) {
408   ResourceKey Key = getResourceKey(MR);
409 
410   std::lock_guard<std::mutex> Lock(PendingObjsLock);
411   auto It = PendingObjs.find(Key);
412   if (It == PendingObjs.end())
413     return Error::success();
414 
415   DebugObject *UnownedDebugObj = It->second.release();
416   PendingObjs.erase(It);
417 
418   // FIXME: We released ownership of the DebugObject, so we can easily capture
419   // the raw pointer in the continuation function, which re-owns it immediately.
420   if (UnownedDebugObj)
421     UnownedDebugObj->finalizeAsync(
422         [this, Key, UnownedDebugObj](Expected<sys::MemoryBlock> TargetMem) {
423           std::unique_ptr<DebugObject> ReownedDebugObj(UnownedDebugObj);
424           if (!TargetMem) {
425             ES.reportError(TargetMem.takeError());
426             return;
427           }
428           if (Error Err = Target->registerDebugObject(*TargetMem)) {
429             ES.reportError(std::move(Err));
430             return;
431           }
432 
433           std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
434           RegisteredObjs[Key].push_back(std::move(ReownedDebugObj));
435         });
436 
437   return Error::success();
438 }
439 
440 Error DebugObjectManagerPlugin::notifyFailed(
441     MaterializationResponsibility &MR) {
442   std::lock_guard<std::mutex> Lock(PendingObjsLock);
443   PendingObjs.erase(getResourceKey(MR));
444   return Error::success();
445 }
446 
447 void DebugObjectManagerPlugin::notifyTransferringResources(ResourceKey DstKey,
448                                                            ResourceKey SrcKey) {
449   {
450     std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
451     auto SrcIt = RegisteredObjs.find(SrcKey);
452     if (SrcIt != RegisteredObjs.end()) {
453       // Resources from distinct MaterializationResponsibilitys can get merged
454       // after emission, so we can have multiple debug objects per resource key.
455       for (std::unique_ptr<DebugObject> &DebugObj : SrcIt->second)
456         RegisteredObjs[DstKey].push_back(std::move(DebugObj));
457       RegisteredObjs.erase(SrcIt);
458     }
459   }
460   {
461     std::lock_guard<std::mutex> Lock(PendingObjsLock);
462     auto SrcIt = PendingObjs.find(SrcKey);
463     if (SrcIt != PendingObjs.end()) {
464       assert(PendingObjs.count(DstKey) == 0 &&
465              "Cannot have more than one pending debug object per "
466              "MaterializationResponsibility");
467       PendingObjs[DstKey] = std::move(SrcIt->second);
468       PendingObjs.erase(SrcIt);
469     }
470   }
471 }
472 
473 Error DebugObjectManagerPlugin::notifyRemovingResources(ResourceKey K) {
474   {
475     std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
476     RegisteredObjs.erase(K);
477     // TODO: Implement unregister notifications.
478   }
479   std::lock_guard<std::mutex> Lock(PendingObjsLock);
480   PendingObjs.erase(K);
481 
482   return Error::success();
483 }
484 
485 } // namespace orc
486 } // namespace llvm
487