LLDB  mainline
ThreadPlanStack.cpp
Go to the documentation of this file.
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 
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::EnableTracer(bool value, bool single_stepping) {
128  for (ThreadPlanSP plan : m_plans) {
129  if (plan->GetThreadPlanTracer()) {
130  plan->GetThreadPlanTracer()->EnableTracing(value);
131  plan->GetThreadPlanTracer()->EnableSingleStep(single_stepping);
132  }
133  }
134 }
135 
136 void ThreadPlanStack::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) {
137  for (ThreadPlanSP plan : m_plans)
138  plan->SetThreadPlanTracer(tracer_sp);
139 }
140 
141 void ThreadPlanStack::PushPlan(lldb::ThreadPlanSP new_plan_sp) {
142  // If the thread plan doesn't already have a tracer, give it its parent's
143  // tracer:
144  // The first plan has to be a base plan:
145  assert((m_plans.size() > 0 || new_plan_sp->IsBasePlan()) &&
146  "Zeroth plan must be a base plan");
147 
148  if (!new_plan_sp->GetThreadPlanTracer()) {
149  assert(!m_plans.empty());
150  new_plan_sp->SetThreadPlanTracer(m_plans.back()->GetThreadPlanTracer());
151  }
152  m_plans.push_back(new_plan_sp);
153  new_plan_sp->DidPush();
154 }
155 
156 lldb::ThreadPlanSP ThreadPlanStack::PopPlan() {
157  assert(m_plans.size() > 1 && "Can't pop the base thread plan");
158 
159  lldb::ThreadPlanSP plan_sp = std::move(m_plans.back());
160  m_completed_plans.push_back(plan_sp);
161  plan_sp->WillPop();
162  m_plans.pop_back();
163  return plan_sp;
164 }
165 
166 lldb::ThreadPlanSP ThreadPlanStack::DiscardPlan() {
167  assert(m_plans.size() > 1 && "Can't discard the base thread plan");
168 
169  lldb::ThreadPlanSP plan_sp = std::move(m_plans.back());
170  m_discarded_plans.push_back(plan_sp);
171  plan_sp->WillPop();
172  m_plans.pop_back();
173  return plan_sp;
174 }
175 
176 // If the input plan is nullptr, discard all plans. Otherwise make sure this
177 // plan is in the stack, and if so discard up to and including it.
178 void ThreadPlanStack::DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr) {
179  int stack_size = m_plans.size();
180 
181  if (up_to_plan_ptr == nullptr) {
182  for (int i = stack_size - 1; i > 0; i--)
183  DiscardPlan();
184  return;
185  }
186 
187  bool found_it = false;
188  for (int i = stack_size - 1; i > 0; i--) {
189  if (m_plans[i].get() == up_to_plan_ptr) {
190  found_it = true;
191  break;
192  }
193  }
194 
195  if (found_it) {
196  bool last_one = false;
197  for (int i = stack_size - 1; i > 0 && !last_one; i--) {
198  if (GetCurrentPlan().get() == up_to_plan_ptr)
199  last_one = true;
200  DiscardPlan();
201  }
202  }
203 }
204 
205 void ThreadPlanStack::DiscardAllPlans() {
206  int stack_size = m_plans.size();
207  for (int i = stack_size - 1; i > 0; i--) {
208  DiscardPlan();
209  }
210  return;
211 }
212 
213 void ThreadPlanStack::DiscardConsultingMasterPlans() {
214  while (true) {
215  int master_plan_idx;
216  bool discard = true;
217 
218  // Find the first master plan, see if it wants discarding, and if yes
219  // discard up to it.
220  for (master_plan_idx = m_plans.size() - 1; master_plan_idx >= 0;
221  master_plan_idx--) {
222  if (m_plans[master_plan_idx]->IsMasterPlan()) {
223  discard = m_plans[master_plan_idx]->OkayToDiscard();
224  break;
225  }
226  }
227 
228  // If the master plan doesn't want to get discarded, then we're done.
229  if (!discard)
230  return;
231 
232  // First pop all the dependent plans:
233  for (int i = m_plans.size() - 1; i > master_plan_idx; i--) {
234  DiscardPlan();
235  }
236 
237  // Now discard the master plan itself.
238  // The bottom-most plan never gets discarded. "OkayToDiscard" for it
239  // means discard it's dependent plans, but not it...
240  if (master_plan_idx > 0) {
241  DiscardPlan();
242  }
243  }
244 }
245 
246 lldb::ThreadPlanSP ThreadPlanStack::GetCurrentPlan() const {
247  assert(m_plans.size() != 0 && "There will always be a base plan.");
248  return m_plans.back();
249 }
250 
251 lldb::ThreadPlanSP ThreadPlanStack::GetCompletedPlan(bool skip_private) const {
252  if (m_completed_plans.empty())
253  return {};
254 
255  if (!skip_private)
256  return m_completed_plans.back();
257 
258  for (int i = m_completed_plans.size() - 1; i >= 0; i--) {
259  lldb::ThreadPlanSP completed_plan_sp;
260  completed_plan_sp = m_completed_plans[i];
261  if (!completed_plan_sp->GetPrivate())
262  return completed_plan_sp;
263  }
264  return {};
265 }
266 
267 lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx,
268  bool skip_private) const {
269  uint32_t idx = 0;
270 
271  for (lldb::ThreadPlanSP plan_sp : m_plans) {
272  if (skip_private && plan_sp->GetPrivate())
273  continue;
274  if (idx == plan_idx)
275  return plan_sp;
276  idx++;
277  }
278  return {};
279 }
280 
281 lldb::ValueObjectSP ThreadPlanStack::GetReturnValueObject() const {
282  if (m_completed_plans.empty())
283  return {};
284 
285  for (int i = m_completed_plans.size() - 1; i >= 0; i--) {
286  lldb::ValueObjectSP return_valobj_sp;
287  return_valobj_sp = m_completed_plans[i]->GetReturnValueObject();
288  if (return_valobj_sp)
289  return return_valobj_sp;
290  }
291  return {};
292 }
293 
294 lldb::ExpressionVariableSP ThreadPlanStack::GetExpressionVariable() const {
295  if (m_completed_plans.empty())
296  return {};
297 
298  for (int i = m_completed_plans.size() - 1; i >= 0; i--) {
299  lldb::ExpressionVariableSP expression_variable_sp;
300  expression_variable_sp = m_completed_plans[i]->GetExpressionVariable();
301  if (expression_variable_sp)
302  return expression_variable_sp;
303  }
304  return {};
305 }
306 bool ThreadPlanStack::AnyPlans() const {
307  // There is always a base plan...
308  return m_plans.size() > 1;
309 }
310 
311 bool ThreadPlanStack::AnyCompletedPlans() const {
312  return !m_completed_plans.empty();
313 }
314 
315 bool ThreadPlanStack::AnyDiscardedPlans() const {
316  return !m_discarded_plans.empty();
317 }
318 
319 bool ThreadPlanStack::IsPlanDone(ThreadPlan *in_plan) const {
320  for (auto plan : m_completed_plans) {
321  if (plan.get() == in_plan)
322  return true;
323  }
324  return false;
325 }
326 
327 bool ThreadPlanStack::WasPlanDiscarded(ThreadPlan *in_plan) const {
328  for (auto plan : m_discarded_plans) {
329  if (plan.get() == in_plan)
330  return true;
331  }
332  return false;
333 }
334 
335 ThreadPlan *ThreadPlanStack::GetPreviousPlan(ThreadPlan *current_plan) const {
336  if (current_plan == nullptr)
337  return nullptr;
338 
339  // Look first in the completed plans, if the plan is here and there is
340  // a completed plan above it, return that.
341  int stack_size = m_completed_plans.size();
342  for (int i = stack_size - 1; i > 0; i--) {
343  if (current_plan == m_completed_plans[i].get())
344  return m_completed_plans[i - 1].get();
345  }
346 
347  // If this is the first completed plan, the previous one is the
348  // bottom of the regular plan stack.
349  if (stack_size > 0 && m_completed_plans[0].get() == current_plan) {
350  return GetCurrentPlan().get();
351  }
352 
353  // Otherwise look for it in the regular plans.
354  stack_size = m_plans.size();
355  for (int i = stack_size - 1; i > 0; i--) {
356  if (current_plan == m_plans[i].get())
357  return m_plans[i - 1].get();
358  }
359  return nullptr;
360 }
361 
362 ThreadPlan *ThreadPlanStack::GetInnermostExpression() const {
363  int stack_size = m_plans.size();
364 
365  for (int i = stack_size - 1; i > 0; i--) {
366  if (m_plans[i]->GetKind() == ThreadPlan::eKindCallFunction)
367  return m_plans[i].get();
368  }
369  return nullptr;
370 }
371 
372 void ThreadPlanStack::WillResume() {
373  m_completed_plans.clear();
374  m_discarded_plans.clear();
375 }
376 
378 ThreadPlanStack::GetStackOfKind(ThreadPlanStack::StackKind kind) const {
379  switch (kind) {
380  case ePlans:
381  return m_plans;
382  case eCompletedPlans:
383  return m_completed_plans;
384  case eDiscardedPlans:
385  return m_discarded_plans;
386  }
387  llvm_unreachable("Invalid StackKind value");
388 }
389 
390 void ThreadPlanStackMap::Update(ThreadList &current_threads,
391  bool delete_missing,
392  bool check_for_new) {
393 
394  // Now find all the new threads and add them to the map:
395  if (check_for_new) {
396  for (auto thread : current_threads.Threads()) {
397  lldb::tid_t cur_tid = thread->GetID();
398  if (!Find(cur_tid)) {
399  AddThread(*thread.get());
400  thread->QueueFundamentalPlan(true);
401  }
402  }
403  }
404 
405  // If we aren't reaping missing threads at this point,
406  // we are done.
407  if (!delete_missing)
408  return;
409  // Otherwise scan for absent TID's.
410  std::vector<lldb::tid_t> missing_threads;
411  // If we are going to delete plans from the plan stack,
412  // then scan for absent TID's:
413  for (auto thread_plans : m_plans_list) {
414  lldb::tid_t cur_tid = thread_plans.first;
415  ThreadSP thread_sp = current_threads.FindThreadByID(cur_tid);
416  if (!thread_sp)
417  missing_threads.push_back(cur_tid);
418  }
419  for (lldb::tid_t tid : missing_threads) {
420  RemoveTID(tid);
421  }
422 }
423 
424 void ThreadPlanStackMap::DumpPlans(Stream &strm,
425  lldb::DescriptionLevel desc_level,
426  bool internal, bool condense_if_trivial,
427  bool skip_unreported) {
428  for (auto elem : m_plans_list) {
429  lldb::tid_t tid = elem.first;
430  uint32_t index_id = 0;
431  ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid);
432 
433  if (skip_unreported) {
434  if (!thread_sp)
435  continue;
436  }
437  if (thread_sp)
438  index_id = thread_sp->GetIndexID();
439 
440  if (condense_if_trivial) {
441  if (!elem.second.AnyPlans() && !elem.second.AnyCompletedPlans() &&
442  !elem.second.AnyDiscardedPlans()) {
443  strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid);
444  strm.IndentMore();
445  strm.Indent();
446  strm.Printf("No active thread plans\n");
447  strm.IndentLess();
448  return;
449  }
450  }
451 
452  strm.Indent();
453  strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid);
454 
455  elem.second.DumpThreadPlans(strm, desc_level, internal);
456  }
457 }
458 
459 bool ThreadPlanStackMap::DumpPlansForTID(Stream &strm, lldb::tid_t tid,
460  lldb::DescriptionLevel desc_level,
461  bool internal,
462  bool condense_if_trivial,
463  bool skip_unreported) {
464  uint32_t index_id = 0;
465  ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid);
466 
467  if (skip_unreported) {
468  if (!thread_sp) {
469  strm.Format("Unknown TID: {0}", tid);
470  return false;
471  }
472  }
473 
474  if (thread_sp)
475  index_id = thread_sp->GetIndexID();
476  ThreadPlanStack *stack = Find(tid);
477  if (!stack) {
478  strm.Format("Unknown TID: {0}\n", tid);
479  return false;
480  }
481 
482  if (condense_if_trivial) {
483  if (!stack->AnyPlans() && !stack->AnyCompletedPlans() &&
484  !stack->AnyDiscardedPlans()) {
485  strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid);
486  strm.IndentMore();
487  strm.Indent();
488  strm.Printf("No active thread plans\n");
489  strm.IndentLess();
490  return true;
491  }
492  }
493 
494  strm.Indent();
495  strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid);
496 
497  stack->DumpThreadPlans(strm, desc_level, internal);
498  return true;
499 }
500 
501 bool ThreadPlanStackMap::PrunePlansForTID(lldb::tid_t tid) {
502  // We only remove the plans for unreported TID's.
503  ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid);
504  if (thread_sp)
505  return false;
506 
507  return RemoveTID(tid);
508 }
void IndentMore(unsigned amount=2)
Increment the current indentation level.
Definition: Stream.cpp:168
A class that represents a running process on the host machine.
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
void IndentLess(unsigned amount=2)
Decrement the current indentation level.
Definition: Stream.cpp:171
virtual ThreadIterable Threads()
void DumpThreadPlans(Stream &s, lldb::DescriptionLevel desc_level, bool include_internal) const
DescriptionLevel
Description levels for "void GetDescription(Stream *, DescriptionLevel)" calls.
void Format(const char *format, Args &&... args)
Definition: Stream.h:309
lldb::ThreadSP FindThreadByID(lldb::tid_t tid, bool can_update=true)
Definition: ThreadList.cpp:102
size_t Indent(llvm::StringRef s="")
Indent the current line in the stream.
Definition: Stream.cpp:130
size_t EOL()
Output and End of Line character to the stream.
Definition: Stream.cpp:128
uint64_t tid_t
Definition: lldb-types.h:86
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
Definition: SBAddress.h:15
std::vector< lldb::ThreadPlanSP > PlanStack
static void PrintPlanElement(Stream &s, const ThreadPlanSP &plan, lldb::DescriptionLevel desc_level, int32_t elem_idx)