1 //===-- ThreadPlanStack.cpp -------------------------------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Target/ThreadPlanStack.h"
10 #include "lldb/Target/Process.h"
11 #include "lldb/Target/Target.h"
12 #include "lldb/Target/Thread.h"
13 #include "lldb/Target/ThreadPlan.h"
14 #include "lldb/Utility/Log.h"
15 
16 using namespace lldb;
17 using namespace lldb_private;
18 
19 static void PrintPlanElement(Stream *s, const ThreadPlanSP &plan,
20                              lldb::DescriptionLevel desc_level,
21                              int32_t elem_idx) {
22   s->IndentMore();
23   s->Indent();
24   s->Printf("Element %d: ", elem_idx);
25   plan->GetDescription(s, desc_level);
26   s->EOL();
27   s->IndentLess();
28 }
29 
30 void ThreadPlanStack::DumpThreadPlans(Stream *s,
31                                       lldb::DescriptionLevel desc_level,
32                                       bool include_internal) const {
33 
34   uint32_t stack_size;
35 
36   s->IndentMore();
37   s->Indent();
38   s->Printf("Active plan stack:\n");
39   int32_t print_idx = 0;
40   for (auto plan : m_plans) {
41     PrintPlanElement(s, plan, desc_level, print_idx++);
42   }
43 
44   if (AnyCompletedPlans()) {
45     print_idx = 0;
46     s->Indent();
47     s->Printf("Completed Plan Stack:\n");
48     for (auto plan : m_completed_plans)
49       PrintPlanElement(s, plan, desc_level, print_idx++);
50   }
51 
52   if (AnyDiscardedPlans()) {
53     print_idx = 0;
54     s->Indent();
55     s->Printf("Discarded Plan Stack:\n");
56     for (auto plan : m_discarded_plans)
57       PrintPlanElement(s, plan, desc_level, print_idx++);
58   }
59 
60   s->IndentLess();
61 }
62 
63 size_t ThreadPlanStack::CheckpointCompletedPlans() {
64   m_completed_plan_checkpoint++;
65   m_completed_plan_store.insert(
66       std::make_pair(m_completed_plan_checkpoint, m_completed_plans));
67   return m_completed_plan_checkpoint;
68 }
69 
70 void ThreadPlanStack::RestoreCompletedPlanCheckpoint(size_t checkpoint) {
71   auto result = m_completed_plan_store.find(checkpoint);
72   assert(result != m_completed_plan_store.end() &&
73          "Asked for a checkpoint that didn't exist");
74   m_completed_plans.swap((*result).second);
75   m_completed_plan_store.erase(result);
76 }
77 
78 void ThreadPlanStack::DiscardCompletedPlanCheckpoint(size_t checkpoint) {
79   m_completed_plan_store.erase(checkpoint);
80 }
81 
82 void ThreadPlanStack::ThreadDestroyed(Thread *thread) {
83   // Tell the plan stacks that this thread is going away:
84   for (ThreadPlanSP plan : m_plans)
85     plan->ThreadDestroyed();
86 
87   for (ThreadPlanSP plan : m_discarded_plans)
88     plan->ThreadDestroyed();
89 
90   for (ThreadPlanSP plan : m_completed_plans)
91     plan->ThreadDestroyed();
92 
93   // Now clear the current plan stacks:
94   m_plans.clear();
95   m_discarded_plans.clear();
96   m_completed_plans.clear();
97 
98   // Push a ThreadPlanNull on the plan stack.  That way we can continue
99   // assuming that the plan stack is never empty, but if somebody errantly asks
100   // questions of a destroyed thread without checking first whether it is
101   // destroyed, they won't crash.
102   if (thread != nullptr) {
103     lldb::ThreadPlanSP null_plan_sp(new ThreadPlanNull(*thread));
104     m_plans.push_back(null_plan_sp);
105   }
106 }
107 
108 void ThreadPlanStack::EnableTracer(bool value, bool single_stepping) {
109   for (ThreadPlanSP plan : m_plans) {
110     if (plan->GetThreadPlanTracer()) {
111       plan->GetThreadPlanTracer()->EnableTracing(value);
112       plan->GetThreadPlanTracer()->EnableSingleStep(single_stepping);
113     }
114   }
115 }
116 
117 void ThreadPlanStack::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) {
118   for (ThreadPlanSP plan : m_plans)
119     plan->SetThreadPlanTracer(tracer_sp);
120 }
121 
122 void ThreadPlanStack::PushPlan(lldb::ThreadPlanSP new_plan_sp) {
123   // If the thread plan doesn't already have a tracer, give it its parent's
124   // tracer:
125   // The first plan has to be a base plan:
126   assert(m_plans.size() > 0 ||
127          new_plan_sp->IsBasePlan() && "Zeroth plan must be a base plan");
128 
129   if (!new_plan_sp->GetThreadPlanTracer()) {
130     assert(!m_plans.empty());
131     new_plan_sp->SetThreadPlanTracer(m_plans.back()->GetThreadPlanTracer());
132   }
133   m_plans.push_back(new_plan_sp);
134   new_plan_sp->DidPush();
135 }
136 
137 lldb::ThreadPlanSP ThreadPlanStack::PopPlan() {
138   assert(m_plans.size() > 1 && "Can't pop the base thread plan");
139 
140   lldb::ThreadPlanSP &plan_sp = m_plans.back();
141   m_completed_plans.push_back(plan_sp);
142   plan_sp->WillPop();
143   m_plans.pop_back();
144   return plan_sp;
145 }
146 
147 lldb::ThreadPlanSP ThreadPlanStack::DiscardPlan() {
148   assert(m_plans.size() > 1 && "Can't discard the base thread plan");
149 
150   lldb::ThreadPlanSP &plan_sp = m_plans.back();
151   m_discarded_plans.push_back(plan_sp);
152   plan_sp->WillPop();
153   m_plans.pop_back();
154   return plan_sp;
155 }
156 
157 // If the input plan is nullptr, discard all plans.  Otherwise make sure this
158 // plan is in the stack, and if so discard up to and including it.
159 void ThreadPlanStack::DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr) {
160   int stack_size = m_plans.size();
161 
162   if (up_to_plan_ptr == nullptr) {
163     for (int i = stack_size - 1; i > 0; i--)
164       DiscardPlan();
165     return;
166   }
167 
168   bool found_it = false;
169   for (int i = stack_size - 1; i > 0; i--) {
170     if (m_plans[i].get() == up_to_plan_ptr) {
171       found_it = true;
172       break;
173     }
174   }
175 
176   if (found_it) {
177     bool last_one = false;
178     for (int i = stack_size - 1; i > 0 && !last_one; i--) {
179       if (GetCurrentPlan().get() == up_to_plan_ptr)
180         last_one = true;
181       DiscardPlan();
182     }
183   }
184 }
185 
186 void ThreadPlanStack::DiscardAllPlans() {
187   int stack_size = m_plans.size();
188   for (int i = stack_size - 1; i > 0; i--) {
189     DiscardPlan();
190   }
191   return;
192 }
193 
194 void ThreadPlanStack::DiscardConsultingMasterPlans() {
195   while (true) {
196     int master_plan_idx;
197     bool discard = true;
198 
199     // Find the first master plan, see if it wants discarding, and if yes
200     // discard up to it.
201     for (master_plan_idx = m_plans.size() - 1; master_plan_idx >= 0;
202          master_plan_idx--) {
203       if (m_plans[master_plan_idx]->IsMasterPlan()) {
204         discard = m_plans[master_plan_idx]->OkayToDiscard();
205         break;
206       }
207     }
208 
209     // If the master plan doesn't want to get discarded, then we're done.
210     if (!discard)
211       return;
212 
213     // First pop all the dependent plans:
214     for (int i = m_plans.size() - 1; i > master_plan_idx; i--) {
215       DiscardPlan();
216     }
217 
218     // Now discard the master plan itself.
219     // The bottom-most plan never gets discarded.  "OkayToDiscard" for it
220     // means discard it's dependent plans, but not it...
221     if (master_plan_idx > 0) {
222       DiscardPlan();
223     }
224   }
225 }
226 
227 lldb::ThreadPlanSP ThreadPlanStack::GetCurrentPlan() const {
228   assert(m_plans.size() != 0 && "There will always be a base plan.");
229   return m_plans.back();
230 }
231 
232 lldb::ThreadPlanSP ThreadPlanStack::GetCompletedPlan(bool skip_private) const {
233   if (m_completed_plans.empty())
234     return {};
235 
236   if (!skip_private)
237     return m_completed_plans.back();
238 
239   for (int i = m_completed_plans.size() - 1; i >= 0; i--) {
240     lldb::ThreadPlanSP completed_plan_sp;
241     completed_plan_sp = m_completed_plans[i];
242     if (!completed_plan_sp->GetPrivate())
243       return completed_plan_sp;
244   }
245   return {};
246 }
247 
248 lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx,
249                                                    bool skip_private) const {
250   uint32_t idx = 0;
251   ThreadPlan *up_to_plan_ptr = nullptr;
252 
253   for (lldb::ThreadPlanSP plan_sp : m_plans) {
254     if (skip_private && plan_sp->GetPrivate())
255       continue;
256     if (idx == plan_idx)
257       return plan_sp;
258     idx++;
259   }
260   return {};
261 }
262 
263 lldb::ValueObjectSP ThreadPlanStack::GetReturnValueObject() const {
264   if (m_completed_plans.empty())
265     return {};
266 
267   for (int i = m_completed_plans.size() - 1; i >= 0; i--) {
268     lldb::ValueObjectSP return_valobj_sp;
269     return_valobj_sp = m_completed_plans[i]->GetReturnValueObject();
270     if (return_valobj_sp)
271       return return_valobj_sp;
272   }
273   return {};
274 }
275 
276 lldb::ExpressionVariableSP ThreadPlanStack::GetExpressionVariable() const {
277   if (m_completed_plans.empty())
278     return {};
279 
280   for (int i = m_completed_plans.size() - 1; i >= 0; i--) {
281     lldb::ExpressionVariableSP expression_variable_sp;
282     expression_variable_sp = m_completed_plans[i]->GetExpressionVariable();
283     if (expression_variable_sp)
284       return expression_variable_sp;
285   }
286   return {};
287 }
288 bool ThreadPlanStack::AnyPlans() const {
289   // There is always a base plan...
290   return m_plans.size() > 1;
291 }
292 
293 bool ThreadPlanStack::AnyCompletedPlans() const {
294   return !m_completed_plans.empty();
295 }
296 
297 bool ThreadPlanStack::AnyDiscardedPlans() const {
298   return !m_discarded_plans.empty();
299 }
300 
301 bool ThreadPlanStack::IsPlanDone(ThreadPlan *in_plan) const {
302   for (auto plan : m_completed_plans) {
303     if (plan.get() == in_plan)
304       return true;
305   }
306   return false;
307 }
308 
309 bool ThreadPlanStack::WasPlanDiscarded(ThreadPlan *in_plan) const {
310   for (auto plan : m_discarded_plans) {
311     if (plan.get() == in_plan)
312       return true;
313   }
314   return false;
315 }
316 
317 ThreadPlan *ThreadPlanStack::GetPreviousPlan(ThreadPlan *current_plan) const {
318   if (current_plan == nullptr)
319     return nullptr;
320 
321   // Look first in the completed plans, if the plan is here and there is
322   // a completed plan above it, return that.
323   int stack_size = m_completed_plans.size();
324   for (int i = stack_size - 1; i > 0; i--) {
325     if (current_plan == m_completed_plans[i].get())
326       return m_completed_plans[i - 1].get();
327   }
328 
329   // If this is the first completed plan, the previous one is the
330   // bottom of the regular plan stack.
331   if (stack_size > 0 && m_completed_plans[0].get() == current_plan) {
332     return GetCurrentPlan().get();
333   }
334 
335   // Otherwise look for it in the regular plans.
336   stack_size = m_plans.size();
337   for (int i = stack_size - 1; i > 0; i--) {
338     if (current_plan == m_plans[i].get())
339       return m_plans[i - 1].get();
340   }
341   return nullptr;
342 }
343 
344 ThreadPlan *ThreadPlanStack::GetInnermostExpression() const {
345   int stack_size = m_plans.size();
346 
347   for (int i = stack_size - 1; i > 0; i--) {
348     if (m_plans[i]->GetKind() == ThreadPlan::eKindCallFunction)
349       return m_plans[i].get();
350   }
351   return nullptr;
352 }
353 
354 void ThreadPlanStack::WillResume() {
355   m_completed_plans.clear();
356   m_discarded_plans.clear();
357 }
358 
359 const ThreadPlanStack::PlanStack &
360 ThreadPlanStack::GetStackOfKind(ThreadPlanStack::StackKind kind) const {
361   switch (kind) {
362   case ePlans:
363     return m_plans;
364   case eCompletedPlans:
365     return m_completed_plans;
366   case eDiscardedPlans:
367     return m_discarded_plans;
368   }
369   llvm_unreachable("Invalid StackKind value");
370 }
371