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