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