xref: /freebsd-src/contrib/llvm-project/lldb/source/Target/ThreadPlanStack.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1*5ffd83dbSDimitry Andric //===-- ThreadPlanStack.cpp -------------------------------------*- C++ -*-===//
2*5ffd83dbSDimitry Andric //
3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5ffd83dbSDimitry Andric //
7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
8*5ffd83dbSDimitry Andric 
9*5ffd83dbSDimitry Andric #include "lldb/Target/ThreadPlanStack.h"
10*5ffd83dbSDimitry Andric #include "lldb/Target/Process.h"
11*5ffd83dbSDimitry Andric #include "lldb/Target/Target.h"
12*5ffd83dbSDimitry Andric #include "lldb/Target/Thread.h"
13*5ffd83dbSDimitry Andric #include "lldb/Target/ThreadPlan.h"
14*5ffd83dbSDimitry Andric #include "lldb/Utility/Log.h"
15*5ffd83dbSDimitry Andric 
16*5ffd83dbSDimitry Andric using namespace lldb;
17*5ffd83dbSDimitry Andric using namespace lldb_private;
18*5ffd83dbSDimitry Andric 
19*5ffd83dbSDimitry Andric static void PrintPlanElement(Stream &s, const ThreadPlanSP &plan,
20*5ffd83dbSDimitry Andric                              lldb::DescriptionLevel desc_level,
21*5ffd83dbSDimitry Andric                              int32_t elem_idx) {
22*5ffd83dbSDimitry Andric   s.IndentMore();
23*5ffd83dbSDimitry Andric   s.Indent();
24*5ffd83dbSDimitry Andric   s.Printf("Element %d: ", elem_idx);
25*5ffd83dbSDimitry Andric   plan->GetDescription(&s, desc_level);
26*5ffd83dbSDimitry Andric   s.EOL();
27*5ffd83dbSDimitry Andric   s.IndentLess();
28*5ffd83dbSDimitry Andric }
29*5ffd83dbSDimitry Andric 
30*5ffd83dbSDimitry Andric ThreadPlanStack::ThreadPlanStack(const Thread &thread, bool make_null) {
31*5ffd83dbSDimitry Andric   if (make_null) {
32*5ffd83dbSDimitry Andric     // The ThreadPlanNull doesn't do anything to the Thread, so this is actually
33*5ffd83dbSDimitry Andric     // still a const operation.
34*5ffd83dbSDimitry Andric     m_plans.push_back(
35*5ffd83dbSDimitry Andric         ThreadPlanSP(new ThreadPlanNull(const_cast<Thread &>(thread))));
36*5ffd83dbSDimitry Andric   }
37*5ffd83dbSDimitry Andric }
38*5ffd83dbSDimitry Andric 
39*5ffd83dbSDimitry Andric void ThreadPlanStack::DumpThreadPlans(Stream &s,
40*5ffd83dbSDimitry Andric                                       lldb::DescriptionLevel desc_level,
41*5ffd83dbSDimitry Andric                                       bool include_internal) const {
42*5ffd83dbSDimitry Andric   s.IndentMore();
43*5ffd83dbSDimitry Andric   PrintOneStack(s, "Active plan stack", m_plans, desc_level, include_internal);
44*5ffd83dbSDimitry Andric   PrintOneStack(s, "Completed plan stack", m_completed_plans, desc_level,
45*5ffd83dbSDimitry Andric                 include_internal);
46*5ffd83dbSDimitry Andric   PrintOneStack(s, "Discarded plan stack", m_discarded_plans, desc_level,
47*5ffd83dbSDimitry Andric                 include_internal);
48*5ffd83dbSDimitry Andric   s.IndentLess();
49*5ffd83dbSDimitry Andric }
50*5ffd83dbSDimitry Andric 
51*5ffd83dbSDimitry Andric void ThreadPlanStack::PrintOneStack(Stream &s, llvm::StringRef stack_name,
52*5ffd83dbSDimitry Andric                                     const PlanStack &stack,
53*5ffd83dbSDimitry Andric                                     lldb::DescriptionLevel desc_level,
54*5ffd83dbSDimitry Andric                                     bool include_internal) const {
55*5ffd83dbSDimitry Andric   // If the stack is empty, just exit:
56*5ffd83dbSDimitry Andric   if (stack.empty())
57*5ffd83dbSDimitry Andric     return;
58*5ffd83dbSDimitry Andric 
59*5ffd83dbSDimitry Andric   // Make sure there are public completed plans:
60*5ffd83dbSDimitry Andric   bool any_public = false;
61*5ffd83dbSDimitry Andric   if (!include_internal) {
62*5ffd83dbSDimitry Andric     for (auto plan : stack) {
63*5ffd83dbSDimitry Andric       if (!plan->GetPrivate()) {
64*5ffd83dbSDimitry Andric         any_public = true;
65*5ffd83dbSDimitry Andric         break;
66*5ffd83dbSDimitry Andric       }
67*5ffd83dbSDimitry Andric     }
68*5ffd83dbSDimitry Andric   }
69*5ffd83dbSDimitry Andric 
70*5ffd83dbSDimitry Andric   if (include_internal || any_public) {
71*5ffd83dbSDimitry Andric     int print_idx = 0;
72*5ffd83dbSDimitry Andric     s.Indent();
73*5ffd83dbSDimitry Andric     s << stack_name << ":\n";
74*5ffd83dbSDimitry Andric     for (auto plan : stack) {
75*5ffd83dbSDimitry Andric       if (!include_internal && plan->GetPrivate())
76*5ffd83dbSDimitry Andric         continue;
77*5ffd83dbSDimitry Andric       PrintPlanElement(s, plan, desc_level, print_idx++);
78*5ffd83dbSDimitry Andric     }
79*5ffd83dbSDimitry Andric   }
80*5ffd83dbSDimitry Andric }
81*5ffd83dbSDimitry Andric 
82*5ffd83dbSDimitry Andric size_t ThreadPlanStack::CheckpointCompletedPlans() {
83*5ffd83dbSDimitry Andric   m_completed_plan_checkpoint++;
84*5ffd83dbSDimitry Andric   m_completed_plan_store.insert(
85*5ffd83dbSDimitry Andric       std::make_pair(m_completed_plan_checkpoint, m_completed_plans));
86*5ffd83dbSDimitry Andric   return m_completed_plan_checkpoint;
87*5ffd83dbSDimitry Andric }
88*5ffd83dbSDimitry Andric 
89*5ffd83dbSDimitry Andric void ThreadPlanStack::RestoreCompletedPlanCheckpoint(size_t checkpoint) {
90*5ffd83dbSDimitry Andric   auto result = m_completed_plan_store.find(checkpoint);
91*5ffd83dbSDimitry Andric   assert(result != m_completed_plan_store.end() &&
92*5ffd83dbSDimitry Andric          "Asked for a checkpoint that didn't exist");
93*5ffd83dbSDimitry Andric   m_completed_plans.swap((*result).second);
94*5ffd83dbSDimitry Andric   m_completed_plan_store.erase(result);
95*5ffd83dbSDimitry Andric }
96*5ffd83dbSDimitry Andric 
97*5ffd83dbSDimitry Andric void ThreadPlanStack::DiscardCompletedPlanCheckpoint(size_t checkpoint) {
98*5ffd83dbSDimitry Andric   m_completed_plan_store.erase(checkpoint);
99*5ffd83dbSDimitry Andric }
100*5ffd83dbSDimitry Andric 
101*5ffd83dbSDimitry Andric void ThreadPlanStack::ThreadDestroyed(Thread *thread) {
102*5ffd83dbSDimitry Andric   // Tell the plan stacks that this thread is going away:
103*5ffd83dbSDimitry Andric   for (ThreadPlanSP plan : m_plans)
104*5ffd83dbSDimitry Andric     plan->ThreadDestroyed();
105*5ffd83dbSDimitry Andric 
106*5ffd83dbSDimitry Andric   for (ThreadPlanSP plan : m_discarded_plans)
107*5ffd83dbSDimitry Andric     plan->ThreadDestroyed();
108*5ffd83dbSDimitry Andric 
109*5ffd83dbSDimitry Andric   for (ThreadPlanSP plan : m_completed_plans)
110*5ffd83dbSDimitry Andric     plan->ThreadDestroyed();
111*5ffd83dbSDimitry Andric 
112*5ffd83dbSDimitry Andric   // Now clear the current plan stacks:
113*5ffd83dbSDimitry Andric   m_plans.clear();
114*5ffd83dbSDimitry Andric   m_discarded_plans.clear();
115*5ffd83dbSDimitry Andric   m_completed_plans.clear();
116*5ffd83dbSDimitry Andric 
117*5ffd83dbSDimitry Andric   // Push a ThreadPlanNull on the plan stack.  That way we can continue
118*5ffd83dbSDimitry Andric   // assuming that the plan stack is never empty, but if somebody errantly asks
119*5ffd83dbSDimitry Andric   // questions of a destroyed thread without checking first whether it is
120*5ffd83dbSDimitry Andric   // destroyed, they won't crash.
121*5ffd83dbSDimitry Andric   if (thread != nullptr) {
122*5ffd83dbSDimitry Andric     lldb::ThreadPlanSP null_plan_sp(new ThreadPlanNull(*thread));
123*5ffd83dbSDimitry Andric     m_plans.push_back(null_plan_sp);
124*5ffd83dbSDimitry Andric   }
125*5ffd83dbSDimitry Andric }
126*5ffd83dbSDimitry Andric 
127*5ffd83dbSDimitry Andric void ThreadPlanStack::EnableTracer(bool value, bool single_stepping) {
128*5ffd83dbSDimitry Andric   for (ThreadPlanSP plan : m_plans) {
129*5ffd83dbSDimitry Andric     if (plan->GetThreadPlanTracer()) {
130*5ffd83dbSDimitry Andric       plan->GetThreadPlanTracer()->EnableTracing(value);
131*5ffd83dbSDimitry Andric       plan->GetThreadPlanTracer()->EnableSingleStep(single_stepping);
132*5ffd83dbSDimitry Andric     }
133*5ffd83dbSDimitry Andric   }
134*5ffd83dbSDimitry Andric }
135*5ffd83dbSDimitry Andric 
136*5ffd83dbSDimitry Andric void ThreadPlanStack::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) {
137*5ffd83dbSDimitry Andric   for (ThreadPlanSP plan : m_plans)
138*5ffd83dbSDimitry Andric     plan->SetThreadPlanTracer(tracer_sp);
139*5ffd83dbSDimitry Andric }
140*5ffd83dbSDimitry Andric 
141*5ffd83dbSDimitry Andric void ThreadPlanStack::PushPlan(lldb::ThreadPlanSP new_plan_sp) {
142*5ffd83dbSDimitry Andric   // If the thread plan doesn't already have a tracer, give it its parent's
143*5ffd83dbSDimitry Andric   // tracer:
144*5ffd83dbSDimitry Andric   // The first plan has to be a base plan:
145*5ffd83dbSDimitry Andric   assert((m_plans.size() > 0 || new_plan_sp->IsBasePlan()) &&
146*5ffd83dbSDimitry Andric          "Zeroth plan must be a base plan");
147*5ffd83dbSDimitry Andric 
148*5ffd83dbSDimitry Andric   if (!new_plan_sp->GetThreadPlanTracer()) {
149*5ffd83dbSDimitry Andric     assert(!m_plans.empty());
150*5ffd83dbSDimitry Andric     new_plan_sp->SetThreadPlanTracer(m_plans.back()->GetThreadPlanTracer());
151*5ffd83dbSDimitry Andric   }
152*5ffd83dbSDimitry Andric   m_plans.push_back(new_plan_sp);
153*5ffd83dbSDimitry Andric   new_plan_sp->DidPush();
154*5ffd83dbSDimitry Andric }
155*5ffd83dbSDimitry Andric 
156*5ffd83dbSDimitry Andric lldb::ThreadPlanSP ThreadPlanStack::PopPlan() {
157*5ffd83dbSDimitry Andric   assert(m_plans.size() > 1 && "Can't pop the base thread plan");
158*5ffd83dbSDimitry Andric 
159*5ffd83dbSDimitry Andric   lldb::ThreadPlanSP plan_sp = std::move(m_plans.back());
160*5ffd83dbSDimitry Andric   m_completed_plans.push_back(plan_sp);
161*5ffd83dbSDimitry Andric   plan_sp->WillPop();
162*5ffd83dbSDimitry Andric   m_plans.pop_back();
163*5ffd83dbSDimitry Andric   return plan_sp;
164*5ffd83dbSDimitry Andric }
165*5ffd83dbSDimitry Andric 
166*5ffd83dbSDimitry Andric lldb::ThreadPlanSP ThreadPlanStack::DiscardPlan() {
167*5ffd83dbSDimitry Andric   assert(m_plans.size() > 1 && "Can't discard the base thread plan");
168*5ffd83dbSDimitry Andric 
169*5ffd83dbSDimitry Andric   lldb::ThreadPlanSP plan_sp = std::move(m_plans.back());
170*5ffd83dbSDimitry Andric   m_discarded_plans.push_back(plan_sp);
171*5ffd83dbSDimitry Andric   plan_sp->WillPop();
172*5ffd83dbSDimitry Andric   m_plans.pop_back();
173*5ffd83dbSDimitry Andric   return plan_sp;
174*5ffd83dbSDimitry Andric }
175*5ffd83dbSDimitry Andric 
176*5ffd83dbSDimitry Andric // If the input plan is nullptr, discard all plans.  Otherwise make sure this
177*5ffd83dbSDimitry Andric // plan is in the stack, and if so discard up to and including it.
178*5ffd83dbSDimitry Andric void ThreadPlanStack::DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr) {
179*5ffd83dbSDimitry Andric   int stack_size = m_plans.size();
180*5ffd83dbSDimitry Andric 
181*5ffd83dbSDimitry Andric   if (up_to_plan_ptr == nullptr) {
182*5ffd83dbSDimitry Andric     for (int i = stack_size - 1; i > 0; i--)
183*5ffd83dbSDimitry Andric       DiscardPlan();
184*5ffd83dbSDimitry Andric     return;
185*5ffd83dbSDimitry Andric   }
186*5ffd83dbSDimitry Andric 
187*5ffd83dbSDimitry Andric   bool found_it = false;
188*5ffd83dbSDimitry Andric   for (int i = stack_size - 1; i > 0; i--) {
189*5ffd83dbSDimitry Andric     if (m_plans[i].get() == up_to_plan_ptr) {
190*5ffd83dbSDimitry Andric       found_it = true;
191*5ffd83dbSDimitry Andric       break;
192*5ffd83dbSDimitry Andric     }
193*5ffd83dbSDimitry Andric   }
194*5ffd83dbSDimitry Andric 
195*5ffd83dbSDimitry Andric   if (found_it) {
196*5ffd83dbSDimitry Andric     bool last_one = false;
197*5ffd83dbSDimitry Andric     for (int i = stack_size - 1; i > 0 && !last_one; i--) {
198*5ffd83dbSDimitry Andric       if (GetCurrentPlan().get() == up_to_plan_ptr)
199*5ffd83dbSDimitry Andric         last_one = true;
200*5ffd83dbSDimitry Andric       DiscardPlan();
201*5ffd83dbSDimitry Andric     }
202*5ffd83dbSDimitry Andric   }
203*5ffd83dbSDimitry Andric }
204*5ffd83dbSDimitry Andric 
205*5ffd83dbSDimitry Andric void ThreadPlanStack::DiscardAllPlans() {
206*5ffd83dbSDimitry Andric   int stack_size = m_plans.size();
207*5ffd83dbSDimitry Andric   for (int i = stack_size - 1; i > 0; i--) {
208*5ffd83dbSDimitry Andric     DiscardPlan();
209*5ffd83dbSDimitry Andric   }
210*5ffd83dbSDimitry Andric   return;
211*5ffd83dbSDimitry Andric }
212*5ffd83dbSDimitry Andric 
213*5ffd83dbSDimitry Andric void ThreadPlanStack::DiscardConsultingMasterPlans() {
214*5ffd83dbSDimitry Andric   while (true) {
215*5ffd83dbSDimitry Andric     int master_plan_idx;
216*5ffd83dbSDimitry Andric     bool discard = true;
217*5ffd83dbSDimitry Andric 
218*5ffd83dbSDimitry Andric     // Find the first master plan, see if it wants discarding, and if yes
219*5ffd83dbSDimitry Andric     // discard up to it.
220*5ffd83dbSDimitry Andric     for (master_plan_idx = m_plans.size() - 1; master_plan_idx >= 0;
221*5ffd83dbSDimitry Andric          master_plan_idx--) {
222*5ffd83dbSDimitry Andric       if (m_plans[master_plan_idx]->IsMasterPlan()) {
223*5ffd83dbSDimitry Andric         discard = m_plans[master_plan_idx]->OkayToDiscard();
224*5ffd83dbSDimitry Andric         break;
225*5ffd83dbSDimitry Andric       }
226*5ffd83dbSDimitry Andric     }
227*5ffd83dbSDimitry Andric 
228*5ffd83dbSDimitry Andric     // If the master plan doesn't want to get discarded, then we're done.
229*5ffd83dbSDimitry Andric     if (!discard)
230*5ffd83dbSDimitry Andric       return;
231*5ffd83dbSDimitry Andric 
232*5ffd83dbSDimitry Andric     // First pop all the dependent plans:
233*5ffd83dbSDimitry Andric     for (int i = m_plans.size() - 1; i > master_plan_idx; i--) {
234*5ffd83dbSDimitry Andric       DiscardPlan();
235*5ffd83dbSDimitry Andric     }
236*5ffd83dbSDimitry Andric 
237*5ffd83dbSDimitry Andric     // Now discard the master plan itself.
238*5ffd83dbSDimitry Andric     // The bottom-most plan never gets discarded.  "OkayToDiscard" for it
239*5ffd83dbSDimitry Andric     // means discard it's dependent plans, but not it...
240*5ffd83dbSDimitry Andric     if (master_plan_idx > 0) {
241*5ffd83dbSDimitry Andric       DiscardPlan();
242*5ffd83dbSDimitry Andric     }
243*5ffd83dbSDimitry Andric   }
244*5ffd83dbSDimitry Andric }
245*5ffd83dbSDimitry Andric 
246*5ffd83dbSDimitry Andric lldb::ThreadPlanSP ThreadPlanStack::GetCurrentPlan() const {
247*5ffd83dbSDimitry Andric   assert(m_plans.size() != 0 && "There will always be a base plan.");
248*5ffd83dbSDimitry Andric   return m_plans.back();
249*5ffd83dbSDimitry Andric }
250*5ffd83dbSDimitry Andric 
251*5ffd83dbSDimitry Andric lldb::ThreadPlanSP ThreadPlanStack::GetCompletedPlan(bool skip_private) const {
252*5ffd83dbSDimitry Andric   if (m_completed_plans.empty())
253*5ffd83dbSDimitry Andric     return {};
254*5ffd83dbSDimitry Andric 
255*5ffd83dbSDimitry Andric   if (!skip_private)
256*5ffd83dbSDimitry Andric     return m_completed_plans.back();
257*5ffd83dbSDimitry Andric 
258*5ffd83dbSDimitry Andric   for (int i = m_completed_plans.size() - 1; i >= 0; i--) {
259*5ffd83dbSDimitry Andric     lldb::ThreadPlanSP completed_plan_sp;
260*5ffd83dbSDimitry Andric     completed_plan_sp = m_completed_plans[i];
261*5ffd83dbSDimitry Andric     if (!completed_plan_sp->GetPrivate())
262*5ffd83dbSDimitry Andric       return completed_plan_sp;
263*5ffd83dbSDimitry Andric   }
264*5ffd83dbSDimitry Andric   return {};
265*5ffd83dbSDimitry Andric }
266*5ffd83dbSDimitry Andric 
267*5ffd83dbSDimitry Andric lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx,
268*5ffd83dbSDimitry Andric                                                    bool skip_private) const {
269*5ffd83dbSDimitry Andric   uint32_t idx = 0;
270*5ffd83dbSDimitry Andric 
271*5ffd83dbSDimitry Andric   for (lldb::ThreadPlanSP plan_sp : m_plans) {
272*5ffd83dbSDimitry Andric     if (skip_private && plan_sp->GetPrivate())
273*5ffd83dbSDimitry Andric       continue;
274*5ffd83dbSDimitry Andric     if (idx == plan_idx)
275*5ffd83dbSDimitry Andric       return plan_sp;
276*5ffd83dbSDimitry Andric     idx++;
277*5ffd83dbSDimitry Andric   }
278*5ffd83dbSDimitry Andric   return {};
279*5ffd83dbSDimitry Andric }
280*5ffd83dbSDimitry Andric 
281*5ffd83dbSDimitry Andric lldb::ValueObjectSP ThreadPlanStack::GetReturnValueObject() const {
282*5ffd83dbSDimitry Andric   if (m_completed_plans.empty())
283*5ffd83dbSDimitry Andric     return {};
284*5ffd83dbSDimitry Andric 
285*5ffd83dbSDimitry Andric   for (int i = m_completed_plans.size() - 1; i >= 0; i--) {
286*5ffd83dbSDimitry Andric     lldb::ValueObjectSP return_valobj_sp;
287*5ffd83dbSDimitry Andric     return_valobj_sp = m_completed_plans[i]->GetReturnValueObject();
288*5ffd83dbSDimitry Andric     if (return_valobj_sp)
289*5ffd83dbSDimitry Andric       return return_valobj_sp;
290*5ffd83dbSDimitry Andric   }
291*5ffd83dbSDimitry Andric   return {};
292*5ffd83dbSDimitry Andric }
293*5ffd83dbSDimitry Andric 
294*5ffd83dbSDimitry Andric lldb::ExpressionVariableSP ThreadPlanStack::GetExpressionVariable() const {
295*5ffd83dbSDimitry Andric   if (m_completed_plans.empty())
296*5ffd83dbSDimitry Andric     return {};
297*5ffd83dbSDimitry Andric 
298*5ffd83dbSDimitry Andric   for (int i = m_completed_plans.size() - 1; i >= 0; i--) {
299*5ffd83dbSDimitry Andric     lldb::ExpressionVariableSP expression_variable_sp;
300*5ffd83dbSDimitry Andric     expression_variable_sp = m_completed_plans[i]->GetExpressionVariable();
301*5ffd83dbSDimitry Andric     if (expression_variable_sp)
302*5ffd83dbSDimitry Andric       return expression_variable_sp;
303*5ffd83dbSDimitry Andric   }
304*5ffd83dbSDimitry Andric   return {};
305*5ffd83dbSDimitry Andric }
306*5ffd83dbSDimitry Andric bool ThreadPlanStack::AnyPlans() const {
307*5ffd83dbSDimitry Andric   // There is always a base plan...
308*5ffd83dbSDimitry Andric   return m_plans.size() > 1;
309*5ffd83dbSDimitry Andric }
310*5ffd83dbSDimitry Andric 
311*5ffd83dbSDimitry Andric bool ThreadPlanStack::AnyCompletedPlans() const {
312*5ffd83dbSDimitry Andric   return !m_completed_plans.empty();
313*5ffd83dbSDimitry Andric }
314*5ffd83dbSDimitry Andric 
315*5ffd83dbSDimitry Andric bool ThreadPlanStack::AnyDiscardedPlans() const {
316*5ffd83dbSDimitry Andric   return !m_discarded_plans.empty();
317*5ffd83dbSDimitry Andric }
318*5ffd83dbSDimitry Andric 
319*5ffd83dbSDimitry Andric bool ThreadPlanStack::IsPlanDone(ThreadPlan *in_plan) const {
320*5ffd83dbSDimitry Andric   for (auto plan : m_completed_plans) {
321*5ffd83dbSDimitry Andric     if (plan.get() == in_plan)
322*5ffd83dbSDimitry Andric       return true;
323*5ffd83dbSDimitry Andric   }
324*5ffd83dbSDimitry Andric   return false;
325*5ffd83dbSDimitry Andric }
326*5ffd83dbSDimitry Andric 
327*5ffd83dbSDimitry Andric bool ThreadPlanStack::WasPlanDiscarded(ThreadPlan *in_plan) const {
328*5ffd83dbSDimitry Andric   for (auto plan : m_discarded_plans) {
329*5ffd83dbSDimitry Andric     if (plan.get() == in_plan)
330*5ffd83dbSDimitry Andric       return true;
331*5ffd83dbSDimitry Andric   }
332*5ffd83dbSDimitry Andric   return false;
333*5ffd83dbSDimitry Andric }
334*5ffd83dbSDimitry Andric 
335*5ffd83dbSDimitry Andric ThreadPlan *ThreadPlanStack::GetPreviousPlan(ThreadPlan *current_plan) const {
336*5ffd83dbSDimitry Andric   if (current_plan == nullptr)
337*5ffd83dbSDimitry Andric     return nullptr;
338*5ffd83dbSDimitry Andric 
339*5ffd83dbSDimitry Andric   // Look first in the completed plans, if the plan is here and there is
340*5ffd83dbSDimitry Andric   // a completed plan above it, return that.
341*5ffd83dbSDimitry Andric   int stack_size = m_completed_plans.size();
342*5ffd83dbSDimitry Andric   for (int i = stack_size - 1; i > 0; i--) {
343*5ffd83dbSDimitry Andric     if (current_plan == m_completed_plans[i].get())
344*5ffd83dbSDimitry Andric       return m_completed_plans[i - 1].get();
345*5ffd83dbSDimitry Andric   }
346*5ffd83dbSDimitry Andric 
347*5ffd83dbSDimitry Andric   // If this is the first completed plan, the previous one is the
348*5ffd83dbSDimitry Andric   // bottom of the regular plan stack.
349*5ffd83dbSDimitry Andric   if (stack_size > 0 && m_completed_plans[0].get() == current_plan) {
350*5ffd83dbSDimitry Andric     return GetCurrentPlan().get();
351*5ffd83dbSDimitry Andric   }
352*5ffd83dbSDimitry Andric 
353*5ffd83dbSDimitry Andric   // Otherwise look for it in the regular plans.
354*5ffd83dbSDimitry Andric   stack_size = m_plans.size();
355*5ffd83dbSDimitry Andric   for (int i = stack_size - 1; i > 0; i--) {
356*5ffd83dbSDimitry Andric     if (current_plan == m_plans[i].get())
357*5ffd83dbSDimitry Andric       return m_plans[i - 1].get();
358*5ffd83dbSDimitry Andric   }
359*5ffd83dbSDimitry Andric   return nullptr;
360*5ffd83dbSDimitry Andric }
361*5ffd83dbSDimitry Andric 
362*5ffd83dbSDimitry Andric ThreadPlan *ThreadPlanStack::GetInnermostExpression() const {
363*5ffd83dbSDimitry Andric   int stack_size = m_plans.size();
364*5ffd83dbSDimitry Andric 
365*5ffd83dbSDimitry Andric   for (int i = stack_size - 1; i > 0; i--) {
366*5ffd83dbSDimitry Andric     if (m_plans[i]->GetKind() == ThreadPlan::eKindCallFunction)
367*5ffd83dbSDimitry Andric       return m_plans[i].get();
368*5ffd83dbSDimitry Andric   }
369*5ffd83dbSDimitry Andric   return nullptr;
370*5ffd83dbSDimitry Andric }
371*5ffd83dbSDimitry Andric 
372*5ffd83dbSDimitry Andric void ThreadPlanStack::WillResume() {
373*5ffd83dbSDimitry Andric   m_completed_plans.clear();
374*5ffd83dbSDimitry Andric   m_discarded_plans.clear();
375*5ffd83dbSDimitry Andric }
376*5ffd83dbSDimitry Andric 
377*5ffd83dbSDimitry Andric const ThreadPlanStack::PlanStack &
378*5ffd83dbSDimitry Andric ThreadPlanStack::GetStackOfKind(ThreadPlanStack::StackKind kind) const {
379*5ffd83dbSDimitry Andric   switch (kind) {
380*5ffd83dbSDimitry Andric   case ePlans:
381*5ffd83dbSDimitry Andric     return m_plans;
382*5ffd83dbSDimitry Andric   case eCompletedPlans:
383*5ffd83dbSDimitry Andric     return m_completed_plans;
384*5ffd83dbSDimitry Andric   case eDiscardedPlans:
385*5ffd83dbSDimitry Andric     return m_discarded_plans;
386*5ffd83dbSDimitry Andric   }
387*5ffd83dbSDimitry Andric   llvm_unreachable("Invalid StackKind value");
388*5ffd83dbSDimitry Andric }
389*5ffd83dbSDimitry Andric 
390*5ffd83dbSDimitry Andric void ThreadPlanStackMap::Update(ThreadList &current_threads,
391*5ffd83dbSDimitry Andric                                 bool delete_missing,
392*5ffd83dbSDimitry Andric                                 bool check_for_new) {
393*5ffd83dbSDimitry Andric 
394*5ffd83dbSDimitry Andric   // Now find all the new threads and add them to the map:
395*5ffd83dbSDimitry Andric   if (check_for_new) {
396*5ffd83dbSDimitry Andric     for (auto thread : current_threads.Threads()) {
397*5ffd83dbSDimitry Andric       lldb::tid_t cur_tid = thread->GetID();
398*5ffd83dbSDimitry Andric       if (!Find(cur_tid)) {
399*5ffd83dbSDimitry Andric         AddThread(*thread.get());
400*5ffd83dbSDimitry Andric         thread->QueueFundamentalPlan(true);
401*5ffd83dbSDimitry Andric       }
402*5ffd83dbSDimitry Andric     }
403*5ffd83dbSDimitry Andric   }
404*5ffd83dbSDimitry Andric 
405*5ffd83dbSDimitry Andric   // If we aren't reaping missing threads at this point,
406*5ffd83dbSDimitry Andric   // we are done.
407*5ffd83dbSDimitry Andric   if (!delete_missing)
408*5ffd83dbSDimitry Andric     return;
409*5ffd83dbSDimitry Andric   // Otherwise scan for absent TID's.
410*5ffd83dbSDimitry Andric   std::vector<lldb::tid_t> missing_threads;
411*5ffd83dbSDimitry Andric   // If we are going to delete plans from the plan stack,
412*5ffd83dbSDimitry Andric   // then scan for absent TID's:
413*5ffd83dbSDimitry Andric   for (auto thread_plans : m_plans_list) {
414*5ffd83dbSDimitry Andric     lldb::tid_t cur_tid = thread_plans.first;
415*5ffd83dbSDimitry Andric     ThreadSP thread_sp = current_threads.FindThreadByID(cur_tid);
416*5ffd83dbSDimitry Andric     if (!thread_sp)
417*5ffd83dbSDimitry Andric       missing_threads.push_back(cur_tid);
418*5ffd83dbSDimitry Andric   }
419*5ffd83dbSDimitry Andric   for (lldb::tid_t tid : missing_threads) {
420*5ffd83dbSDimitry Andric     RemoveTID(tid);
421*5ffd83dbSDimitry Andric   }
422*5ffd83dbSDimitry Andric }
423*5ffd83dbSDimitry Andric 
424*5ffd83dbSDimitry Andric void ThreadPlanStackMap::DumpPlans(Stream &strm,
425*5ffd83dbSDimitry Andric                                    lldb::DescriptionLevel desc_level,
426*5ffd83dbSDimitry Andric                                    bool internal, bool condense_if_trivial,
427*5ffd83dbSDimitry Andric                                    bool skip_unreported) {
428*5ffd83dbSDimitry Andric   for (auto elem : m_plans_list) {
429*5ffd83dbSDimitry Andric     lldb::tid_t tid = elem.first;
430*5ffd83dbSDimitry Andric     uint32_t index_id = 0;
431*5ffd83dbSDimitry Andric     ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid);
432*5ffd83dbSDimitry Andric 
433*5ffd83dbSDimitry Andric     if (skip_unreported) {
434*5ffd83dbSDimitry Andric       if (!thread_sp)
435*5ffd83dbSDimitry Andric         continue;
436*5ffd83dbSDimitry Andric     }
437*5ffd83dbSDimitry Andric     if (thread_sp)
438*5ffd83dbSDimitry Andric       index_id = thread_sp->GetIndexID();
439*5ffd83dbSDimitry Andric 
440*5ffd83dbSDimitry Andric     if (condense_if_trivial) {
441*5ffd83dbSDimitry Andric       if (!elem.second.AnyPlans() && !elem.second.AnyCompletedPlans() &&
442*5ffd83dbSDimitry Andric           !elem.second.AnyDiscardedPlans()) {
443*5ffd83dbSDimitry Andric         strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid);
444*5ffd83dbSDimitry Andric         strm.IndentMore();
445*5ffd83dbSDimitry Andric         strm.Indent();
446*5ffd83dbSDimitry Andric         strm.Printf("No active thread plans\n");
447*5ffd83dbSDimitry Andric         strm.IndentLess();
448*5ffd83dbSDimitry Andric         return;
449*5ffd83dbSDimitry Andric       }
450*5ffd83dbSDimitry Andric     }
451*5ffd83dbSDimitry Andric 
452*5ffd83dbSDimitry Andric     strm.Indent();
453*5ffd83dbSDimitry Andric     strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid);
454*5ffd83dbSDimitry Andric 
455*5ffd83dbSDimitry Andric     elem.second.DumpThreadPlans(strm, desc_level, internal);
456*5ffd83dbSDimitry Andric   }
457*5ffd83dbSDimitry Andric }
458*5ffd83dbSDimitry Andric 
459*5ffd83dbSDimitry Andric bool ThreadPlanStackMap::DumpPlansForTID(Stream &strm, lldb::tid_t tid,
460*5ffd83dbSDimitry Andric                                          lldb::DescriptionLevel desc_level,
461*5ffd83dbSDimitry Andric                                          bool internal,
462*5ffd83dbSDimitry Andric                                          bool condense_if_trivial,
463*5ffd83dbSDimitry Andric                                          bool skip_unreported) {
464*5ffd83dbSDimitry Andric   uint32_t index_id = 0;
465*5ffd83dbSDimitry Andric   ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid);
466*5ffd83dbSDimitry Andric 
467*5ffd83dbSDimitry Andric   if (skip_unreported) {
468*5ffd83dbSDimitry Andric     if (!thread_sp) {
469*5ffd83dbSDimitry Andric       strm.Format("Unknown TID: {0}", tid);
470*5ffd83dbSDimitry Andric       return false;
471*5ffd83dbSDimitry Andric     }
472*5ffd83dbSDimitry Andric   }
473*5ffd83dbSDimitry Andric 
474*5ffd83dbSDimitry Andric   if (thread_sp)
475*5ffd83dbSDimitry Andric     index_id = thread_sp->GetIndexID();
476*5ffd83dbSDimitry Andric   ThreadPlanStack *stack = Find(tid);
477*5ffd83dbSDimitry Andric   if (!stack) {
478*5ffd83dbSDimitry Andric     strm.Format("Unknown TID: {0}\n", tid);
479*5ffd83dbSDimitry Andric     return false;
480*5ffd83dbSDimitry Andric   }
481*5ffd83dbSDimitry Andric 
482*5ffd83dbSDimitry Andric   if (condense_if_trivial) {
483*5ffd83dbSDimitry Andric     if (!stack->AnyPlans() && !stack->AnyCompletedPlans() &&
484*5ffd83dbSDimitry Andric         !stack->AnyDiscardedPlans()) {
485*5ffd83dbSDimitry Andric       strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid);
486*5ffd83dbSDimitry Andric       strm.IndentMore();
487*5ffd83dbSDimitry Andric       strm.Indent();
488*5ffd83dbSDimitry Andric       strm.Printf("No active thread plans\n");
489*5ffd83dbSDimitry Andric       strm.IndentLess();
490*5ffd83dbSDimitry Andric       return true;
491*5ffd83dbSDimitry Andric     }
492*5ffd83dbSDimitry Andric   }
493*5ffd83dbSDimitry Andric 
494*5ffd83dbSDimitry Andric   strm.Indent();
495*5ffd83dbSDimitry Andric   strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid);
496*5ffd83dbSDimitry Andric 
497*5ffd83dbSDimitry Andric   stack->DumpThreadPlans(strm, desc_level, internal);
498*5ffd83dbSDimitry Andric   return true;
499*5ffd83dbSDimitry Andric }
500*5ffd83dbSDimitry Andric 
501*5ffd83dbSDimitry Andric bool ThreadPlanStackMap::PrunePlansForTID(lldb::tid_t tid) {
502*5ffd83dbSDimitry Andric   // We only remove the plans for unreported TID's.
503*5ffd83dbSDimitry Andric   ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid);
504*5ffd83dbSDimitry Andric   if (thread_sp)
505*5ffd83dbSDimitry Andric     return false;
506*5ffd83dbSDimitry Andric 
507*5ffd83dbSDimitry Andric   return RemoveTID(tid);
508*5ffd83dbSDimitry Andric }
509