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