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