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