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