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
35using namespace llvm::jitlink;
36using namespace llvm::object;
37
38namespace llvm {
39namespace orc {
40
41class DebugObjectSection {
42public:
43  virtual void setTargetMemoryRange(SectionRange Range) = 0;
44  virtual void dump(raw_ostream &OS, StringRef Name) {}
45  virtual ~DebugObjectSection() = default;
46};
47
48template <typename ELFT>
49class ELFDebugObjectSection : public DebugObjectSection {
50public:
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
61private:
62  typename ELFT::Shdr *Header;
63
64  bool isTextOrDataSection() const;
65};
66
67template <typename ELFT>
68void 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
75template <typename ELFT>
76bool 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
85template <typename ELFT>
86Error 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
107template <typename ELFT>
108void 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
116enum 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///
126class DebugObject {
127public:
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
151protected:
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
160private:
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.
169void 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///
194class ELFDebugObject : public DebugObject {
195public:
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
204protected:
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
212private:
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
232static 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
239static bool isDwarfSection(StringRef SectionName) {
240  return DwarfSectionNames.count(SectionName) == 1;
241}
242
243std::unique_ptr<WritableMemoryBuffer>
244ELFDebugObject::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
257template <typename ELFT>
258Expected<std::unique_ptr<ELFDebugObject>>
259ELFDebugObject::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
310Expected<std::unique_ptr<DebugObject>>
311ELFDebugObject::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
337Expected<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
363void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name,
364                                                    SectionRange TargetMem) {
365  if (auto *DebugObjSection = getSection(Name))
366    DebugObjSection->setTargetMemoryRange(TargetMem);
367}
368
369template <typename ELFT>
370Error 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
383DebugObjectSection *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///
391static Expected<std::unique_ptr<DebugObject>>
392createDebugObjectFromBuffer(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
405DebugObjectManagerPlugin::DebugObjectManagerPlugin(
406    ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target)
407    : ES(ES), Target(std::move(Target)) {}
408
409DebugObjectManagerPlugin::~DebugObjectManagerPlugin() = default;
410
411void 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
428void 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
449Error 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
488Error DebugObjectManagerPlugin::notifyFailed(
489    MaterializationResponsibility &MR) {
490  std::lock_guard<std::mutex> Lock(PendingObjsLock);
491  PendingObjs.erase(&MR);
492  return Error::success();
493}
494
495void 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
511Error 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