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