blob: f1874136cad835a81eeda89ccaeaafdef1327f88 [file] [log] [blame]
Olivier Deprezf4ef2d02021-04-20 13:36:24 +02001//===-- 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
22namespace 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.
31class ThreadPlanStack {
32 friend class lldb_private::Thread;
33
34public:
35 ThreadPlanStack(const Thread &thread, bool make_empty = false);
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
98private:
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
117class ThreadPlanStackMap {
118public:
119 ThreadPlanStackMap(Process &process) : m_process(process) {}
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
126 void AddThread(Thread &thread) {
127 lldb::tid_t tid = thread.GetID();
128 m_plans_list.emplace(tid, thread);
129 }
130
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
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
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
165private:
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