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