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/Object/ELFObjectFile.h"
23 #include "llvm/Support/Errc.h"
24 #include "llvm/Support/MSVCErrorWorkarounds.h"
25 #include "llvm/Support/MemoryBuffer.h"
26 #include "llvm/Support/Process.h"
27 #include "llvm/Support/raw_ostream.h"
31 #define DEBUG_TYPE "orc"
33 using namespace llvm::jitlink
;
34 using namespace llvm::object
;
39 class DebugObjectSection
{
41 virtual void setTargetMemoryRange(SectionRange Range
) = 0;
42 virtual void dump(raw_ostream
&OS
, StringRef Name
) {}
43 virtual ~DebugObjectSection() = default;
46 template <typename ELFT
>
47 class ELFDebugObjectSection
: public DebugObjectSection
{
49 // BinaryFormat ELF is not meant as a mutable format. We can only make changes
50 // that don't invalidate the file structure.
51 ELFDebugObjectSection(const typename
ELFT::Shdr
*Header
)
52 : Header(const_cast<typename
ELFT::Shdr
*>(Header
)) {}
54 void setTargetMemoryRange(SectionRange Range
) override
;
55 void dump(raw_ostream
&OS
, StringRef Name
) override
;
57 Error
validateInBounds(StringRef Buffer
, const char *Name
) const;
60 typename
ELFT::Shdr
*Header
;
63 template <typename ELFT
>
64 void ELFDebugObjectSection
<ELFT
>::setTargetMemoryRange(SectionRange Range
) {
65 // All recorded sections are candidates for load-address patching.
67 static_cast<typename
ELFT::uint
>(Range
.getStart().getValue());
70 template <typename ELFT
>
71 Error ELFDebugObjectSection
<ELFT
>::validateInBounds(StringRef Buffer
,
72 const char *Name
) const {
73 const uint8_t *Start
= Buffer
.bytes_begin();
74 const uint8_t *End
= Buffer
.bytes_end();
75 const uint8_t *HeaderPtr
= reinterpret_cast<uint8_t *>(Header
);
76 if (HeaderPtr
< Start
|| HeaderPtr
+ sizeof(typename
ELFT::Shdr
) > End
)
77 return make_error
<StringError
>(
78 formatv("{0} section header at {1:x16} not within bounds of the "
79 "given debug object buffer [{2:x16} - {3:x16}]",
80 Name
, &Header
->sh_addr
, Start
, End
),
81 inconvertibleErrorCode());
82 if (Header
->sh_offset
+ Header
->sh_size
> Buffer
.size())
83 return make_error
<StringError
>(
84 formatv("{0} section data [{1:x16} - {2:x16}] not within bounds of "
85 "the given debug object buffer [{3:x16} - {4:x16}]",
86 Name
, Start
+ Header
->sh_offset
,
87 Start
+ Header
->sh_offset
+ Header
->sh_size
, Start
, End
),
88 inconvertibleErrorCode());
89 return Error::success();
92 template <typename ELFT
>
93 void ELFDebugObjectSection
<ELFT
>::dump(raw_ostream
&OS
, StringRef Name
) {
94 if (uint64_t Addr
= Header
->sh_addr
) {
95 OS
<< formatv(" {0:x16} {1}\n", Addr
, Name
);
97 OS
<< formatv(" {0}\n", Name
);
101 enum DebugObjectFlags
: int {
102 // Request final target memory load-addresses for all sections.
103 ReportFinalSectionLoadAddresses
= 1 << 0,
105 // We found sections with debug information when processing the input object.
106 HasDebugSections
= 1 << 1,
109 /// The plugin creates a debug object from when JITLink starts processing the
110 /// corresponding LinkGraph. It provides access to the pass configuration of
111 /// the LinkGraph and calls the finalization function, once the resulting link
112 /// artifact was emitted.
116 DebugObject(JITLinkMemoryManager
&MemMgr
, const JITLinkDylib
*JD
,
117 ExecutionSession
&ES
)
118 : MemMgr(MemMgr
), JD(JD
), ES(ES
), Flags(DebugObjectFlags
{}) {}
120 bool hasFlags(DebugObjectFlags F
) const { return Flags
& F
; }
121 void setFlags(DebugObjectFlags F
) {
122 Flags
= static_cast<DebugObjectFlags
>(Flags
| F
);
124 void clearFlags(DebugObjectFlags F
) {
125 Flags
= static_cast<DebugObjectFlags
>(Flags
& ~F
);
128 using FinalizeContinuation
= std::function
<void(Expected
<ExecutorAddrRange
>)>;
130 void finalizeAsync(FinalizeContinuation OnFinalize
);
132 virtual ~DebugObject() {
134 std::vector
<FinalizedAlloc
> Allocs
;
135 Allocs
.push_back(std::move(Alloc
));
136 if (Error Err
= MemMgr
.deallocate(std::move(Allocs
)))
137 ES
.reportError(std::move(Err
));
141 virtual void reportSectionTargetMemoryRange(StringRef Name
,
142 SectionRange TargetMem
) {}
145 using InFlightAlloc
= JITLinkMemoryManager::InFlightAlloc
;
146 using FinalizedAlloc
= JITLinkMemoryManager::FinalizedAlloc
;
148 virtual Expected
<SimpleSegmentAlloc
> finalizeWorkingMemory() = 0;
150 JITLinkMemoryManager
&MemMgr
;
151 const JITLinkDylib
*JD
= nullptr;
152 ExecutionSession
&ES
;
155 DebugObjectFlags Flags
;
156 FinalizedAlloc Alloc
;
159 // Finalize working memory and take ownership of the resulting allocation. Start
160 // copying memory over to the target and pass on the result once we're done.
161 // Ownership of the allocation remains with us for the rest of our lifetime.
162 void DebugObject::finalizeAsync(FinalizeContinuation OnFinalize
) {
163 assert(!Alloc
&& "Cannot finalize more than once");
165 if (auto SimpleSegAlloc
= finalizeWorkingMemory()) {
166 auto ROSeg
= SimpleSegAlloc
->getSegInfo(MemProt::Read
);
167 ExecutorAddrRange
DebugObjRange(ROSeg
.Addr
, ROSeg
.WorkingMem
.size());
168 SimpleSegAlloc
->finalize(
169 [this, DebugObjRange
,
170 OnFinalize
= std::move(OnFinalize
)](Expected
<FinalizedAlloc
> FA
) {
172 Alloc
= std::move(*FA
);
173 OnFinalize(DebugObjRange
);
175 OnFinalize(FA
.takeError());
178 OnFinalize(SimpleSegAlloc
.takeError());
181 /// The current implementation of ELFDebugObject replicates the approach used in
182 /// RuntimeDyld: It patches executable and data section headers in the given
183 /// object buffer with load-addresses of their corresponding sections in target
186 class ELFDebugObject
: public DebugObject
{
188 static Expected
<std::unique_ptr
<DebugObject
>>
189 Create(MemoryBufferRef Buffer
, JITLinkContext
&Ctx
, ExecutionSession
&ES
);
191 void reportSectionTargetMemoryRange(StringRef Name
,
192 SectionRange TargetMem
) override
;
194 StringRef
getBuffer() const { return Buffer
->getMemBufferRef().getBuffer(); }
197 Expected
<SimpleSegmentAlloc
> finalizeWorkingMemory() override
;
199 template <typename ELFT
>
200 Error
recordSection(StringRef Name
,
201 std::unique_ptr
<ELFDebugObjectSection
<ELFT
>> Section
);
202 DebugObjectSection
*getSection(StringRef Name
);
205 template <typename ELFT
>
206 static Expected
<std::unique_ptr
<ELFDebugObject
>>
207 CreateArchType(MemoryBufferRef Buffer
, JITLinkMemoryManager
&MemMgr
,
208 const JITLinkDylib
*JD
, ExecutionSession
&ES
);
210 static std::unique_ptr
<WritableMemoryBuffer
>
211 CopyBuffer(MemoryBufferRef Buffer
, Error
&Err
);
213 ELFDebugObject(std::unique_ptr
<WritableMemoryBuffer
> Buffer
,
214 JITLinkMemoryManager
&MemMgr
, const JITLinkDylib
*JD
,
215 ExecutionSession
&ES
)
216 : DebugObject(MemMgr
, JD
, ES
), Buffer(std::move(Buffer
)) {
217 setFlags(ReportFinalSectionLoadAddresses
);
220 std::unique_ptr
<WritableMemoryBuffer
> Buffer
;
221 StringMap
<std::unique_ptr
<DebugObjectSection
>> Sections
;
224 static const std::set
<StringRef
> DwarfSectionNames
= {
225 #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION) \
227 #include "llvm/BinaryFormat/Dwarf.def"
228 #undef HANDLE_DWARF_SECTION
231 static bool isDwarfSection(StringRef SectionName
) {
232 return DwarfSectionNames
.count(SectionName
) == 1;
235 std::unique_ptr
<WritableMemoryBuffer
>
236 ELFDebugObject::CopyBuffer(MemoryBufferRef Buffer
, Error
&Err
) {
237 ErrorAsOutParameter
_(Err
);
238 size_t Size
= Buffer
.getBufferSize();
239 StringRef Name
= Buffer
.getBufferIdentifier();
240 if (auto Copy
= WritableMemoryBuffer::getNewUninitMemBuffer(Size
, Name
)) {
241 memcpy(Copy
->getBufferStart(), Buffer
.getBufferStart(), Size
);
245 Err
= errorCodeToError(make_error_code(errc::not_enough_memory
));
249 template <typename ELFT
>
250 Expected
<std::unique_ptr
<ELFDebugObject
>>
251 ELFDebugObject::CreateArchType(MemoryBufferRef Buffer
,
252 JITLinkMemoryManager
&MemMgr
,
253 const JITLinkDylib
*JD
, ExecutionSession
&ES
) {
254 using SectionHeader
= typename
ELFT::Shdr
;
256 Error Err
= Error::success();
257 std::unique_ptr
<ELFDebugObject
> DebugObj(
258 new ELFDebugObject(CopyBuffer(Buffer
, Err
), MemMgr
, JD
, ES
));
260 return std::move(Err
);
262 Expected
<ELFFile
<ELFT
>> ObjRef
= ELFFile
<ELFT
>::create(DebugObj
->getBuffer());
264 return ObjRef
.takeError();
266 Expected
<ArrayRef
<SectionHeader
>> Sections
= ObjRef
->sections();
268 return Sections
.takeError();
270 for (const SectionHeader
&Header
: *Sections
) {
271 Expected
<StringRef
> Name
= ObjRef
->getSectionName(Header
);
273 return Name
.takeError();
276 if (isDwarfSection(*Name
))
277 DebugObj
->setFlags(HasDebugSections
);
279 // Only record text and data sections (i.e. no bss, comments, rel, etc.)
280 if (Header
.sh_type
!= ELF::SHT_PROGBITS
&&
281 Header
.sh_type
!= ELF::SHT_X86_64_UNWIND
)
283 if (!(Header
.sh_flags
& ELF::SHF_ALLOC
))
286 auto Wrapped
= std::make_unique
<ELFDebugObjectSection
<ELFT
>>(&Header
);
287 if (Error Err
= DebugObj
->recordSection(*Name
, std::move(Wrapped
)))
288 return std::move(Err
);
291 return std::move(DebugObj
);
294 Expected
<std::unique_ptr
<DebugObject
>>
295 ELFDebugObject::Create(MemoryBufferRef Buffer
, JITLinkContext
&Ctx
,
296 ExecutionSession
&ES
) {
297 unsigned char Class
, Endian
;
298 std::tie(Class
, Endian
) = getElfArchType(Buffer
.getBuffer());
300 if (Class
== ELF::ELFCLASS32
) {
301 if (Endian
== ELF::ELFDATA2LSB
)
302 return CreateArchType
<ELF32LE
>(Buffer
, Ctx
.getMemoryManager(),
303 Ctx
.getJITLinkDylib(), ES
);
304 if (Endian
== ELF::ELFDATA2MSB
)
305 return CreateArchType
<ELF32BE
>(Buffer
, Ctx
.getMemoryManager(),
306 Ctx
.getJITLinkDylib(), ES
);
309 if (Class
== ELF::ELFCLASS64
) {
310 if (Endian
== ELF::ELFDATA2LSB
)
311 return CreateArchType
<ELF64LE
>(Buffer
, Ctx
.getMemoryManager(),
312 Ctx
.getJITLinkDylib(), ES
);
313 if (Endian
== ELF::ELFDATA2MSB
)
314 return CreateArchType
<ELF64BE
>(Buffer
, Ctx
.getMemoryManager(),
315 Ctx
.getJITLinkDylib(), ES
);
321 Expected
<SimpleSegmentAlloc
> ELFDebugObject::finalizeWorkingMemory() {
323 dbgs() << "Section load-addresses in debug object for \""
324 << Buffer
->getBufferIdentifier() << "\":\n";
325 for (const auto &KV
: Sections
)
326 KV
.second
->dump(dbgs(), KV
.first());
329 // TODO: This works, but what actual alignment requirements do we have?
330 unsigned PageSize
= sys::Process::getPageSizeEstimate();
331 size_t Size
= Buffer
->getBufferSize();
333 // Allocate working memory for debug object in read-only segment.
335 SimpleSegmentAlloc::Create(MemMgr
, ES
.getSymbolStringPool(), JD
,
336 {{MemProt::Read
, {Size
, Align(PageSize
)}}});
340 // Initialize working memory with a copy of our object buffer.
341 auto SegInfo
= Alloc
->getSegInfo(MemProt::Read
);
342 memcpy(SegInfo
.WorkingMem
.data(), Buffer
->getBufferStart(), Size
);
348 void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name
,
349 SectionRange TargetMem
) {
350 if (auto *DebugObjSection
= getSection(Name
))
351 DebugObjSection
->setTargetMemoryRange(TargetMem
);
354 template <typename ELFT
>
355 Error
ELFDebugObject::recordSection(
356 StringRef Name
, std::unique_ptr
<ELFDebugObjectSection
<ELFT
>> Section
) {
357 if (Error Err
= Section
->validateInBounds(this->getBuffer(), Name
.data()))
359 bool Inserted
= Sections
.try_emplace(Name
, std::move(Section
)).second
;
361 LLVM_DEBUG(dbgs() << "Skipping debug registration for section '" << Name
362 << "' in object " << Buffer
->getBufferIdentifier()
363 << " (duplicate name)\n");
364 return Error::success();
367 DebugObjectSection
*ELFDebugObject::getSection(StringRef Name
) {
368 auto It
= Sections
.find(Name
);
369 return It
== Sections
.end() ? nullptr : It
->second
.get();
372 /// Creates a debug object based on the input object file from
373 /// ObjectLinkingLayerJITLinkContext.
375 static Expected
<std::unique_ptr
<DebugObject
>>
376 createDebugObjectFromBuffer(ExecutionSession
&ES
, LinkGraph
&G
,
377 JITLinkContext
&Ctx
, MemoryBufferRef ObjBuffer
) {
378 switch (G
.getTargetTriple().getObjectFormat()) {
380 return ELFDebugObject::Create(ObjBuffer
, Ctx
, ES
);
383 // TODO: Once we add support for other formats, we might want to split this
384 // into multiple files.
389 DebugObjectManagerPlugin::DebugObjectManagerPlugin(
390 ExecutionSession
&ES
, std::unique_ptr
<DebugObjectRegistrar
> Target
,
391 bool RequireDebugSections
, bool AutoRegisterCode
)
392 : ES(ES
), Target(std::move(Target
)),
393 RequireDebugSections(RequireDebugSections
),
394 AutoRegisterCode(AutoRegisterCode
) {}
396 DebugObjectManagerPlugin::DebugObjectManagerPlugin(
397 ExecutionSession
&ES
, std::unique_ptr
<DebugObjectRegistrar
> Target
)
398 : DebugObjectManagerPlugin(ES
, std::move(Target
), true, true) {}
400 DebugObjectManagerPlugin::~DebugObjectManagerPlugin() = default;
402 void DebugObjectManagerPlugin::notifyMaterializing(
403 MaterializationResponsibility
&MR
, LinkGraph
&G
, JITLinkContext
&Ctx
,
404 MemoryBufferRef ObjBuffer
) {
405 std::lock_guard
<std::mutex
> Lock(PendingObjsLock
);
406 assert(PendingObjs
.count(&MR
) == 0 &&
407 "Cannot have more than one pending debug object per "
408 "MaterializationResponsibility");
410 if (auto DebugObj
= createDebugObjectFromBuffer(ES
, G
, Ctx
, ObjBuffer
)) {
411 // Not all link artifacts allow debugging.
412 if (*DebugObj
== nullptr)
414 if (RequireDebugSections
&& !(**DebugObj
).hasFlags(HasDebugSections
)) {
415 LLVM_DEBUG(dbgs() << "Skipping debug registration for LinkGraph '"
416 << G
.getName() << "': no debug info\n");
419 PendingObjs
[&MR
] = std::move(*DebugObj
);
421 ES
.reportError(DebugObj
.takeError());
425 void DebugObjectManagerPlugin::modifyPassConfig(
426 MaterializationResponsibility
&MR
, LinkGraph
&G
,
427 PassConfiguration
&PassConfig
) {
428 // Not all link artifacts have associated debug objects.
429 std::lock_guard
<std::mutex
> Lock(PendingObjsLock
);
430 auto It
= PendingObjs
.find(&MR
);
431 if (It
== PendingObjs
.end())
434 DebugObject
&DebugObj
= *It
->second
;
435 if (DebugObj
.hasFlags(ReportFinalSectionLoadAddresses
)) {
436 PassConfig
.PostAllocationPasses
.push_back(
437 [&DebugObj
](LinkGraph
&Graph
) -> Error
{
438 for (const Section
&GraphSection
: Graph
.sections())
439 DebugObj
.reportSectionTargetMemoryRange(GraphSection
.getName(),
440 SectionRange(GraphSection
));
441 return Error::success();
446 Error
DebugObjectManagerPlugin::notifyEmitted(
447 MaterializationResponsibility
&MR
) {
448 std::lock_guard
<std::mutex
> Lock(PendingObjsLock
);
449 auto It
= PendingObjs
.find(&MR
);
450 if (It
== PendingObjs
.end())
451 return Error::success();
453 // During finalization the debug object is registered with the target.
454 // Materialization must wait for this process to finish. Otherwise we might
455 // start running code before the debugger processed the corresponding debug
457 std::promise
<MSVCPError
> FinalizePromise
;
458 std::future
<MSVCPError
> FinalizeErr
= FinalizePromise
.get_future();
460 It
->second
->finalizeAsync(
461 [this, &FinalizePromise
, &MR
](Expected
<ExecutorAddrRange
> TargetMem
) {
462 // Any failure here will fail materialization.
464 FinalizePromise
.set_value(TargetMem
.takeError());
468 Target
->registerDebugObject(*TargetMem
, AutoRegisterCode
)) {
469 FinalizePromise
.set_value(std::move(Err
));
473 // Once our tracking info is updated, notifyEmitted() can return and
474 // finish materialization.
475 FinalizePromise
.set_value(MR
.withResourceKeyDo([&](ResourceKey K
) {
476 assert(PendingObjs
.count(&MR
) && "We still hold PendingObjsLock");
477 std::lock_guard
<std::mutex
> Lock(RegisteredObjsLock
);
478 RegisteredObjs
[K
].push_back(std::move(PendingObjs
[&MR
]));
479 PendingObjs
.erase(&MR
);
483 return FinalizeErr
.get();
486 Error
DebugObjectManagerPlugin::notifyFailed(
487 MaterializationResponsibility
&MR
) {
488 std::lock_guard
<std::mutex
> Lock(PendingObjsLock
);
489 PendingObjs
.erase(&MR
);
490 return Error::success();
493 void DebugObjectManagerPlugin::notifyTransferringResources(JITDylib
&JD
,
495 ResourceKey SrcKey
) {
496 // Debug objects are stored by ResourceKey only after registration.
497 // Thus, pending objects don't need to be updated here.
498 std::lock_guard
<std::mutex
> Lock(RegisteredObjsLock
);
499 auto SrcIt
= RegisteredObjs
.find(SrcKey
);
500 if (SrcIt
!= RegisteredObjs
.end()) {
501 // Resources from distinct MaterializationResponsibilitys can get merged
502 // after emission, so we can have multiple debug objects per resource key.
503 for (std::unique_ptr
<DebugObject
> &DebugObj
: SrcIt
->second
)
504 RegisteredObjs
[DstKey
].push_back(std::move(DebugObj
));
505 RegisteredObjs
.erase(SrcIt
);
509 Error
DebugObjectManagerPlugin::notifyRemovingResources(JITDylib
&JD
,
511 // Removing the resource for a pending object fails materialization, so they
512 // get cleaned up in the notifyFailed() handler.
513 std::lock_guard
<std::mutex
> Lock(RegisteredObjsLock
);
514 RegisteredObjs
.erase(Key
);
516 // TODO: Implement unregister notifications.
517 return Error::success();