@@ -99,10 +99,6 @@ static bool IsModuleSwiftRuntime(lldb_private::Process &process,
9999 return module .GetFileSpec ().GetFilename () == GetStandardLibraryName (process);
100100}
101101
102- static UnwindPlanSP
103- GetFollowAsyncContextUnwindPlan (RegisterContext *regctx, ArchSpec &arch,
104- bool &behaves_like_zeroth_frame);
105-
106102AppleObjCRuntimeV2 *
107103SwiftLanguageRuntime::GetObjCRuntime (lldb_private::Process &process) {
108104 if (auto objc_runtime = ObjCLanguageRuntime::Get (process)) {
@@ -2608,7 +2604,7 @@ SwiftLanguageRuntime::GetRuntimeUnwindPlan(ProcessSP process_sp,
26082604 addr_t fp = regctx->GetFP (LLDB_INVALID_ADDRESS);
26092605 if (fp == LLDB_INVALID_ADDRESS) {
26102606 if (GetAsyncContext (regctx) != LLDB_INVALID_ADDRESS)
2611- return GetFollowAsyncContextUnwindPlan (regctx, arch,
2607+ return GetFollowAsyncContextUnwindPlan (process_sp, regctx, arch,
26122608 behaves_like_zeroth_frame);
26132609 return UnwindPlanSP ();
26142610 }
@@ -2749,9 +2745,31 @@ SwiftLanguageRuntime::GetRuntimeUnwindPlan(ProcessSP process_sp,
27492745 regnums->dummy_regnum , g_dummy_dwarf_expression,
27502746 sizeof (g_dummy_dwarf_expression), false );
27512747 }
2752- row->SetRegisterLocationToAtCFAPlusOffset (regnums->pc_regnum , ptr_size,
2753- false );
27542748
2749+ std::optional<addr_t > pc_after_prologue = [&]() -> std::optional<addr_t > {
2750+ // In the prologue, use the async_reg as is, it has not been clobbered.
2751+ if (in_prologue)
2752+ return TrySkipVirtualParentProlog (GetAsyncContext (regctx), *process_sp,
2753+ indirect_context);
2754+
2755+ // Both ABIs (x86_64 and aarch64) guarantee the async reg is saved at:
2756+ // *(fp - 8).
2757+ Status error;
2758+ addr_t async_reg_entry_value = LLDB_INVALID_ADDRESS;
2759+ process_sp->ReadMemory (fp - ptr_size, &async_reg_entry_value, ptr_size,
2760+ error);
2761+ if (error.Fail ())
2762+ return {};
2763+ return TrySkipVirtualParentProlog (async_reg_entry_value, *process_sp,
2764+ indirect_context);
2765+ }();
2766+
2767+ if (pc_after_prologue)
2768+ row->SetRegisterLocationToIsConstant (regnums->pc_regnum , *pc_after_prologue,
2769+ false );
2770+ else
2771+ row->SetRegisterLocationToAtCFAPlusOffset (regnums->pc_regnum , ptr_size,
2772+ false );
27552773 row->SetUnspecifiedRegistersAreUndefined (true );
27562774
27572775 UnwindPlanSP plan = std::make_shared<UnwindPlan>(lldb::eRegisterKindDWARF);
@@ -2763,11 +2781,9 @@ SwiftLanguageRuntime::GetRuntimeUnwindPlan(ProcessSP process_sp,
27632781 return plan;
27642782}
27652783
2766- // Creates an UnwindPlan for following the AsyncContext chain
2767- // up the stack, from a current AsyncContext frame.
2768- static UnwindPlanSP
2769- GetFollowAsyncContextUnwindPlan (RegisterContext *regctx, ArchSpec &arch,
2770- bool &behaves_like_zeroth_frame) {
2784+ UnwindPlanSP SwiftLanguageRuntime::GetFollowAsyncContextUnwindPlan (
2785+ ProcessSP process_sp, RegisterContext *regctx, ArchSpec &arch,
2786+ bool &behaves_like_zeroth_frame) {
27712787 LLDB_SCOPED_TIMER ();
27722788
27732789 UnwindPlan::RowSP row (new UnwindPlan::Row);
@@ -2779,13 +2795,15 @@ GetFollowAsyncContextUnwindPlan(RegisterContext *regctx, ArchSpec &arch,
27792795 if (!regnums)
27802796 return UnwindPlanSP ();
27812797
2798+ const bool is_indirect =
2799+ regctx->ReadRegisterAsUnsigned (regnums->dummy_regnum , (uint64_t )-1ll ) ==
2800+ (uint64_t )-1ll ;
27822801 // In the general case, the async register setup by the frame above us
27832802 // should be dereferenced twice to get our context, except when the frame
27842803 // above us is an async frame on the OS stack that takes its context directly
27852804 // (see discussion in GetRuntimeUnwindPlan()). The availability of
27862805 // dummy_regnum is used as a marker for this situation.
2787- if (regctx->ReadRegisterAsUnsigned (regnums->dummy_regnum , (uint64_t )-1ll ) !=
2788- (uint64_t )-1ll ) {
2806+ if (!is_indirect) {
27892807 row->GetCFAValue ().SetIsRegisterDereferenced (regnums->async_ctx_regnum );
27902808 row->SetRegisterLocationToSame (regnums->async_ctx_regnum , false );
27912809 } else {
@@ -2822,8 +2840,21 @@ GetFollowAsyncContextUnwindPlan(RegisterContext *regctx, ArchSpec &arch,
28222840 regnums->async_ctx_regnum , expression, expr_size - 1 , false );
28232841 }
28242842
2825- row->SetRegisterLocationToAtCFAPlusOffset (regnums->pc_regnum , ptr_size,
2826- false );
2843+ // Suppose this is unwinding frame #2 of a call stack. The value given for
2844+ // the async register has two possible values, depending on what frame #1
2845+ // expects:
2846+ // 1. The CFA of frame #1, direct ABI, dereferencing it once produces CFA of
2847+ // Frame #2.
2848+ // 2. The CFA of frame #0, indirect ABI, dereferencing it twice produces CFA
2849+ // of Frame #2.
2850+ const unsigned num_indirections = 1 + is_indirect;
2851+ if (std::optional<addr_t > pc_after_prologue = TrySkipVirtualParentProlog (
2852+ GetAsyncContext (regctx), *process_sp, num_indirections))
2853+ row->SetRegisterLocationToIsConstant (regnums->pc_regnum , *pc_after_prologue,
2854+ false );
2855+ else
2856+ row->SetRegisterLocationToAtCFAPlusOffset (regnums->pc_regnum , ptr_size,
2857+ false );
28272858
28282859 row->SetUnspecifiedRegistersAreUndefined (true );
28292860
@@ -2837,4 +2868,51 @@ GetFollowAsyncContextUnwindPlan(RegisterContext *regctx, ArchSpec &arch,
28372868 return plan;
28382869}
28392870
2871+ std::optional<lldb::addr_t > SwiftLanguageRuntime::TrySkipVirtualParentProlog (
2872+ lldb::addr_t async_reg_val, Process &process, unsigned num_indirections) {
2873+ assert (num_indirections <= 2 &&
2874+ " more than two dereferences should not be needed" );
2875+ if (async_reg_val == LLDB_INVALID_ADDRESS || async_reg_val == 0 )
2876+ return {};
2877+
2878+ const auto ptr_size = process.GetAddressByteSize ();
2879+ Status error;
2880+
2881+ // Compute the CFA of this frame.
2882+ addr_t cfa = async_reg_val;
2883+ for (; num_indirections != 0 ; --num_indirections) {
2884+ process.ReadMemory (cfa, &cfa, ptr_size, error);
2885+ if (error.Fail ())
2886+ return {};
2887+ }
2888+
2889+ // The last funclet will have a zero CFA, we don't want to read that.
2890+ if (cfa == 0 )
2891+ return {};
2892+
2893+ // Get the PC of the parent frame, i.e. the continuation pointer, which is
2894+ // the second field of the CFA.
2895+ addr_t pc_location = cfa + ptr_size;
2896+ addr_t pc_value = LLDB_INVALID_ADDRESS;
2897+ process.ReadMemory (pc_location, &pc_value, ptr_size, error);
2898+ if (error.Fail ())
2899+ return {};
2900+
2901+ Address pc;
2902+ Target &target = process.GetTarget ();
2903+ pc.SetLoadAddress (pc_value, &target);
2904+ if (!pc.IsValid ())
2905+ return {};
2906+
2907+ SymbolContext sc;
2908+ if (!pc.CalculateSymbolContext (&sc,
2909+ eSymbolContextFunction | eSymbolContextSymbol))
2910+ return {};
2911+ if (!sc.symbol && !sc.function )
2912+ return {};
2913+
2914+ auto prologue_size = sc.symbol ? sc.symbol ->GetPrologueByteSize ()
2915+ : sc.function ->GetPrologueByteSize ();
2916+ return pc_value + prologue_size;
2917+ }
28402918} // namespace lldb_private
0 commit comments