1919#include " llvm/BinaryFormat/ELF.h"
2020#include " llvm/ExecutionEngine/JITLink/JITLinkDylib.h"
2121#include " llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
22+ #include " llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
2223#include " llvm/Object/ELFObjectFile.h"
2324#include " llvm/Support/Errc.h"
2425#include " llvm/Support/MSVCErrorWorkarounds.h"
@@ -115,7 +116,9 @@ class DebugObject {
115116public:
116117 DebugObject (JITLinkMemoryManager &MemMgr, const JITLinkDylib *JD,
117118 ExecutionSession &ES)
118- : MemMgr(MemMgr), JD(JD), ES(ES), Flags(DebugObjectFlags{}) {}
119+ : MemMgr(MemMgr), JD(JD), ES(ES), Flags(DebugObjectFlags{}) {
120+ FinalizeFuture = FinalizePromise.get_future ();
121+ }
119122
120123 bool hasFlags (DebugObjectFlags F) const { return Flags & F; }
121124 void setFlags (DebugObjectFlags F) {
@@ -126,8 +129,17 @@ class DebugObject {
126129 }
127130
128131 using FinalizeContinuation = std::function<void (Expected<ExecutorAddrRange>)>;
132+ void finalizeAsync (FinalizeContinuation OnAsync);
133+
134+ void failMaterialization (Error Err) {
135+ FinalizePromise.set_value (std::move (Err));
136+ }
129137
130- void finalizeAsync (FinalizeContinuation OnFinalize);
138+ void reportTargetMem (ExecutorAddrRange TargetMem) {
139+ FinalizePromise.set_value (TargetMem);
140+ }
141+
142+ Expected<ExecutorAddrRange> awaitTargetMem () { return FinalizeFuture.get (); }
131143
132144 virtual ~DebugObject () {
133145 if (Alloc) {
@@ -151,6 +163,9 @@ class DebugObject {
151163 const JITLinkDylib *JD = nullptr ;
152164 ExecutionSession &ES;
153165
166+ std::promise<MSVCPExpected<ExecutorAddrRange>> FinalizePromise;
167+ std::future<MSVCPExpected<ExecutorAddrRange>> FinalizeFuture;
168+
154169private:
155170 DebugObjectFlags Flags;
156171 FinalizedAlloc Alloc;
@@ -160,22 +175,27 @@ class DebugObject {
160175// copying memory over to the target and pass on the result once we're done.
161176// Ownership of the allocation remains with us for the rest of our lifetime.
162177void DebugObject::finalizeAsync (FinalizeContinuation OnFinalize) {
163- assert (!Alloc && " Cannot finalize more than once" );
164-
178+ assert (!this ->Alloc && " Cannot finalize more than once" );
165179 if (auto SimpleSegAlloc = finalizeWorkingMemory ()) {
166180 auto ROSeg = SimpleSegAlloc->getSegInfo (MemProt::Read);
167181 ExecutorAddrRange DebugObjRange (ROSeg.Addr , ROSeg.WorkingMem .size ());
168182 SimpleSegAlloc->finalize (
169183 [this , DebugObjRange,
170184 OnFinalize = std::move (OnFinalize)](Expected<FinalizedAlloc> FA) {
171185 if (FA) {
172- Alloc = std::move (*FA);
186+ // Note: FA->getAddress() is supposed to be the address of the
187+ // memory range on the target, but InProcessMemoryManager returns
188+ // the address of a FinalizedAllocInfo helper instead.
189+ this ->Alloc = std::move (*FA);
173190 OnFinalize (DebugObjRange);
174191 } else
175192 OnFinalize (FA.takeError ());
176193 });
177- } else
194+ } else {
195+ // We could report this error synchronously, but it's easier this way,
196+ // because the FinalizePromise will be triggered unconditionally.
178197 OnFinalize (SimpleSegAlloc.takeError ());
198+ }
179199}
180200
181201// / The current implementation of ELFDebugObject replicates the approach used in
@@ -386,16 +406,17 @@ createDebugObjectFromBuffer(ExecutionSession &ES, LinkGraph &G,
386406 }
387407}
388408
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) {}
395-
396- DebugObjectManagerPlugin::DebugObjectManagerPlugin (
397- ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target)
398- : DebugObjectManagerPlugin(ES, std::move(Target), true, true) {}
409+ DebugObjectManagerPlugin::DebugObjectManagerPlugin (ExecutionSession &ES,
410+ bool RequireDebugSections,
411+ bool AutoRegisterCode,
412+ Error &Err)
413+ : ES(ES), RequireDebugSections(RequireDebugSections),
414+ AutoRegisterCode (AutoRegisterCode) {
415+ // Pass bootstrap symbol for registration function to enable debugging
416+ ErrorAsOutParameter _ (&Err);
417+ Err = ES.getExecutorProcessControl ().getBootstrapSymbols (
418+ {{RegistrationAction, rt::RegisterJITLoaderGDBAllocActionName}});
419+ }
399420
400421DebugObjectManagerPlugin::~DebugObjectManagerPlugin () = default ;
401422
@@ -440,48 +461,50 @@ void DebugObjectManagerPlugin::modifyPassConfig(
440461 SectionRange (GraphSection));
441462 return Error::success ();
442463 });
443- }
444- }
445464
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 ();
452-
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
456- // info.
457- std::promise<MSVCPError> FinalizePromise;
458- std::future<MSVCPError> FinalizeErr = FinalizePromise.get_future ();
459-
460- It->second ->finalizeAsync (
461- [this , &FinalizePromise, &MR](Expected<ExecutorAddrRange> TargetMem) {
462- // Any failure here will fail materialization.
463- if (!TargetMem) {
464- FinalizePromise.set_value (TargetMem.takeError ());
465- return ;
466- }
467- if (Error Err =
468- Target->registerDebugObject (*TargetMem, AutoRegisterCode)) {
469- FinalizePromise.set_value (std::move (Err));
470- return ;
471- }
472-
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- auto It = PendingObjs.find (&MR);
479- RegisteredObjs[K].push_back (std::move (It->second ));
480- PendingObjs.erase (It);
481- }));
482- });
483-
484- return FinalizeErr.get ();
465+ PassConfig.PreFixupPasses .push_back (
466+ [this , &DebugObj, &MR](LinkGraph &G) -> Error {
467+ DebugObj.finalizeAsync ([this , &DebugObj,
468+ &MR](Expected<ExecutorAddrRange> TargetMem) {
469+ if (!TargetMem) {
470+ DebugObj.failMaterialization (TargetMem.takeError ());
471+ return ;
472+ }
473+ // Update tracking info
474+ Error Err = MR.withResourceKeyDo ([&](ResourceKey K) {
475+ std::lock_guard<std::mutex> LockPending (PendingObjsLock);
476+ std::lock_guard<std::mutex> LockRegistered (RegisteredObjsLock);
477+ auto It = PendingObjs.find (&MR);
478+ RegisteredObjs[K].push_back (std::move (It->second ));
479+ PendingObjs.erase (It);
480+ });
481+
482+ if (Err)
483+ DebugObj.failMaterialization (std::move (Err));
484+
485+ // Unblock post-fixup pass
486+ DebugObj.reportTargetMem (*TargetMem);
487+ });
488+ return Error::success ();
489+ });
490+
491+ PassConfig.PostFixupPasses .push_back (
492+ [this , &DebugObj](LinkGraph &G) -> Error {
493+ Expected<ExecutorAddrRange> R = DebugObj.awaitTargetMem ();
494+ if (!R)
495+ return R.takeError ();
496+ if (R->empty ())
497+ return Error::success ();
498+
499+ using namespace shared ;
500+ G.allocActions ().push_back (
501+ {cantFail (WrapperFunctionCall::Create<
502+ SPSArgList<SPSExecutorAddrRange, bool >>(
503+ RegistrationAction, *R, AutoRegisterCode)),
504+ {/* no deregistration */ }});
505+ return Error::success ();
506+ });
507+ }
485508}
486509
487510Error DebugObjectManagerPlugin::notifyFailed (
0 commit comments