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