1 //===------- DebugObjectManagerPlugin.cpp - JITLink debug objects ---------===//
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
7 //===----------------------------------------------------------------------===//
9 // FIXME: Update Plugin to poke the debug object into a new JITLink section,
10 // rather than creating a new allocation.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
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"
33 #define DEBUG_TYPE "orc"
35 using namespace llvm::jitlink
;
36 using namespace llvm::object
;
41 class DebugObjectSection
{
43 virtual void setTargetMemoryRange(SectionRange Range
) = 0;
44 virtual void dump(raw_ostream
&OS
, StringRef Name
) {}
45 virtual ~DebugObjectSection() {}
48 template <typename ELFT
>
49 class ELFDebugObjectSection
: public DebugObjectSection
{
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
)) {}
56 void setTargetMemoryRange(SectionRange Range
) override
;
57 void dump(raw_ostream
&OS
, StringRef Name
) override
;
59 Error
validateInBounds(StringRef Buffer
, const char *Name
) const;
62 typename
ELFT::Shdr
*Header
;
64 bool isTextOrDataSection() const;
67 template <typename ELFT
>
68 void ELFDebugObjectSection
<ELFT
>::setTargetMemoryRange(SectionRange Range
) {
69 // Only patch load-addresses for executable and data sections.
70 if (isTextOrDataSection())
72 static_cast<typename
ELFT::uint
>(Range
.getStart().getValue());
75 template <typename ELFT
>
76 bool ELFDebugObjectSection
<ELFT
>::isTextOrDataSection() const {
77 switch (Header
->sh_type
) {
78 case ELF::SHT_PROGBITS
:
79 case ELF::SHT_X86_64_UNWIND
:
80 return Header
->sh_flags
& (ELF::SHF_EXECINSTR
| ELF::SHF_ALLOC
);
85 template <typename ELFT
>
86 Error ELFDebugObjectSection
<ELFT
>::validateInBounds(StringRef Buffer
,
87 const char *Name
) const {
88 const uint8_t *Start
= Buffer
.bytes_begin();
89 const uint8_t *End
= Buffer
.bytes_end();
90 const uint8_t *HeaderPtr
= reinterpret_cast<uint8_t *>(Header
);
91 if (HeaderPtr
< Start
|| HeaderPtr
+ sizeof(typename
ELFT::Shdr
) > End
)
92 return make_error
<StringError
>(
93 formatv("{0} section header at {1:x16} not within bounds of the "
94 "given debug object buffer [{2:x16} - {3:x16}]",
95 Name
, &Header
->sh_addr
, Start
, End
),
96 inconvertibleErrorCode());
97 if (Header
->sh_offset
+ Header
->sh_size
> Buffer
.size())
98 return make_error
<StringError
>(
99 formatv("{0} section data [{1:x16} - {2:x16}] not within bounds of "
100 "the given debug object buffer [{3:x16} - {4:x16}]",
101 Name
, Start
+ Header
->sh_offset
,
102 Start
+ Header
->sh_offset
+ Header
->sh_size
, Start
, End
),
103 inconvertibleErrorCode());
104 return Error::success();
107 template <typename ELFT
>
108 void ELFDebugObjectSection
<ELFT
>::dump(raw_ostream
&OS
, StringRef Name
) {
109 if (auto Addr
= static_cast<JITTargetAddress
>(Header
->sh_addr
)) {
110 OS
<< formatv(" {0:x16} {1}\n", Addr
, Name
);
112 OS
<< formatv(" {0}\n", Name
);
116 enum class Requirement
{
117 // Request final target memory load-addresses for all sections.
118 ReportFinalSectionLoadAddresses
,
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.
128 DebugObject(JITLinkMemoryManager
&MemMgr
, const JITLinkDylib
*JD
,
129 ExecutionSession
&ES
)
130 : MemMgr(MemMgr
), JD(JD
), ES(ES
) {}
132 void set(Requirement Req
) { Reqs
.insert(Req
); }
133 bool has(Requirement Req
) const { return Reqs
.count(Req
) > 0; }
135 using FinalizeContinuation
= std::function
<void(Expected
<ExecutorAddrRange
>)>;
137 void finalizeAsync(FinalizeContinuation OnFinalize
);
139 virtual ~DebugObject() {
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
));
148 virtual void reportSectionTargetMemoryRange(StringRef Name
,
149 SectionRange TargetMem
) {}
152 using InFlightAlloc
= JITLinkMemoryManager::InFlightAlloc
;
153 using FinalizedAlloc
= JITLinkMemoryManager::FinalizedAlloc
;
155 virtual Expected
<SimpleSegmentAlloc
> finalizeWorkingMemory() = 0;
157 JITLinkMemoryManager
&MemMgr
;
158 const JITLinkDylib
*JD
= nullptr;
161 ExecutionSession
&ES
;
162 std::set
<Requirement
> Reqs
;
163 FinalizedAlloc Alloc
;
166 // Finalize working memory and take ownership of the resulting allocation. Start
167 // copying memory over to the target and pass on the result once we're done.
168 // Ownership of the allocation remains with us for the rest of our lifetime.
169 void DebugObject::finalizeAsync(FinalizeContinuation OnFinalize
) {
170 assert(!Alloc
&& "Cannot finalize more than once");
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
) {
180 Alloc
= std::move(*FA
);
181 OnFinalize(DebugObjRange
);
183 OnFinalize(FA
.takeError());
186 OnFinalize(SimpleSegAlloc
.takeError());
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
194 class ELFDebugObject
: public DebugObject
{
196 static Expected
<std::unique_ptr
<DebugObject
>>
197 Create(MemoryBufferRef Buffer
, JITLinkContext
&Ctx
, ExecutionSession
&ES
);
199 void reportSectionTargetMemoryRange(StringRef Name
,
200 SectionRange TargetMem
) override
;
202 StringRef
getBuffer() const { return Buffer
->getMemBufferRef().getBuffer(); }
205 Expected
<SimpleSegmentAlloc
> finalizeWorkingMemory() override
;
207 template <typename ELFT
>
208 Error
recordSection(StringRef Name
,
209 std::unique_ptr
<ELFDebugObjectSection
<ELFT
>> Section
);
210 DebugObjectSection
*getSection(StringRef Name
);
213 template <typename ELFT
>
214 static Expected
<std::unique_ptr
<ELFDebugObject
>>
215 CreateArchType(MemoryBufferRef Buffer
, JITLinkMemoryManager
&MemMgr
,
216 const JITLinkDylib
*JD
, ExecutionSession
&ES
);
218 static std::unique_ptr
<WritableMemoryBuffer
>
219 CopyBuffer(MemoryBufferRef Buffer
, Error
&Err
);
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
);
228 std::unique_ptr
<WritableMemoryBuffer
> Buffer
;
229 StringMap
<std::unique_ptr
<DebugObjectSection
>> Sections
;
232 static const std::set
<StringRef
> DwarfSectionNames
= {
233 #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION) \
235 #include "llvm/BinaryFormat/Dwarf.def"
236 #undef HANDLE_DWARF_SECTION
239 static bool isDwarfSection(StringRef SectionName
) {
240 return DwarfSectionNames
.count(SectionName
) == 1;
243 std::unique_ptr
<WritableMemoryBuffer
>
244 ELFDebugObject::CopyBuffer(MemoryBufferRef Buffer
, Error
&Err
) {
245 ErrorAsOutParameter
_(&Err
);
246 size_t Size
= Buffer
.getBufferSize();
247 StringRef Name
= Buffer
.getBufferIdentifier();
248 if (auto Copy
= WritableMemoryBuffer::getNewUninitMemBuffer(Size
, Name
)) {
249 memcpy(Copy
->getBufferStart(), Buffer
.getBufferStart(), Size
);
253 Err
= errorCodeToError(make_error_code(errc::not_enough_memory
));
257 template <typename ELFT
>
258 Expected
<std::unique_ptr
<ELFDebugObject
>>
259 ELFDebugObject::CreateArchType(MemoryBufferRef Buffer
,
260 JITLinkMemoryManager
&MemMgr
,
261 const JITLinkDylib
*JD
, ExecutionSession
&ES
) {
262 using SectionHeader
= typename
ELFT::Shdr
;
264 Error Err
= Error::success();
265 std::unique_ptr
<ELFDebugObject
> DebugObj(
266 new ELFDebugObject(CopyBuffer(Buffer
, Err
), MemMgr
, JD
, ES
));
268 return std::move(Err
);
270 Expected
<ELFFile
<ELFT
>> ObjRef
= ELFFile
<ELFT
>::create(DebugObj
->getBuffer());
272 return ObjRef
.takeError();
274 // TODO: Add support for other architectures.
275 uint16_t TargetMachineArch
= ObjRef
->getHeader().e_machine
;
276 if (TargetMachineArch
!= ELF::EM_X86_64
)
279 Expected
<ArrayRef
<SectionHeader
>> Sections
= ObjRef
->sections();
281 return Sections
.takeError();
283 bool HasDwarfSection
= false;
284 for (const SectionHeader
&Header
: *Sections
) {
285 Expected
<StringRef
> Name
= ObjRef
->getSectionName(Header
);
287 return Name
.takeError();
290 HasDwarfSection
|= isDwarfSection(*Name
);
292 auto Wrapped
= std::make_unique
<ELFDebugObjectSection
<ELFT
>>(&Header
);
293 if (Error Err
= DebugObj
->recordSection(*Name
, std::move(Wrapped
)))
294 return std::move(Err
);
297 if (!HasDwarfSection
) {
298 LLVM_DEBUG(dbgs() << "Aborting debug registration for LinkGraph \""
299 << DebugObj
->Buffer
->getBufferIdentifier()
300 << "\": input object contains no debug info\n");
304 return std::move(DebugObj
);
307 Expected
<std::unique_ptr
<DebugObject
>>
308 ELFDebugObject::Create(MemoryBufferRef Buffer
, JITLinkContext
&Ctx
,
309 ExecutionSession
&ES
) {
310 unsigned char Class
, Endian
;
311 std::tie(Class
, Endian
) = getElfArchType(Buffer
.getBuffer());
313 if (Class
== ELF::ELFCLASS32
) {
314 if (Endian
== ELF::ELFDATA2LSB
)
315 return CreateArchType
<ELF32LE
>(Buffer
, Ctx
.getMemoryManager(),
316 Ctx
.getJITLinkDylib(), ES
);
317 if (Endian
== ELF::ELFDATA2MSB
)
318 return CreateArchType
<ELF32BE
>(Buffer
, Ctx
.getMemoryManager(),
319 Ctx
.getJITLinkDylib(), ES
);
322 if (Class
== ELF::ELFCLASS64
) {
323 if (Endian
== ELF::ELFDATA2LSB
)
324 return CreateArchType
<ELF64LE
>(Buffer
, Ctx
.getMemoryManager(),
325 Ctx
.getJITLinkDylib(), ES
);
326 if (Endian
== ELF::ELFDATA2MSB
)
327 return CreateArchType
<ELF64BE
>(Buffer
, Ctx
.getMemoryManager(),
328 Ctx
.getJITLinkDylib(), ES
);
334 Expected
<SimpleSegmentAlloc
> ELFDebugObject::finalizeWorkingMemory() {
336 dbgs() << "Section load-addresses in debug object for \""
337 << Buffer
->getBufferIdentifier() << "\":\n";
338 for (const auto &KV
: Sections
)
339 KV
.second
->dump(dbgs(), KV
.first());
342 // TODO: This works, but what actual alignment requirements do we have?
343 unsigned PageSize
= sys::Process::getPageSizeEstimate();
344 size_t Size
= Buffer
->getBufferSize();
346 // Allocate working memory for debug object in read-only segment.
347 auto Alloc
= SimpleSegmentAlloc::Create(
348 MemMgr
, JD
, {{MemProt::Read
, {Size
, Align(PageSize
)}}});
352 // Initialize working memory with a copy of our object buffer.
353 auto SegInfo
= Alloc
->getSegInfo(MemProt::Read
);
354 memcpy(SegInfo
.WorkingMem
.data(), Buffer
->getBufferStart(), Size
);
360 void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name
,
361 SectionRange TargetMem
) {
362 if (auto *DebugObjSection
= getSection(Name
))
363 DebugObjSection
->setTargetMemoryRange(TargetMem
);
366 template <typename ELFT
>
367 Error
ELFDebugObject::recordSection(
368 StringRef Name
, std::unique_ptr
<ELFDebugObjectSection
<ELFT
>> Section
) {
369 if (Error Err
= Section
->validateInBounds(this->getBuffer(), Name
.data()))
371 auto ItInserted
= Sections
.try_emplace(Name
, std::move(Section
));
372 if (!ItInserted
.second
)
373 return make_error
<StringError
>("Duplicate section",
374 inconvertibleErrorCode());
375 return Error::success();
378 DebugObjectSection
*ELFDebugObject::getSection(StringRef Name
) {
379 auto It
= Sections
.find(Name
);
380 return It
== Sections
.end() ? nullptr : It
->second
.get();
383 /// Creates a debug object based on the input object file from
384 /// ObjectLinkingLayerJITLinkContext.
386 static Expected
<std::unique_ptr
<DebugObject
>>
387 createDebugObjectFromBuffer(ExecutionSession
&ES
, LinkGraph
&G
,
388 JITLinkContext
&Ctx
, MemoryBufferRef ObjBuffer
) {
389 switch (G
.getTargetTriple().getObjectFormat()) {
391 return ELFDebugObject::Create(ObjBuffer
, Ctx
, ES
);
394 // TODO: Once we add support for other formats, we might want to split this
395 // into multiple files.
400 DebugObjectManagerPlugin::DebugObjectManagerPlugin(
401 ExecutionSession
&ES
, std::unique_ptr
<DebugObjectRegistrar
> Target
)
402 : ES(ES
), Target(std::move(Target
)) {}
404 DebugObjectManagerPlugin::~DebugObjectManagerPlugin() = default;
406 void DebugObjectManagerPlugin::notifyMaterializing(
407 MaterializationResponsibility
&MR
, LinkGraph
&G
, JITLinkContext
&Ctx
,
408 MemoryBufferRef ObjBuffer
) {
409 std::lock_guard
<std::mutex
> Lock(PendingObjsLock
);
410 assert(PendingObjs
.count(&MR
) == 0 &&
411 "Cannot have more than one pending debug object per "
412 "MaterializationResponsibility");
414 if (auto DebugObj
= createDebugObjectFromBuffer(ES
, G
, Ctx
, ObjBuffer
)) {
415 // Not all link artifacts allow debugging.
416 if (*DebugObj
!= nullptr)
417 PendingObjs
[&MR
] = std::move(*DebugObj
);
419 ES
.reportError(DebugObj
.takeError());
423 void DebugObjectManagerPlugin::modifyPassConfig(
424 MaterializationResponsibility
&MR
, LinkGraph
&G
,
425 PassConfiguration
&PassConfig
) {
426 // Not all link artifacts have associated debug objects.
427 std::lock_guard
<std::mutex
> Lock(PendingObjsLock
);
428 auto It
= PendingObjs
.find(&MR
);
429 if (It
== PendingObjs
.end())
432 DebugObject
&DebugObj
= *It
->second
;
433 if (DebugObj
.has(Requirement::ReportFinalSectionLoadAddresses
)) {
434 PassConfig
.PostAllocationPasses
.push_back(
435 [&DebugObj
](LinkGraph
&Graph
) -> Error
{
436 for (const Section
&GraphSection
: Graph
.sections())
437 DebugObj
.reportSectionTargetMemoryRange(GraphSection
.getName(),
438 SectionRange(GraphSection
));
439 return Error::success();
444 Error
DebugObjectManagerPlugin::notifyEmitted(
445 MaterializationResponsibility
&MR
) {
446 std::lock_guard
<std::mutex
> Lock(PendingObjsLock
);
447 auto It
= PendingObjs
.find(&MR
);
448 if (It
== PendingObjs
.end())
449 return Error::success();
451 // During finalization the debug object is registered with the target.
452 // Materialization must wait for this process to finish. Otherwise we might
453 // start running code before the debugger processed the corresponding debug
455 std::promise
<MSVCPError
> FinalizePromise
;
456 std::future
<MSVCPError
> FinalizeErr
= FinalizePromise
.get_future();
458 It
->second
->finalizeAsync(
459 [this, &FinalizePromise
, &MR
](Expected
<ExecutorAddrRange
> TargetMem
) {
460 // Any failure here will fail materialization.
462 FinalizePromise
.set_value(TargetMem
.takeError());
465 if (Error Err
= Target
->registerDebugObject(*TargetMem
)) {
466 FinalizePromise
.set_value(std::move(Err
));
470 // Once our tracking info is updated, notifyEmitted() can return and
471 // finish materialization.
472 FinalizePromise
.set_value(MR
.withResourceKeyDo([&](ResourceKey K
) {
473 assert(PendingObjs
.count(&MR
) && "We still hold PendingObjsLock");
474 std::lock_guard
<std::mutex
> Lock(RegisteredObjsLock
);
475 RegisteredObjs
[K
].push_back(std::move(PendingObjs
[&MR
]));
476 PendingObjs
.erase(&MR
);
480 return FinalizeErr
.get();
483 Error
DebugObjectManagerPlugin::notifyFailed(
484 MaterializationResponsibility
&MR
) {
485 std::lock_guard
<std::mutex
> Lock(PendingObjsLock
);
486 PendingObjs
.erase(&MR
);
487 return Error::success();
490 void DebugObjectManagerPlugin::notifyTransferringResources(ResourceKey DstKey
,
491 ResourceKey SrcKey
) {
492 // Debug objects are stored by ResourceKey only after registration.
493 // Thus, pending objects don't need to be updated here.
494 std::lock_guard
<std::mutex
> Lock(RegisteredObjsLock
);
495 auto SrcIt
= RegisteredObjs
.find(SrcKey
);
496 if (SrcIt
!= RegisteredObjs
.end()) {
497 // Resources from distinct MaterializationResponsibilitys can get merged
498 // after emission, so we can have multiple debug objects per resource key.
499 for (std::unique_ptr
<DebugObject
> &DebugObj
: SrcIt
->second
)
500 RegisteredObjs
[DstKey
].push_back(std::move(DebugObj
));
501 RegisteredObjs
.erase(SrcIt
);
505 Error
DebugObjectManagerPlugin::notifyRemovingResources(ResourceKey Key
) {
506 // Removing the resource for a pending object fails materialization, so they
507 // get cleaned up in the notifyFailed() handler.
508 std::lock_guard
<std::mutex
> Lock(RegisteredObjsLock
);
509 RegisteredObjs
.erase(Key
);
511 // TODO: Implement unregister notifications.
512 return Error::success();