@@ -76,11 +76,40 @@ bool lldb_private::operator!=(const StackID &lhs, const StackID &rhs) {
7676}
7777
7878// BEGIN SWIFT
79+ // / Given two async contexts, source and maybe_parent, chase continuation
80+ // / pointers to check if maybe_parent can be reached from source. The search
81+ // / stops when it hits the end of the chain (parent_ctx == 0) or a safety limit
82+ // / in case of an invalid continuation chain.
83+ static llvm::Expected<bool > IsReachableParent (lldb::addr_t source,
84+ lldb::addr_t maybe_parent,
85+ Process &process) {
86+ auto max_num_frames = 512 ;
87+ for (lldb::addr_t parent_ctx = source; parent_ctx && max_num_frames;
88+ max_num_frames--) {
89+ Status error;
90+ lldb::addr_t old_parent_ctx = parent_ctx;
91+ // The continuation's context is the first field of an async context.
92+ parent_ctx = process.ReadPointerFromMemory (old_parent_ctx, error);
93+ if (error.Fail ())
94+ return llvm::createStringError (llvm::formatv (
95+ " Failed to read parent async context of: {0:x}. Error: {1}" ,
96+ old_parent_ctx, error.AsCString ()));
97+ if (parent_ctx == maybe_parent)
98+ return true ;
99+ }
100+ if (max_num_frames == 0 )
101+ return llvm::createStringError (
102+ llvm::formatv (" Failed to read continuation chain from {0:x} to "
103+ " possible parent {1:x}. Reached limit of frames." ,
104+ source, maybe_parent));
105+ return false ;
106+ }
107+
79108enum class HeapCFAComparisonResult { Younger, Older, NoOpinion };
80109// / If at least one of the stack IDs (lhs, rhs) is a heap CFA, perform the
81110// / swift-specific async frame comparison. Otherwise, returns NoOpinion.
82111static HeapCFAComparisonResult
83- IsYoungerHeapCFAs (const StackID &lhs, const StackID &rhs, Process &process) {
112+ CompareHeapCFAs (const StackID &lhs, const StackID &rhs, Process &process) {
84113 const bool lhs_cfa_on_stack = lhs.IsCFAOnStack (process);
85114 const bool rhs_cfa_on_stack = rhs.IsCFAOnStack (process);
86115 if (lhs_cfa_on_stack && rhs_cfa_on_stack)
@@ -103,34 +132,21 @@ IsYoungerHeapCFAs(const StackID &lhs, const StackID &rhs, Process &process) {
103132
104133 // Both CFAs are on the heap and they are distinct.
105134 // LHS is younger if and only if its continuation async context is (directly
106- // or indirectly) RHS. Chase continuation pointers to check this case, until
107- // we hit the end of the chain (parent_ctx == 0) or a safety limit in case of
108- // an invalid continuation chain.
109- auto max_num_frames = 512 ;
110- for (lldb::addr_t parent_ctx = lhs_cfa; parent_ctx && max_num_frames;
111- max_num_frames--) {
112- Status error;
113- lldb::addr_t old_parent_ctx = parent_ctx;
114- // The continuation's context is the first field of an async context.
115- parent_ctx = process.ReadPointerFromMemory (old_parent_ctx, error);
116- if (error.Fail ()) {
117- Log *log = GetLog (LLDBLog::Unwind);
118- LLDB_LOGF (log, " Failed to read parent async context of: 0x%8.8" PRIx64,
119- old_parent_ctx);
120- break ;
121- }
122- if (parent_ctx == rhs_cfa)
123- return HeapCFAComparisonResult::Younger;
124- }
125-
135+ // or indirectly) RHS.
136+ llvm::Expected<bool > lhs_younger =
137+ IsReachableParent (lhs_cfa, rhs_cfa, process);
138+ if (auto E = lhs_younger.takeError ())
139+ LLDB_LOG_ERROR (GetLog (LLDBLog::Unwind), std::move (E), " {0}" );
140+ else if (*lhs_younger)
141+ return HeapCFAComparisonResult::Younger;
126142 return HeapCFAComparisonResult::NoOpinion;
127143}
128144// END SWIFT
129145
130146bool StackID::IsYounger (const StackID &lhs, const StackID &rhs,
131147 Process &process) {
132148 // BEGIN SWIFT
133- switch (IsYoungerHeapCFAs (lhs, rhs, process)) {
149+ switch (CompareHeapCFAs (lhs, rhs, process)) {
134150 case HeapCFAComparisonResult::Younger:
135151 return true ;
136152 case HeapCFAComparisonResult::Older:
0 commit comments