1 //===-- ThreadPlanStack.h ---------------------------------------*- 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 #ifndef LLDB_TARGET_THREADPLANSTACK_H
10 #define LLDB_TARGET_THREADPLANSTACK_H
11 
12 #include <mutex>
13 #include <string>
14 #include <unordered_map>
15 #include <vector>
16 
17 #include "lldb/Target/Target.h"
18 #include "lldb/Target/Thread.h"
19 #include "lldb/lldb-private-forward.h"
20 #include "lldb/lldb-private.h"
21 
22 namespace lldb_private {
23 
24 // The ThreadPlans have a thread for use when they are asked all the ThreadPlan
25 // state machine questions, but they should never cache any pointers from their
26 // owning lldb_private::Thread.  That's because we want to be able to detach
27 // them from an owning thread, then reattach them by TID.
28 // The ThreadPlanStack holds the ThreadPlans for a given TID.  All its methods
29 // are private, and it should only be accessed through the owning thread.  When
30 // it is detached from a thread, all you can do is reattach it or delete it.
31 class ThreadPlanStack {
32   friend class lldb_private::Thread;
33 
34 public:
35   ThreadPlanStack(const Thread &thread, bool make_empty = false);
~ThreadPlanStack()36   ~ThreadPlanStack() {}
37 
38   enum StackKind { ePlans, eCompletedPlans, eDiscardedPlans };
39 
40   using PlanStack = std::vector<lldb::ThreadPlanSP>;
41 
42   void DumpThreadPlans(Stream &s, lldb::DescriptionLevel desc_level,
43                        bool include_internal) const;
44 
45   size_t CheckpointCompletedPlans();
46 
47   void RestoreCompletedPlanCheckpoint(size_t checkpoint);
48 
49   void DiscardCompletedPlanCheckpoint(size_t checkpoint);
50 
51   void ThreadDestroyed(Thread *thread);
52 
53   void EnableTracer(bool value, bool single_stepping);
54 
55   void SetTracer(lldb::ThreadPlanTracerSP &tracer_sp);
56 
57   void PushPlan(lldb::ThreadPlanSP new_plan_sp);
58 
59   lldb::ThreadPlanSP PopPlan();
60 
61   lldb::ThreadPlanSP DiscardPlan();
62 
63   // If the input plan is nullptr, discard all plans.  Otherwise make sure this
64   // plan is in the stack, and if so discard up to and including it.
65   void DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr);
66 
67   void DiscardAllPlans();
68 
69   void DiscardConsultingMasterPlans();
70 
71   lldb::ThreadPlanSP GetCurrentPlan() const;
72 
73   lldb::ThreadPlanSP GetCompletedPlan(bool skip_private = true) const;
74 
75   lldb::ThreadPlanSP GetPlanByIndex(uint32_t plan_idx,
76                                     bool skip_private = true) const;
77 
78   lldb::ValueObjectSP GetReturnValueObject() const;
79 
80   lldb::ExpressionVariableSP GetExpressionVariable() const;
81 
82   bool AnyPlans() const;
83 
84   bool AnyCompletedPlans() const;
85 
86   bool AnyDiscardedPlans() const;
87 
88   bool IsPlanDone(ThreadPlan *plan) const;
89 
90   bool WasPlanDiscarded(ThreadPlan *plan) const;
91 
92   ThreadPlan *GetPreviousPlan(ThreadPlan *current_plan) const;
93 
94   ThreadPlan *GetInnermostExpression() const;
95 
96   void WillResume();
97 
98 private:
99   const PlanStack &GetStackOfKind(ThreadPlanStack::StackKind kind) const;
100 
101   void PrintOneStack(Stream &s, llvm::StringRef stack_name,
102                      const PlanStack &stack, lldb::DescriptionLevel desc_level,
103                      bool include_internal) const;
104 
105   PlanStack m_plans;           ///< The stack of plans this thread is executing.
106   PlanStack m_completed_plans; ///< Plans that have been completed by this
107                                /// stop.  They get deleted when the thread
108                                /// resumes.
109   PlanStack m_discarded_plans; ///< Plans that have been discarded by this
110                                /// stop.  They get deleted when the thread
111                                /// resumes.
112   size_t m_completed_plan_checkpoint = 0; // Monotonically increasing token for
113                                           // completed plan checkpoints.
114   std::unordered_map<size_t, PlanStack> m_completed_plan_store;
115 };
116 
117 class ThreadPlanStackMap {
118 public:
ThreadPlanStackMap(Process & process)119   ThreadPlanStackMap(Process &process) : m_process(process) {}
~ThreadPlanStackMap()120   ~ThreadPlanStackMap() {}
121 
122   // Prune the map using the current_threads list.
123   void Update(ThreadList &current_threads, bool delete_missing,
124               bool check_for_new = true);
125 
AddThread(Thread & thread)126   void AddThread(Thread &thread) {
127     lldb::tid_t tid = thread.GetID();
128     m_plans_list.emplace(tid, thread);
129   }
130 
RemoveTID(lldb::tid_t tid)131   bool RemoveTID(lldb::tid_t tid) {
132     auto result = m_plans_list.find(tid);
133     if (result == m_plans_list.end())
134       return false;
135     result->second.ThreadDestroyed(nullptr);
136     m_plans_list.erase(result);
137     return true;
138   }
139 
Find(lldb::tid_t tid)140   ThreadPlanStack *Find(lldb::tid_t tid) {
141     auto result = m_plans_list.find(tid);
142     if (result == m_plans_list.end())
143       return nullptr;
144     else
145       return &result->second;
146   }
147 
Clear()148   void Clear() {
149     for (auto plan : m_plans_list)
150       plan.second.ThreadDestroyed(nullptr);
151     m_plans_list.clear();
152   }
153 
154   // Implements Process::DumpThreadPlans
155   void DumpPlans(Stream &strm, lldb::DescriptionLevel desc_level, bool internal,
156                  bool ignore_boring, bool skip_unreported);
157 
158   // Implements Process::DumpThreadPlansForTID
159   bool DumpPlansForTID(Stream &strm, lldb::tid_t tid,
160                        lldb::DescriptionLevel desc_level, bool internal,
161                        bool ignore_boring, bool skip_unreported);
162 
163   bool PrunePlansForTID(lldb::tid_t tid);
164 
165 private:
166   Process &m_process;
167   using PlansList = std::unordered_map<lldb::tid_t, ThreadPlanStack>;
168   PlansList m_plans_list;
169 };
170 
171 } // namespace lldb_private
172 
173 #endif // LLDB_TARGET_THREADPLANSTACK_H
174