1 //===---- DebugObjectManagerPlugin.h - JITLink debug objects ---*- C++ -*-===//
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 #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
11 #include "llvm/ADT/ArrayRef.h"
12 #include "llvm/ADT/StringMap.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/BinaryFormat/ELF.h"
15 #include "llvm/ExecutionEngine/JITLink/JITLinkDylib.h"
16 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
17 #include "llvm/ExecutionEngine/JITSymbol.h"
18 #include "llvm/Object/ELFObjectFile.h"
19 #include "llvm/Object/ObjectFile.h"
20 #include "llvm/Support/Errc.h"
21 #include "llvm/Support/MSVCErrorWorkarounds.h"
22 #include "llvm/Support/MemoryBuffer.h"
23 #include "llvm/Support/Process.h"
24 #include "llvm/Support/raw_ostream.h"
28 #define DEBUG_TYPE "orc"
30 using namespace llvm::jitlink
;
31 using namespace llvm::object
;
36 class DebugObjectSection
{
38 virtual void setTargetMemoryRange(SectionRange Range
) = 0;
39 virtual void dump(raw_ostream
&OS
, StringRef Name
) {}
40 virtual ~DebugObjectSection() {}
43 template <typename ELFT
>
44 class ELFDebugObjectSection
: public DebugObjectSection
{
46 // BinaryFormat ELF is not meant as a mutable format. We can only make changes
47 // that don't invalidate the file structure.
48 ELFDebugObjectSection(const typename
ELFT::Shdr
*Header
)
49 : Header(const_cast<typename
ELFT::Shdr
*>(Header
)) {}
51 void setTargetMemoryRange(SectionRange Range
) override
;
52 void dump(raw_ostream
&OS
, StringRef Name
) override
;
54 Error
validateInBounds(StringRef Buffer
, const char *Name
) const;
57 typename
ELFT::Shdr
*Header
;
59 bool isTextOrDataSection() const;
62 template <typename ELFT
>
63 void ELFDebugObjectSection
<ELFT
>::setTargetMemoryRange(SectionRange Range
) {
64 // Only patch load-addresses for executable and data sections.
65 if (isTextOrDataSection()) {
66 Header
->sh_addr
= static_cast<typename
ELFT::uint
>(Range
.getStart());
70 template <typename ELFT
>
71 bool ELFDebugObjectSection
<ELFT
>::isTextOrDataSection() const {
72 switch (Header
->sh_type
) {
73 case ELF::SHT_PROGBITS
:
74 case ELF::SHT_X86_64_UNWIND
:
75 return Header
->sh_flags
& (ELF::SHF_EXECINSTR
| ELF::SHF_ALLOC
);
80 template <typename ELFT
>
81 Error ELFDebugObjectSection
<ELFT
>::validateInBounds(StringRef Buffer
,
82 const char *Name
) const {
83 const uint8_t *Start
= Buffer
.bytes_begin();
84 const uint8_t *End
= Buffer
.bytes_end();
85 const uint8_t *HeaderPtr
= reinterpret_cast<uint8_t *>(Header
);
86 if (HeaderPtr
< Start
|| HeaderPtr
+ sizeof(typename
ELFT::Shdr
) > End
)
87 return make_error
<StringError
>(
88 formatv("{0} section header at {1:x16} not within bounds of the "
89 "given debug object buffer [{2:x16} - {3:x16}]",
90 Name
, &Header
->sh_addr
, Start
, End
),
91 inconvertibleErrorCode());
92 if (Header
->sh_offset
+ Header
->sh_size
> Buffer
.size())
93 return make_error
<StringError
>(
94 formatv("{0} section data [{1:x16} - {2:x16}] not within bounds of "
95 "the given debug object buffer [{3:x16} - {4:x16}]",
96 Name
, Start
+ Header
->sh_offset
,
97 Start
+ Header
->sh_offset
+ Header
->sh_size
, Start
, End
),
98 inconvertibleErrorCode());
99 return Error::success();
102 template <typename ELFT
>
103 void ELFDebugObjectSection
<ELFT
>::dump(raw_ostream
&OS
, StringRef Name
) {
104 if (auto Addr
= static_cast<JITTargetAddress
>(Header
->sh_addr
)) {
105 OS
<< formatv(" {0:x16} {1}\n", Addr
, Name
);
107 OS
<< formatv(" {0}\n", Name
);
111 static constexpr sys::Memory::ProtectionFlags ReadOnly
=
112 static_cast<sys::Memory::ProtectionFlags
>(sys::Memory::MF_READ
);
114 enum class Requirement
{
115 // Request final target memory load-addresses for all sections.
116 ReportFinalSectionLoadAddresses
,
119 /// The plugin creates a debug object from JITLinkContext when JITLink starts
120 /// processing the corresponding LinkGraph. It provides access to the pass
121 /// configuration of the LinkGraph and calls the finalization function, once
122 /// the resulting link artifact was emitted.
126 DebugObject(JITLinkContext
&Ctx
, ExecutionSession
&ES
) : Ctx(Ctx
), ES(ES
) {}
128 void set(Requirement Req
) { Reqs
.insert(Req
); }
129 bool has(Requirement Req
) const { return Reqs
.count(Req
) > 0; }
131 using FinalizeContinuation
= std::function
<void(Expected
<sys::MemoryBlock
>)>;
132 void finalizeAsync(FinalizeContinuation OnFinalize
);
134 virtual ~DebugObject() {
136 if (Error Err
= Alloc
->deallocate())
137 ES
.reportError(std::move(Err
));
140 virtual void reportSectionTargetMemoryRange(StringRef Name
,
141 SectionRange TargetMem
) {}
144 using Allocation
= JITLinkMemoryManager::Allocation
;
146 virtual Expected
<std::unique_ptr
<Allocation
>>
147 finalizeWorkingMemory(JITLinkContext
&Ctx
) = 0;
151 ExecutionSession
&ES
;
152 std::set
<Requirement
> Reqs
;
153 std::unique_ptr
<Allocation
> Alloc
{nullptr};
156 // Finalize working memory and take ownership of the resulting allocation. Start
157 // copying memory over to the target and pass on the result once we're done.
158 // Ownership of the allocation remains with us for the rest of our lifetime.
159 void DebugObject::finalizeAsync(FinalizeContinuation OnFinalize
) {
160 assert(Alloc
== nullptr && "Cannot finalize more than once");
162 auto AllocOrErr
= finalizeWorkingMemory(Ctx
);
164 OnFinalize(AllocOrErr
.takeError());
165 Alloc
= std::move(*AllocOrErr
);
167 Alloc
->finalizeAsync([this, OnFinalize
](Error Err
) {
169 OnFinalize(std::move(Err
));
171 OnFinalize(sys::MemoryBlock(
172 jitTargetAddressToPointer
<void *>(Alloc
->getTargetMemory(ReadOnly
)),
173 Alloc
->getWorkingMemory(ReadOnly
).size()));
177 /// The current implementation of ELFDebugObject replicates the approach used in
178 /// RuntimeDyld: It patches executable and data section headers in the given
179 /// object buffer with load-addresses of their corresponding sections in target
182 class ELFDebugObject
: public DebugObject
{
184 static Expected
<std::unique_ptr
<DebugObject
>>
185 Create(MemoryBufferRef Buffer
, JITLinkContext
&Ctx
, ExecutionSession
&ES
);
187 void reportSectionTargetMemoryRange(StringRef Name
,
188 SectionRange TargetMem
) override
;
190 StringRef
getBuffer() const { return Buffer
->getMemBufferRef().getBuffer(); }
193 Expected
<std::unique_ptr
<Allocation
>>
194 finalizeWorkingMemory(JITLinkContext
&Ctx
) override
;
196 template <typename ELFT
>
197 Error
recordSection(StringRef Name
,
198 std::unique_ptr
<ELFDebugObjectSection
<ELFT
>> Section
);
199 DebugObjectSection
*getSection(StringRef Name
);
202 template <typename ELFT
>
203 static Expected
<std::unique_ptr
<ELFDebugObject
>>
204 CreateArchType(MemoryBufferRef Buffer
, JITLinkContext
&Ctx
,
205 ExecutionSession
&ES
);
207 static std::unique_ptr
<WritableMemoryBuffer
>
208 CopyBuffer(MemoryBufferRef Buffer
, Error
&Err
);
210 ELFDebugObject(std::unique_ptr
<WritableMemoryBuffer
> Buffer
,
211 JITLinkContext
&Ctx
, ExecutionSession
&ES
)
212 : DebugObject(Ctx
, ES
), Buffer(std::move(Buffer
)) {
213 set(Requirement::ReportFinalSectionLoadAddresses
);
216 std::unique_ptr
<WritableMemoryBuffer
> Buffer
;
217 StringMap
<std::unique_ptr
<DebugObjectSection
>> Sections
;
220 static const std::set
<StringRef
> DwarfSectionNames
= {
221 #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION) \
223 #include "llvm/BinaryFormat/Dwarf.def"
224 #undef HANDLE_DWARF_SECTION
227 static bool isDwarfSection(StringRef SectionName
) {
228 return DwarfSectionNames
.count(SectionName
) == 1;
231 std::unique_ptr
<WritableMemoryBuffer
>
232 ELFDebugObject::CopyBuffer(MemoryBufferRef Buffer
, Error
&Err
) {
233 ErrorAsOutParameter
_(&Err
);
234 size_t Size
= Buffer
.getBufferSize();
235 StringRef Name
= Buffer
.getBufferIdentifier();
236 if (auto Copy
= WritableMemoryBuffer::getNewUninitMemBuffer(Size
, Name
)) {
237 memcpy(Copy
->getBufferStart(), Buffer
.getBufferStart(), Size
);
241 Err
= errorCodeToError(make_error_code(errc::not_enough_memory
));
245 template <typename ELFT
>
246 Expected
<std::unique_ptr
<ELFDebugObject
>>
247 ELFDebugObject::CreateArchType(MemoryBufferRef Buffer
, JITLinkContext
&Ctx
,
248 ExecutionSession
&ES
) {
249 using SectionHeader
= typename
ELFT::Shdr
;
251 Error Err
= Error::success();
252 std::unique_ptr
<ELFDebugObject
> DebugObj(
253 new ELFDebugObject(CopyBuffer(Buffer
, Err
), Ctx
, ES
));
255 return std::move(Err
);
257 Expected
<ELFFile
<ELFT
>> ObjRef
= ELFFile
<ELFT
>::create(DebugObj
->getBuffer());
259 return ObjRef
.takeError();
261 // TODO: Add support for other architectures.
262 uint16_t TargetMachineArch
= ObjRef
->getHeader().e_machine
;
263 if (TargetMachineArch
!= ELF::EM_X86_64
)
266 Expected
<ArrayRef
<SectionHeader
>> Sections
= ObjRef
->sections();
268 return Sections
.takeError();
270 bool HasDwarfSection
= false;
271 for (const SectionHeader
&Header
: *Sections
) {
272 Expected
<StringRef
> Name
= ObjRef
->getSectionName(Header
);
274 return Name
.takeError();
277 HasDwarfSection
|= isDwarfSection(*Name
);
279 auto Wrapped
= std::make_unique
<ELFDebugObjectSection
<ELFT
>>(&Header
);
280 if (Error Err
= DebugObj
->recordSection(*Name
, std::move(Wrapped
)))
281 return std::move(Err
);
284 if (!HasDwarfSection
) {
285 LLVM_DEBUG(dbgs() << "Aborting debug registration for LinkGraph \""
286 << DebugObj
->Buffer
->getBufferIdentifier()
287 << "\": input object contains no debug info\n");
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
, ES
);
303 if (Endian
== ELF::ELFDATA2MSB
)
304 return CreateArchType
<ELF32BE
>(Buffer
, Ctx
, ES
);
307 if (Class
== ELF::ELFCLASS64
) {
308 if (Endian
== ELF::ELFDATA2LSB
)
309 return CreateArchType
<ELF64LE
>(Buffer
, Ctx
, ES
);
310 if (Endian
== ELF::ELFDATA2MSB
)
311 return CreateArchType
<ELF64BE
>(Buffer
, Ctx
, ES
);
317 Expected
<std::unique_ptr
<DebugObject::Allocation
>>
318 ELFDebugObject::finalizeWorkingMemory(JITLinkContext
&Ctx
) {
320 dbgs() << "Section load-addresses in debug object for \""
321 << Buffer
->getBufferIdentifier() << "\":\n";
322 for (const auto &KV
: Sections
)
323 KV
.second
->dump(dbgs(), KV
.first());
326 // TODO: This works, but what actual alignment requirements do we have?
327 unsigned Alignment
= sys::Process::getPageSizeEstimate();
328 JITLinkMemoryManager
&MemMgr
= Ctx
.getMemoryManager();
329 const JITLinkDylib
*JD
= Ctx
.getJITLinkDylib();
330 size_t Size
= Buffer
->getBufferSize();
332 // Allocate working memory for debug object in read-only segment.
333 JITLinkMemoryManager::SegmentsRequestMap SingleReadOnlySegment
;
334 SingleReadOnlySegment
[ReadOnly
] =
335 JITLinkMemoryManager::SegmentRequest(Alignment
, Size
, 0);
337 auto AllocOrErr
= MemMgr
.allocate(JD
, SingleReadOnlySegment
);
339 return AllocOrErr
.takeError();
341 // Initialize working memory with a copy of our object buffer.
342 // TODO: Use our buffer as working memory directly.
343 std::unique_ptr
<Allocation
> Alloc
= std::move(*AllocOrErr
);
344 MutableArrayRef
<char> WorkingMem
= Alloc
->getWorkingMemory(ReadOnly
);
345 memcpy(WorkingMem
.data(), Buffer
->getBufferStart(), Size
);
348 return std::move(Alloc
);
351 void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name
,
352 SectionRange TargetMem
) {
353 if (auto *DebugObjSection
= getSection(Name
))
354 DebugObjSection
->setTargetMemoryRange(TargetMem
);
357 template <typename ELFT
>
358 Error
ELFDebugObject::recordSection(
359 StringRef Name
, std::unique_ptr
<ELFDebugObjectSection
<ELFT
>> Section
) {
360 if (Error Err
= Section
->validateInBounds(this->getBuffer(), Name
.data()))
362 auto ItInserted
= Sections
.try_emplace(Name
, std::move(Section
));
363 if (!ItInserted
.second
)
364 return make_error
<StringError
>("Duplicate section",
365 inconvertibleErrorCode());
366 return Error::success();
369 DebugObjectSection
*ELFDebugObject::getSection(StringRef Name
) {
370 auto It
= Sections
.find(Name
);
371 return It
== Sections
.end() ? nullptr : It
->second
.get();
374 /// Creates a debug object based on the input object file from
375 /// ObjectLinkingLayerJITLinkContext.
377 static Expected
<std::unique_ptr
<DebugObject
>>
378 createDebugObjectFromBuffer(ExecutionSession
&ES
, LinkGraph
&G
,
379 JITLinkContext
&Ctx
, MemoryBufferRef ObjBuffer
) {
380 switch (G
.getTargetTriple().getObjectFormat()) {
382 return ELFDebugObject::Create(ObjBuffer
, Ctx
, ES
);
385 // TODO: Once we add support for other formats, we might want to split this
386 // into multiple files.
391 DebugObjectManagerPlugin::DebugObjectManagerPlugin(
392 ExecutionSession
&ES
, std::unique_ptr
<DebugObjectRegistrar
> Target
)
393 : ES(ES
), Target(std::move(Target
)) {}
395 DebugObjectManagerPlugin::~DebugObjectManagerPlugin() = default;
397 void DebugObjectManagerPlugin::notifyMaterializing(
398 MaterializationResponsibility
&MR
, LinkGraph
&G
, JITLinkContext
&Ctx
,
399 MemoryBufferRef ObjBuffer
) {
400 std::lock_guard
<std::mutex
> Lock(PendingObjsLock
);
401 assert(PendingObjs
.count(&MR
) == 0 &&
402 "Cannot have more than one pending debug object per "
403 "MaterializationResponsibility");
405 if (auto DebugObj
= createDebugObjectFromBuffer(ES
, G
, Ctx
, ObjBuffer
)) {
406 // Not all link artifacts allow debugging.
407 if (*DebugObj
!= nullptr)
408 PendingObjs
[&MR
] = std::move(*DebugObj
);
410 ES
.reportError(DebugObj
.takeError());
414 void DebugObjectManagerPlugin::modifyPassConfig(
415 MaterializationResponsibility
&MR
, LinkGraph
&G
,
416 PassConfiguration
&PassConfig
) {
417 // Not all link artifacts have associated debug objects.
418 std::lock_guard
<std::mutex
> Lock(PendingObjsLock
);
419 auto It
= PendingObjs
.find(&MR
);
420 if (It
== PendingObjs
.end())
423 DebugObject
&DebugObj
= *It
->second
;
424 if (DebugObj
.has(Requirement::ReportFinalSectionLoadAddresses
)) {
425 PassConfig
.PostAllocationPasses
.push_back(
426 [&DebugObj
](LinkGraph
&Graph
) -> Error
{
427 for (const Section
&GraphSection
: Graph
.sections())
428 DebugObj
.reportSectionTargetMemoryRange(GraphSection
.getName(),
429 SectionRange(GraphSection
));
430 return Error::success();
435 Error
DebugObjectManagerPlugin::notifyEmitted(
436 MaterializationResponsibility
&MR
) {
437 std::lock_guard
<std::mutex
> Lock(PendingObjsLock
);
438 auto It
= PendingObjs
.find(&MR
);
439 if (It
== PendingObjs
.end())
440 return Error::success();
442 // During finalization the debug object is registered with the target.
443 // Materialization must wait for this process to finish. Otherwise we might
444 // start running code before the debugger processed the corresponding debug
446 std::promise
<MSVCPError
> FinalizePromise
;
447 std::future
<MSVCPError
> FinalizeErr
= FinalizePromise
.get_future();
449 It
->second
->finalizeAsync(
450 [this, &FinalizePromise
, &MR
](Expected
<sys::MemoryBlock
> TargetMem
) {
451 // Any failure here will fail materialization.
453 FinalizePromise
.set_value(TargetMem
.takeError());
456 if (Error Err
= Target
->registerDebugObject(*TargetMem
)) {
457 FinalizePromise
.set_value(std::move(Err
));
461 // Once our tracking info is updated, notifyEmitted() can return and
462 // finish materialization.
463 FinalizePromise
.set_value(MR
.withResourceKeyDo([&](ResourceKey K
) {
464 assert(PendingObjs
.count(&MR
) && "We still hold PendingObjsLock");
465 std::lock_guard
<std::mutex
> Lock(RegisteredObjsLock
);
466 RegisteredObjs
[K
].push_back(std::move(PendingObjs
[&MR
]));
467 PendingObjs
.erase(&MR
);
471 return FinalizeErr
.get();
474 Error
DebugObjectManagerPlugin::notifyFailed(
475 MaterializationResponsibility
&MR
) {
476 std::lock_guard
<std::mutex
> Lock(PendingObjsLock
);
477 PendingObjs
.erase(&MR
);
478 return Error::success();
481 void DebugObjectManagerPlugin::notifyTransferringResources(ResourceKey DstKey
,
482 ResourceKey SrcKey
) {
483 // Debug objects are stored by ResourceKey only after registration.
484 // Thus, pending objects don't need to be updated here.
485 std::lock_guard
<std::mutex
> Lock(RegisteredObjsLock
);
486 auto SrcIt
= RegisteredObjs
.find(SrcKey
);
487 if (SrcIt
!= RegisteredObjs
.end()) {
488 // Resources from distinct MaterializationResponsibilitys can get merged
489 // after emission, so we can have multiple debug objects per resource key.
490 for (std::unique_ptr
<DebugObject
> &DebugObj
: SrcIt
->second
)
491 RegisteredObjs
[DstKey
].push_back(std::move(DebugObj
));
492 RegisteredObjs
.erase(SrcIt
);
496 Error
DebugObjectManagerPlugin::notifyRemovingResources(ResourceKey Key
) {
497 // Removing the resource for a pending object fails materialization, so they
498 // get cleaned up in the notifyFailed() handler.
499 std::lock_guard
<std::mutex
> Lock(RegisteredObjsLock
);
500 RegisteredObjs
.erase(Key
);
502 // TODO: Implement unregister notifications.
503 return Error::success();