xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp (revision 9cb98ab7ceeb97b70a4891a4a3a21372158ccf24)
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 (uint64_t Addr = Header->sh_addr) {
97      OS << formatv("  {0:x16} {1}\n", 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(ROSeg.Addr, ROSeg.WorkingMem.size());
170      SimpleSegAlloc->finalize(
171          [this, DebugObjRange,
172           OnFinalize = std::move(OnFinalize)](Expected<FinalizedAlloc> FA) {
173            if (FA) {
174              Alloc = std::move(*FA);
175              OnFinalize(DebugObjRange);
176            } else
177              OnFinalize(FA.takeError());
178          });
179    } else
180      OnFinalize(SimpleSegAlloc.takeError());
181  }
182  
183  /// The current implementation of ELFDebugObject replicates the approach used in
184  /// RuntimeDyld: It patches executable and data section headers in the given
185  /// object buffer with load-addresses of their corresponding sections in target
186  /// memory.
187  ///
188  class ELFDebugObject : public DebugObject {
189  public:
190    static Expected<std::unique_ptr<DebugObject>>
191    Create(MemoryBufferRef Buffer, JITLinkContext &Ctx, ExecutionSession &ES);
192  
193    void reportSectionTargetMemoryRange(StringRef Name,
194                                        SectionRange TargetMem) override;
195  
196    StringRef getBuffer() const { return Buffer->getMemBufferRef().getBuffer(); }
197  
198  protected:
199    Expected<SimpleSegmentAlloc> finalizeWorkingMemory() override;
200  
201    template <typename ELFT>
202    Error recordSection(StringRef Name,
203                        std::unique_ptr<ELFDebugObjectSection<ELFT>> Section);
204    DebugObjectSection *getSection(StringRef Name);
205  
206  private:
207    template <typename ELFT>
208    static Expected<std::unique_ptr<ELFDebugObject>>
209    CreateArchType(MemoryBufferRef Buffer, JITLinkMemoryManager &MemMgr,
210                   const JITLinkDylib *JD, ExecutionSession &ES);
211  
212    static std::unique_ptr<WritableMemoryBuffer>
213    CopyBuffer(MemoryBufferRef Buffer, Error &Err);
214  
215    ELFDebugObject(std::unique_ptr<WritableMemoryBuffer> Buffer,
216                   JITLinkMemoryManager &MemMgr, const JITLinkDylib *JD,
217                   ExecutionSession &ES)
218        : DebugObject(MemMgr, JD, ES), Buffer(std::move(Buffer)) {
219      setFlags(ReportFinalSectionLoadAddresses);
220    }
221  
222    std::unique_ptr<WritableMemoryBuffer> Buffer;
223    StringMap<std::unique_ptr<DebugObjectSection>> Sections;
224  };
225  
226  static const std::set<StringRef> DwarfSectionNames = {
227  #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION)        \
228    ELF_NAME,
229  #include "llvm/BinaryFormat/Dwarf.def"
230  #undef HANDLE_DWARF_SECTION
231  };
232  
233  static bool isDwarfSection(StringRef SectionName) {
234    return DwarfSectionNames.count(SectionName) == 1;
235  }
236  
237  std::unique_ptr<WritableMemoryBuffer>
238  ELFDebugObject::CopyBuffer(MemoryBufferRef Buffer, Error &Err) {
239    ErrorAsOutParameter _(&Err);
240    size_t Size = Buffer.getBufferSize();
241    StringRef Name = Buffer.getBufferIdentifier();
242    if (auto Copy = WritableMemoryBuffer::getNewUninitMemBuffer(Size, Name)) {
243      memcpy(Copy->getBufferStart(), Buffer.getBufferStart(), Size);
244      return Copy;
245    }
246  
247    Err = errorCodeToError(make_error_code(errc::not_enough_memory));
248    return nullptr;
249  }
250  
251  template <typename ELFT>
252  Expected<std::unique_ptr<ELFDebugObject>>
253  ELFDebugObject::CreateArchType(MemoryBufferRef Buffer,
254                                 JITLinkMemoryManager &MemMgr,
255                                 const JITLinkDylib *JD, ExecutionSession &ES) {
256    using SectionHeader = typename ELFT::Shdr;
257  
258    Error Err = Error::success();
259    std::unique_ptr<ELFDebugObject> DebugObj(
260        new ELFDebugObject(CopyBuffer(Buffer, Err), MemMgr, JD, ES));
261    if (Err)
262      return std::move(Err);
263  
264    Expected<ELFFile<ELFT>> ObjRef = ELFFile<ELFT>::create(DebugObj->getBuffer());
265    if (!ObjRef)
266      return ObjRef.takeError();
267  
268    Expected<ArrayRef<SectionHeader>> Sections = ObjRef->sections();
269    if (!Sections)
270      return Sections.takeError();
271  
272    for (const SectionHeader &Header : *Sections) {
273      Expected<StringRef> Name = ObjRef->getSectionName(Header);
274      if (!Name)
275        return Name.takeError();
276      if (Name->empty())
277        continue;
278      if (isDwarfSection(*Name))
279        DebugObj->setFlags(HasDebugSections);
280  
281      // Only record text and data sections (i.e. no bss, comments, rel, etc.)
282      if (Header.sh_type != ELF::SHT_PROGBITS &&
283          Header.sh_type != ELF::SHT_X86_64_UNWIND)
284        continue;
285      if (!(Header.sh_flags & ELF::SHF_ALLOC))
286        continue;
287  
288      auto Wrapped = std::make_unique<ELFDebugObjectSection<ELFT>>(&Header);
289      if (Error Err = DebugObj->recordSection(*Name, std::move(Wrapped)))
290        return std::move(Err);
291    }
292  
293    return std::move(DebugObj);
294  }
295  
296  Expected<std::unique_ptr<DebugObject>>
297  ELFDebugObject::Create(MemoryBufferRef Buffer, JITLinkContext &Ctx,
298                         ExecutionSession &ES) {
299    unsigned char Class, Endian;
300    std::tie(Class, Endian) = getElfArchType(Buffer.getBuffer());
301  
302    if (Class == ELF::ELFCLASS32) {
303      if (Endian == ELF::ELFDATA2LSB)
304        return CreateArchType<ELF32LE>(Buffer, Ctx.getMemoryManager(),
305                                       Ctx.getJITLinkDylib(), ES);
306      if (Endian == ELF::ELFDATA2MSB)
307        return CreateArchType<ELF32BE>(Buffer, Ctx.getMemoryManager(),
308                                       Ctx.getJITLinkDylib(), ES);
309      return nullptr;
310    }
311    if (Class == ELF::ELFCLASS64) {
312      if (Endian == ELF::ELFDATA2LSB)
313        return CreateArchType<ELF64LE>(Buffer, Ctx.getMemoryManager(),
314                                       Ctx.getJITLinkDylib(), ES);
315      if (Endian == ELF::ELFDATA2MSB)
316        return CreateArchType<ELF64BE>(Buffer, Ctx.getMemoryManager(),
317                                       Ctx.getJITLinkDylib(), ES);
318      return nullptr;
319    }
320    return nullptr;
321  }
322  
323  Expected<SimpleSegmentAlloc> ELFDebugObject::finalizeWorkingMemory() {
324    LLVM_DEBUG({
325      dbgs() << "Section load-addresses in debug object for \""
326             << Buffer->getBufferIdentifier() << "\":\n";
327      for (const auto &KV : Sections)
328        KV.second->dump(dbgs(), KV.first());
329    });
330  
331    // TODO: This works, but what actual alignment requirements do we have?
332    unsigned PageSize = sys::Process::getPageSizeEstimate();
333    size_t Size = Buffer->getBufferSize();
334  
335    // Allocate working memory for debug object in read-only segment.
336    auto Alloc = SimpleSegmentAlloc::Create(
337        MemMgr, JD, {{MemProt::Read, {Size, Align(PageSize)}}});
338    if (!Alloc)
339      return Alloc;
340  
341    // Initialize working memory with a copy of our object buffer.
342    auto SegInfo = Alloc->getSegInfo(MemProt::Read);
343    memcpy(SegInfo.WorkingMem.data(), Buffer->getBufferStart(), Size);
344    Buffer.reset();
345  
346    return Alloc;
347  }
348  
349  void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name,
350                                                      SectionRange TargetMem) {
351    if (auto *DebugObjSection = getSection(Name))
352      DebugObjSection->setTargetMemoryRange(TargetMem);
353  }
354  
355  template <typename ELFT>
356  Error ELFDebugObject::recordSection(
357      StringRef Name, std::unique_ptr<ELFDebugObjectSection<ELFT>> Section) {
358    if (Error Err = Section->validateInBounds(this->getBuffer(), Name.data()))
359      return Err;
360    bool Inserted = Sections.try_emplace(Name, std::move(Section)).second;
361    if (!Inserted)
362      LLVM_DEBUG(dbgs() << "Skipping debug registration for section '" << Name
363                        << "' in object " << Buffer->getBufferIdentifier()
364                        << " (duplicate name)\n");
365    return Error::success();
366  }
367  
368  DebugObjectSection *ELFDebugObject::getSection(StringRef Name) {
369    auto It = Sections.find(Name);
370    return It == Sections.end() ? nullptr : It->second.get();
371  }
372  
373  /// Creates a debug object based on the input object file from
374  /// ObjectLinkingLayerJITLinkContext.
375  ///
376  static Expected<std::unique_ptr<DebugObject>>
377  createDebugObjectFromBuffer(ExecutionSession &ES, LinkGraph &G,
378                              JITLinkContext &Ctx, MemoryBufferRef ObjBuffer) {
379    switch (G.getTargetTriple().getObjectFormat()) {
380    case Triple::ELF:
381      return ELFDebugObject::Create(ObjBuffer, Ctx, ES);
382  
383    default:
384      // TODO: Once we add support for other formats, we might want to split this
385      // into multiple files.
386      return nullptr;
387    }
388  }
389  
390  DebugObjectManagerPlugin::DebugObjectManagerPlugin(
391      ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target,
392      bool RequireDebugSections, bool AutoRegisterCode)
393      : ES(ES), Target(std::move(Target)),
394        RequireDebugSections(RequireDebugSections),
395        AutoRegisterCode(AutoRegisterCode) {}
396  
397  DebugObjectManagerPlugin::DebugObjectManagerPlugin(
398      ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target)
399      : DebugObjectManagerPlugin(ES, std::move(Target), true, 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 =
469                  Target->registerDebugObject(*TargetMem, AutoRegisterCode)) {
470            FinalizePromise.set_value(std::move(Err));
471            return;
472          }
473  
474          // Once our tracking info is updated, notifyEmitted() can return and
475          // finish materialization.
476          FinalizePromise.set_value(MR.withResourceKeyDo([&](ResourceKey K) {
477            assert(PendingObjs.count(&MR) && "We still hold PendingObjsLock");
478            std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
479            RegisteredObjs[K].push_back(std::move(PendingObjs[&MR]));
480            PendingObjs.erase(&MR);
481          }));
482        });
483  
484    return FinalizeErr.get();
485  }
486  
487  Error DebugObjectManagerPlugin::notifyFailed(
488      MaterializationResponsibility &MR) {
489    std::lock_guard<std::mutex> Lock(PendingObjsLock);
490    PendingObjs.erase(&MR);
491    return Error::success();
492  }
493  
494  void DebugObjectManagerPlugin::notifyTransferringResources(JITDylib &JD,
495                                                             ResourceKey DstKey,
496                                                             ResourceKey SrcKey) {
497    // Debug objects are stored by ResourceKey only after registration.
498    // Thus, pending objects don't need to be updated here.
499    std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
500    auto SrcIt = RegisteredObjs.find(SrcKey);
501    if (SrcIt != RegisteredObjs.end()) {
502      // Resources from distinct MaterializationResponsibilitys can get merged
503      // after emission, so we can have multiple debug objects per resource key.
504      for (std::unique_ptr<DebugObject> &DebugObj : SrcIt->second)
505        RegisteredObjs[DstKey].push_back(std::move(DebugObj));
506      RegisteredObjs.erase(SrcIt);
507    }
508  }
509  
510  Error DebugObjectManagerPlugin::notifyRemovingResources(JITDylib &JD,
511                                                          ResourceKey Key) {
512    // Removing the resource for a pending object fails materialization, so they
513    // get cleaned up in the notifyFailed() handler.
514    std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
515    RegisteredObjs.erase(Key);
516  
517    // TODO: Implement unregister notifications.
518    return Error::success();
519  }
520  
521  } // namespace orc
522  } // namespace llvm
523