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::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 }
lldb_private::Stream::IndentLess
void IndentLess(unsigned amount=2)
Decrement the current indentation level.
Definition: Stream.cpp:171
lldb_private::Stream::Format
void Format(const char *format, Args &&... args)
Definition: Stream.h:309
lldb_private::ThreadPlanStack::AnyPlans
bool AnyPlans() const
Definition: ThreadPlanStack.cpp:292
lldb_private::ThreadPlanNull
Definition: ThreadPlan.h:564
ThreadPlanStack.h
lldb_private::Stream
Definition: Stream.h:28
Process.h
Target.h
lldb_private::ThreadPlan
Definition: ThreadPlan.h:282
lldb_private::ThreadList::FindThreadByID
lldb::ThreadSP FindThreadByID(lldb::tid_t tid, bool can_update=true)
Definition: ThreadList.cpp:102
lldb_private::Stream::Indent
size_t Indent(llvm::StringRef s="")
Indent the current line in the stream.
Definition: Stream.cpp:130
Log.h
lldb_private::Thread
Definition: Thread.h:62
lldb_private::ThreadPlanStack::PlanStack
std::vector< lldb::ThreadPlanSP > PlanStack
Definition: ThreadPlanStack.h:38
lldb_private::ThreadList
Definition: ThreadList.h:26
lldb_private::ThreadCollection::Threads
virtual ThreadIterable Threads()
Definition: ThreadCollection.h:46
PrintPlanElement
static void PrintPlanElement(Stream &s, const ThreadPlanSP &plan, lldb::DescriptionLevel desc_level, int32_t elem_idx)
Definition: ThreadPlanStack.cpp:19
Thread.h
ThreadPlan.h
uint32_t
lldb_private::ThreadPlanStack::AnyDiscardedPlans
bool AnyDiscardedPlans() const
Definition: ThreadPlanStack.cpp:301
lldb_private::Stream::IndentMore
void IndentMore(unsigned amount=2)
Increment the current indentation level.
Definition: Stream.cpp:168
lldb_private::Stream::EOL
size_t EOL()
Output and End of Line character to the stream.
Definition: Stream.cpp:128
lldb_private::ThreadPlanStack::DumpThreadPlans
void DumpThreadPlans(Stream &s, lldb::DescriptionLevel desc_level, bool include_internal) const
Definition: ThreadPlanStack.cpp:39
lldb_private::ThreadPlanStack::AnyCompletedPlans
bool AnyCompletedPlans() const
Definition: ThreadPlanStack.cpp:297
lldb_private::Stream::Printf
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
lldb_private::ThreadPlanStack
Definition: ThreadPlanStack.h:31
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
lldb_private::ThreadPlan::ClearThreadCache
void ClearThreadCache()
Clear the Thread* cache.
Definition: ThreadPlan.cpp:102
lldb
Definition: SBAddress.h:15
lldb::DescriptionLevel
DescriptionLevel
Description levels for "void GetDescription(Stream *, DescriptionLevel)" calls.
Definition: lldb-enumerations.h:207
lldb::tid_t
uint64_t tid_t
Definition: lldb-types.h:86