xref: /llvm-project/lldb/source/Target/ThreadPlanStack.cpp (revision b42a81631491571c4b78d095917ebdddee69b04f)
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   llvm::sys::ScopedReader guard(m_stack_mutex);
43   s.IndentMore();
44   PrintOneStackNoLock(s, "Active plan stack", m_plans, desc_level,
45                       include_internal);
46   PrintOneStackNoLock(s, "Completed plan stack", m_completed_plans, desc_level,
47                       include_internal);
48   PrintOneStackNoLock(s, "Discarded plan stack", m_discarded_plans, desc_level,
49                       include_internal);
50   s.IndentLess();
51 }
52 
53 void ThreadPlanStack::PrintOneStackNoLock(Stream &s, llvm::StringRef stack_name,
54                                           const PlanStack &stack,
55                                           lldb::DescriptionLevel desc_level,
56                                           bool include_internal) const {
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 
84 size_t ThreadPlanStack::CheckpointCompletedPlans() {
85   llvm::sys::ScopedWriter 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 
92 void ThreadPlanStack::RestoreCompletedPlanCheckpoint(size_t checkpoint) {
93   llvm::sys::ScopedWriter 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 
101 void ThreadPlanStack::DiscardCompletedPlanCheckpoint(size_t checkpoint) {
102   llvm::sys::ScopedWriter guard(m_stack_mutex);
103   m_completed_plan_store.erase(checkpoint);
104 }
105 
106 void ThreadPlanStack::ThreadDestroyed(Thread *thread) {
107   // Tell the plan stacks that this thread is going away:
108   llvm::sys::ScopedWriter 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 
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   { // Scope for Lock - DidPush often adds plans to the stack:
138     llvm::sys::ScopedWriter guard(m_stack_mutex);
139     assert((m_plans.size() > 0 || new_plan_sp->IsBasePlan()) &&
140            "Zeroth plan must be a base plan");
141 
142     if (!new_plan_sp->GetThreadPlanTracer()) {
143       assert(!m_plans.empty());
144       new_plan_sp->SetThreadPlanTracer(m_plans.back()->GetThreadPlanTracer());
145     }
146     m_plans.push_back(new_plan_sp);
147   }
148   new_plan_sp->DidPush();
149 }
150 
151 lldb::ThreadPlanSP ThreadPlanStack::PopPlan() {
152   llvm::sys::ScopedWriter guard(m_stack_mutex);
153   assert(m_plans.size() > 1 && "Can't pop the base thread plan");
154 
155   // Note that moving the top element of the vector would leave it in an
156   // undefined state, and break the guarantee that the stack's thread plans are
157   // all valid.
158   lldb::ThreadPlanSP plan_sp = m_plans.back();
159   m_plans.pop_back();
160   m_completed_plans.push_back(plan_sp);
161   plan_sp->DidPop();
162   return plan_sp;
163 }
164 
165 lldb::ThreadPlanSP ThreadPlanStack::DiscardPlan() {
166   llvm::sys::ScopedWriter guard(m_stack_mutex);
167   return DiscardPlanNoLock();
168 }
169 
170 lldb::ThreadPlanSP ThreadPlanStack::DiscardPlanNoLock() {
171   assert(m_plans.size() > 1 && "Can't discard the base thread plan");
172 
173   // Note that moving the top element of the vector would leave it in an
174   // undefined state, and break the guarantee that the stack's thread plans are
175   // all valid.
176   lldb::ThreadPlanSP plan_sp = m_plans.back();
177   m_plans.pop_back();
178   m_discarded_plans.push_back(plan_sp);
179   plan_sp->DidPop();
180   return plan_sp;
181 }
182 
183 // If the input plan is nullptr, discard all plans.  Otherwise make sure this
184 // plan is in the stack, and if so discard up to and including it.
185 void ThreadPlanStack::DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr) {
186   llvm::sys::ScopedWriter guard(m_stack_mutex);
187   int stack_size = m_plans.size();
188 
189   if (up_to_plan_ptr == nullptr) {
190     for (int i = stack_size - 1; i > 0; i--)
191       DiscardPlanNoLock();
192     return;
193   }
194 
195   bool found_it = false;
196   for (int i = stack_size - 1; i > 0; i--) {
197     if (m_plans[i].get() == up_to_plan_ptr) {
198       found_it = true;
199       break;
200     }
201   }
202 
203   if (found_it) {
204     bool last_one = false;
205     for (int i = stack_size - 1; i > 0 && !last_one; i--) {
206       if (GetCurrentPlanNoLock().get() == up_to_plan_ptr)
207         last_one = true;
208       DiscardPlanNoLock();
209     }
210   }
211 }
212 
213 void ThreadPlanStack::DiscardAllPlans() {
214   llvm::sys::ScopedWriter guard(m_stack_mutex);
215   int stack_size = m_plans.size();
216   for (int i = stack_size - 1; i > 0; i--) {
217     DiscardPlanNoLock();
218   }
219 }
220 
221 void ThreadPlanStack::DiscardConsultingControllingPlans() {
222   llvm::sys::ScopedWriter guard(m_stack_mutex);
223   while (true) {
224     int controlling_plan_idx;
225     bool discard = true;
226 
227     // Find the first controlling plan, see if it wants discarding, and if yes
228     // discard up to it.
229     for (controlling_plan_idx = m_plans.size() - 1; controlling_plan_idx >= 0;
230          controlling_plan_idx--) {
231       if (m_plans[controlling_plan_idx]->IsControllingPlan()) {
232         discard = m_plans[controlling_plan_idx]->OkayToDiscard();
233         break;
234       }
235     }
236 
237     // If the controlling plan doesn't want to get discarded, then we're done.
238     if (!discard)
239       return;
240 
241     // First pop all the dependent plans:
242     for (int i = m_plans.size() - 1; i > controlling_plan_idx; i--) {
243       DiscardPlanNoLock();
244     }
245 
246     // Now discard the controlling plan itself.
247     // The bottom-most plan never gets discarded.  "OkayToDiscard" for it
248     // means discard it's dependent plans, but not it...
249     if (controlling_plan_idx > 0) {
250       DiscardPlanNoLock();
251     }
252   }
253 }
254 
255 lldb::ThreadPlanSP ThreadPlanStack::GetCurrentPlan() const {
256   llvm::sys::ScopedReader guard(m_stack_mutex);
257   return GetCurrentPlanNoLock();
258 }
259 
260 lldb::ThreadPlanSP ThreadPlanStack::GetCurrentPlanNoLock() const {
261   assert(m_plans.size() != 0 && "There will always be a base plan.");
262   return m_plans.back();
263 }
264 
265 lldb::ThreadPlanSP ThreadPlanStack::GetCompletedPlan(bool skip_private) const {
266   llvm::sys::ScopedReader guard(m_stack_mutex);
267   if (m_completed_plans.empty())
268     return {};
269 
270   if (!skip_private)
271     return m_completed_plans.back();
272 
273   for (int i = m_completed_plans.size() - 1; i >= 0; i--) {
274     lldb::ThreadPlanSP completed_plan_sp;
275     completed_plan_sp = m_completed_plans[i];
276     if (!completed_plan_sp->GetPrivate())
277       return completed_plan_sp;
278   }
279   return {};
280 }
281 
282 lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx,
283                                                    bool skip_private) const {
284   llvm::sys::ScopedReader guard(m_stack_mutex);
285   uint32_t idx = 0;
286 
287   for (lldb::ThreadPlanSP plan_sp : m_plans) {
288     if (skip_private && plan_sp->GetPrivate())
289       continue;
290     if (idx == plan_idx)
291       return plan_sp;
292     idx++;
293   }
294   return {};
295 }
296 
297 lldb::ValueObjectSP ThreadPlanStack::GetReturnValueObject() const {
298   llvm::sys::ScopedReader guard(m_stack_mutex);
299   if (m_completed_plans.empty())
300     return {};
301 
302   for (int i = m_completed_plans.size() - 1; i >= 0; i--) {
303     lldb::ValueObjectSP return_valobj_sp;
304     return_valobj_sp = m_completed_plans[i]->GetReturnValueObject();
305     if (return_valobj_sp)
306       return return_valobj_sp;
307   }
308   return {};
309 }
310 
311 lldb::ExpressionVariableSP ThreadPlanStack::GetExpressionVariable() const {
312   llvm::sys::ScopedReader guard(m_stack_mutex);
313   if (m_completed_plans.empty())
314     return {};
315 
316   for (int i = m_completed_plans.size() - 1; i >= 0; i--) {
317     lldb::ExpressionVariableSP expression_variable_sp;
318     expression_variable_sp = m_completed_plans[i]->GetExpressionVariable();
319     if (expression_variable_sp)
320       return expression_variable_sp;
321   }
322   return {};
323 }
324 bool ThreadPlanStack::AnyPlans() const {
325   llvm::sys::ScopedReader guard(m_stack_mutex);
326   // There is always a base plan...
327   return m_plans.size() > 1;
328 }
329 
330 bool ThreadPlanStack::AnyCompletedPlans() const {
331   llvm::sys::ScopedReader guard(m_stack_mutex);
332   return !m_completed_plans.empty();
333 }
334 
335 bool ThreadPlanStack::AnyDiscardedPlans() const {
336   llvm::sys::ScopedReader guard(m_stack_mutex);
337   return !m_discarded_plans.empty();
338 }
339 
340 bool ThreadPlanStack::IsPlanDone(ThreadPlan *in_plan) const {
341   llvm::sys::ScopedReader guard(m_stack_mutex);
342   for (auto plan : m_completed_plans) {
343     if (plan.get() == in_plan)
344       return true;
345   }
346   return false;
347 }
348 
349 bool ThreadPlanStack::WasPlanDiscarded(ThreadPlan *in_plan) const {
350   llvm::sys::ScopedReader guard(m_stack_mutex);
351   for (auto plan : m_discarded_plans) {
352     if (plan.get() == in_plan)
353       return true;
354   }
355   return false;
356 }
357 
358 ThreadPlan *ThreadPlanStack::GetPreviousPlan(ThreadPlan *current_plan) const {
359   llvm::sys::ScopedReader guard(m_stack_mutex);
360   if (current_plan == nullptr)
361     return nullptr;
362 
363   // Look first in the completed plans, if the plan is here and there is
364   // a completed plan above it, return that.
365   int stack_size = m_completed_plans.size();
366   for (int i = stack_size - 1; i > 0; i--) {
367     if (current_plan == m_completed_plans[i].get())
368       return m_completed_plans[i - 1].get();
369   }
370 
371   // If this is the first completed plan, the previous one is the
372   // bottom of the regular plan stack.
373   if (stack_size > 0 && m_completed_plans[0].get() == current_plan) {
374     return GetCurrentPlanNoLock().get();
375   }
376 
377   // Otherwise look for it in the regular plans.
378   stack_size = m_plans.size();
379   for (int i = stack_size - 1; i > 0; i--) {
380     if (current_plan == m_plans[i].get())
381       return m_plans[i - 1].get();
382   }
383   return nullptr;
384 }
385 
386 ThreadPlan *ThreadPlanStack::GetInnermostExpression() const {
387   llvm::sys::ScopedReader guard(m_stack_mutex);
388   int stack_size = m_plans.size();
389 
390   for (int i = stack_size - 1; i > 0; i--) {
391     if (m_plans[i]->GetKind() == ThreadPlan::eKindCallFunction)
392       return m_plans[i].get();
393   }
394   return nullptr;
395 }
396 
397 void ThreadPlanStack::ClearThreadCache() {
398   llvm::sys::ScopedReader guard(m_stack_mutex);
399   for (lldb::ThreadPlanSP thread_plan_sp : m_plans)
400     thread_plan_sp->ClearThreadCache();
401 }
402 
403 void ThreadPlanStack::WillResume() {
404   llvm::sys::ScopedWriter guard(m_stack_mutex);
405   m_completed_plans.clear();
406   m_discarded_plans.clear();
407 }
408 
409 void ThreadPlanStackMap::Update(ThreadList &current_threads,
410                                 bool delete_missing,
411                                 bool check_for_new) {
412 
413   std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
414   // Now find all the new threads and add them to the map:
415   if (check_for_new) {
416     for (auto thread : current_threads.Threads()) {
417       lldb::tid_t cur_tid = thread->GetID();
418       if (!Find(cur_tid)) {
419         AddThread(*thread);
420         thread->QueueBasePlan(true);
421       }
422     }
423   }
424 
425   // If we aren't reaping missing threads at this point,
426   // we are done.
427   if (!delete_missing)
428     return;
429   // Otherwise scan for absent TID's.
430   std::vector<lldb::tid_t> missing_threads;
431   // If we are going to delete plans from the plan stack,
432   // then scan for absent TID's:
433   for (auto &thread_plans : m_plans_list) {
434     lldb::tid_t cur_tid = thread_plans.first;
435     ThreadSP thread_sp = current_threads.FindThreadByID(cur_tid);
436     if (!thread_sp)
437       missing_threads.push_back(cur_tid);
438   }
439   for (lldb::tid_t tid : missing_threads) {
440     RemoveTID(tid);
441   }
442 }
443 
444 void ThreadPlanStackMap::DumpPlans(Stream &strm,
445                                    lldb::DescriptionLevel desc_level,
446                                    bool internal, bool condense_if_trivial,
447                                    bool skip_unreported) {
448   std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
449   for (auto &elem : m_plans_list) {
450     lldb::tid_t tid = elem.first;
451     uint32_t index_id = 0;
452     ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid);
453 
454     if (skip_unreported) {
455       if (!thread_sp)
456         continue;
457     }
458     if (thread_sp)
459       index_id = thread_sp->GetIndexID();
460 
461     if (condense_if_trivial) {
462       if (!elem.second.AnyPlans() && !elem.second.AnyCompletedPlans() &&
463           !elem.second.AnyDiscardedPlans()) {
464         strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid);
465         strm.IndentMore();
466         strm.Indent();
467         strm.Printf("No active thread plans\n");
468         strm.IndentLess();
469         return;
470       }
471     }
472 
473     strm.Indent();
474     strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid);
475 
476     elem.second.DumpThreadPlans(strm, desc_level, internal);
477   }
478 }
479 
480 bool ThreadPlanStackMap::DumpPlansForTID(Stream &strm, lldb::tid_t tid,
481                                          lldb::DescriptionLevel desc_level,
482                                          bool internal,
483                                          bool condense_if_trivial,
484                                          bool skip_unreported) {
485   std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
486   uint32_t index_id = 0;
487   ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid);
488 
489   if (skip_unreported) {
490     if (!thread_sp) {
491       strm.Format("Unknown TID: {0}", tid);
492       return false;
493     }
494   }
495 
496   if (thread_sp)
497     index_id = thread_sp->GetIndexID();
498   ThreadPlanStack *stack = Find(tid);
499   if (!stack) {
500     strm.Format("Unknown TID: {0}\n", tid);
501     return false;
502   }
503 
504   if (condense_if_trivial) {
505     if (!stack->AnyPlans() && !stack->AnyCompletedPlans() &&
506         !stack->AnyDiscardedPlans()) {
507       strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid);
508       strm.IndentMore();
509       strm.Indent();
510       strm.Printf("No active thread plans\n");
511       strm.IndentLess();
512       return true;
513     }
514   }
515 
516   strm.Indent();
517   strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid);
518 
519   stack->DumpThreadPlans(strm, desc_level, internal);
520   return true;
521 }
522 
523 bool ThreadPlanStackMap::PrunePlansForTID(lldb::tid_t tid) {
524   // We only remove the plans for unreported TID's.
525   std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
526   ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid);
527   if (thread_sp)
528     return false;
529 
530   return RemoveTID(tid);
531 }
532