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 ¤t_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