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