1 | //===-- ThreadPlan.cpp ----------------------------------------------------===// |
---|---|
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 | #include "lldb/Target/ThreadPlan.h" |
10 | #include "lldb/Core/Debugger.h" |
11 | #include "lldb/Target/Process.h" |
12 | #include "lldb/Target/RegisterContext.h" |
13 | #include "lldb/Target/Target.h" |
14 | #include "lldb/Target/Thread.h" |
15 | #include "lldb/Utility/LLDBLog.h" |
16 | #include "lldb/Utility/Log.h" |
17 | #include "lldb/Utility/State.h" |
18 | |
19 | using namespace lldb; |
20 | using namespace lldb_private; |
21 | |
22 | // ThreadPlan constructor |
23 | ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, |
24 | Vote report_stop_vote, Vote report_run_vote) |
25 | : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), |
26 | m_report_stop_vote(report_stop_vote), m_report_run_vote(report_run_vote), |
27 | m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false), |
28 | m_thread(&thread), m_kind(kind), m_name(name), m_plan_complete_mutex(), |
29 | m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false), |
30 | m_plan_private(false), m_okay_to_discard(true), |
31 | m_is_controlling_plan(false), m_plan_succeeded(true) { |
32 | SetID(GetNextID()); |
33 | } |
34 | |
35 | // Destructor |
36 | ThreadPlan::~ThreadPlan() = default; |
37 | |
38 | Target &ThreadPlan::GetTarget() { return m_process.GetTarget(); } |
39 | |
40 | const Target &ThreadPlan::GetTarget() const { return m_process.GetTarget(); } |
41 | |
42 | Thread &ThreadPlan::GetThread() { |
43 | if (m_thread) |
44 | return *m_thread; |
45 | |
46 | ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid: m_tid); |
47 | m_thread = thread_sp.get(); |
48 | return *m_thread; |
49 | } |
50 | |
51 | bool ThreadPlan::PlanExplainsStop(Event *event_ptr) { |
52 | if (m_cached_plan_explains_stop == eLazyBoolCalculate) { |
53 | bool actual_value = DoPlanExplainsStop(event_ptr); |
54 | CachePlanExplainsStop(does_explain: actual_value); |
55 | return actual_value; |
56 | } else { |
57 | return m_cached_plan_explains_stop == eLazyBoolYes; |
58 | } |
59 | } |
60 | |
61 | bool ThreadPlan::IsPlanComplete() { |
62 | std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); |
63 | return m_plan_complete; |
64 | } |
65 | |
66 | void ThreadPlan::SetPlanComplete(bool success) { |
67 | std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); |
68 | m_plan_complete = true; |
69 | m_plan_succeeded = success; |
70 | } |
71 | |
72 | bool ThreadPlan::MischiefManaged() { |
73 | std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); |
74 | // Mark the plan is complete, but don't override the success flag. |
75 | m_plan_complete = true; |
76 | return true; |
77 | } |
78 | |
79 | Vote ThreadPlan::ShouldReportStop(Event *event_ptr) { |
80 | Log *log = GetLog(mask: LLDBLog::Step); |
81 | |
82 | if (m_report_stop_vote == eVoteNoOpinion) { |
83 | ThreadPlan *prev_plan = GetPreviousPlan(); |
84 | if (prev_plan) { |
85 | Vote prev_vote = prev_plan->ShouldReportStop(event_ptr); |
86 | LLDB_LOG(log, "returning previous thread plan vote: {0}", prev_vote); |
87 | return prev_vote; |
88 | } |
89 | } |
90 | LLDB_LOG(log, "Returning vote: {0}", m_report_stop_vote); |
91 | return m_report_stop_vote; |
92 | } |
93 | |
94 | Vote ThreadPlan::ShouldReportRun(Event *event_ptr) { |
95 | if (m_report_run_vote == eVoteNoOpinion) { |
96 | ThreadPlan *prev_plan = GetPreviousPlan(); |
97 | if (prev_plan) |
98 | return prev_plan->ShouldReportRun(event_ptr); |
99 | } |
100 | return m_report_run_vote; |
101 | } |
102 | |
103 | void ThreadPlan::ClearThreadCache() { m_thread = nullptr; } |
104 | |
105 | bool ThreadPlan::StopOthers() { |
106 | ThreadPlan *prev_plan; |
107 | prev_plan = GetPreviousPlan(); |
108 | return (prev_plan == nullptr) ? false : prev_plan->StopOthers(); |
109 | } |
110 | |
111 | void ThreadPlan::SetStopOthers(bool new_value) { |
112 | // SetStopOthers doesn't work up the hierarchy. You have to set the explicit |
113 | // ThreadPlan you want to affect. |
114 | } |
115 | |
116 | bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) { |
117 | m_cached_plan_explains_stop = eLazyBoolCalculate; |
118 | |
119 | if (current_plan) { |
120 | Log *log = GetLog(mask: LLDBLog::Step); |
121 | |
122 | if (log) { |
123 | RegisterContext *reg_ctx = GetThread().GetRegisterContext().get(); |
124 | assert(reg_ctx); |
125 | addr_t pc = reg_ctx->GetPC(); |
126 | addr_t sp = reg_ctx->GetSP(); |
127 | addr_t fp = reg_ctx->GetFP(); |
128 | LLDB_LOGF( |
129 | log, |
130 | "%s Thread #%u (0x%p): tid = 0x%4.4"PRIx64 ", pc = 0x%8.8"PRIx64 |
131 | ", sp = 0x%8.8"PRIx64 ", fp = 0x%8.8"PRIx64 ", " |
132 | "plan = '%s', state = %s, stop others = %d", |
133 | __FUNCTION__, GetThread().GetIndexID(), |
134 | static_cast<void *>(&GetThread()), m_tid, static_cast<uint64_t>(pc), |
135 | static_cast<uint64_t>(sp), static_cast<uint64_t>(fp), m_name.c_str(), |
136 | StateAsCString(resume_state), StopOthers()); |
137 | } |
138 | } |
139 | bool success = DoWillResume(resume_state, current_plan); |
140 | ClearThreadCache(); // We don't cache the thread pointer over resumes. This |
141 | // Thread might go away, and another Thread represent |
142 | // the same underlying object on a later stop. |
143 | return success; |
144 | } |
145 | |
146 | lldb::user_id_t ThreadPlan::GetNextID() { |
147 | static uint32_t g_nextPlanID = 0; |
148 | return ++g_nextPlanID; |
149 | } |
150 | |
151 | void ThreadPlan::DidPush() {} |
152 | |
153 | void ThreadPlan::DidPop() {} |
154 | |
155 | bool ThreadPlan::OkayToDiscard() { |
156 | return IsControllingPlan() ? m_okay_to_discard : true; |
157 | } |
158 | |
159 | lldb::StateType ThreadPlan::RunState() { |
160 | if (m_tracer_sp && m_tracer_sp->TracingEnabled()) |
161 | return eStateStepping; |
162 | else |
163 | return GetPlanRunState(); |
164 | } |
165 | |
166 | bool ThreadPlan::IsUsuallyUnexplainedStopReason(lldb::StopReason reason) { |
167 | switch (reason) { |
168 | case eStopReasonWatchpoint: |
169 | case eStopReasonSignal: |
170 | case eStopReasonException: |
171 | case eStopReasonExec: |
172 | case eStopReasonThreadExiting: |
173 | case eStopReasonInstrumentation: |
174 | case eStopReasonFork: |
175 | case eStopReasonVFork: |
176 | case eStopReasonVForkDone: |
177 | case eStopReasonInterrupt: |
178 | return true; |
179 | default: |
180 | return false; |
181 | } |
182 | } |
183 | |
184 | // ThreadPlanNull |
185 | |
186 | ThreadPlanNull::ThreadPlanNull(Thread &thread) |
187 | : ThreadPlan(ThreadPlan::eKindNull, "Null Thread Plan", thread, |
188 | eVoteNoOpinion, eVoteNoOpinion) {} |
189 | |
190 | ThreadPlanNull::~ThreadPlanNull() = default; |
191 | |
192 | void ThreadPlanNull::GetDescription(Stream *s, lldb::DescriptionLevel level) { |
193 | s->PutCString(cstr: "Null thread plan - thread has been destroyed."); |
194 | } |
195 | |
196 | bool ThreadPlanNull::ValidatePlan(Stream *error) { |
197 | #ifdef LLDB_CONFIGURATION_DEBUG |
198 | fprintf(stderr, |
199 | format: "error: %s called on thread that has been destroyed (tid = 0x%"PRIx64 |
200 | ", ptid = 0x%"PRIx64 ")", |
201 | LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); |
202 | #else |
203 | Log *log = GetLog(LLDBLog::Thread); |
204 | if (log) |
205 | log->Error("%s called on thread that has been destroyed (tid = 0x%"PRIx64 |
206 | ", ptid = 0x%"PRIx64 ")", |
207 | LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); |
208 | #endif |
209 | return true; |
210 | } |
211 | |
212 | bool ThreadPlanNull::ShouldStop(Event *event_ptr) { |
213 | #ifdef LLDB_CONFIGURATION_DEBUG |
214 | fprintf(stderr, |
215 | format: "error: %s called on thread that has been destroyed (tid = 0x%"PRIx64 |
216 | ", ptid = 0x%"PRIx64 ")", |
217 | LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); |
218 | #else |
219 | Log *log = GetLog(LLDBLog::Thread); |
220 | if (log) |
221 | log->Error("%s called on thread that has been destroyed (tid = 0x%"PRIx64 |
222 | ", ptid = 0x%"PRIx64 ")", |
223 | LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); |
224 | #endif |
225 | return true; |
226 | } |
227 | |
228 | bool ThreadPlanNull::WillStop() { |
229 | #ifdef LLDB_CONFIGURATION_DEBUG |
230 | fprintf(stderr, |
231 | format: "error: %s called on thread that has been destroyed (tid = 0x%"PRIx64 |
232 | ", ptid = 0x%"PRIx64 ")", |
233 | LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); |
234 | #else |
235 | Log *log = GetLog(LLDBLog::Thread); |
236 | if (log) |
237 | log->Error("%s called on thread that has been destroyed (tid = 0x%"PRIx64 |
238 | ", ptid = 0x%"PRIx64 ")", |
239 | LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); |
240 | #endif |
241 | return true; |
242 | } |
243 | |
244 | bool ThreadPlanNull::DoPlanExplainsStop(Event *event_ptr) { |
245 | #ifdef LLDB_CONFIGURATION_DEBUG |
246 | fprintf(stderr, |
247 | format: "error: %s called on thread that has been destroyed (tid = 0x%"PRIx64 |
248 | ", ptid = 0x%"PRIx64 ")", |
249 | LLVM_PRETTY_FUNCTION, GetThread().GetID(), GetThread().GetProtocolID()); |
250 | #else |
251 | Log *log = GetLog(LLDBLog::Thread); |
252 | if (log) |
253 | log->Error("%s called on thread that has been destroyed (tid = 0x%"PRIx64 |
254 | ", ptid = 0x%"PRIx64 ")", |
255 | LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); |
256 | #endif |
257 | return true; |
258 | } |
259 | |
260 | // The null plan is never done. |
261 | bool ThreadPlanNull::MischiefManaged() { |
262 | // The null plan is never done. |
263 | #ifdef LLDB_CONFIGURATION_DEBUG |
264 | fprintf(stderr, |
265 | format: "error: %s called on thread that has been destroyed (tid = 0x%"PRIx64 |
266 | ", ptid = 0x%"PRIx64 ")", |
267 | LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); |
268 | #else |
269 | Log *log = GetLog(LLDBLog::Thread); |
270 | if (log) |
271 | log->Error("%s called on thread that has been destroyed (tid = 0x%"PRIx64 |
272 | ", ptid = 0x%"PRIx64 ")", |
273 | LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); |
274 | #endif |
275 | return false; |
276 | } |
277 | |
278 | lldb::StateType ThreadPlanNull::GetPlanRunState() { |
279 | // Not sure what to return here. This is a dead thread. |
280 | #ifdef LLDB_CONFIGURATION_DEBUG |
281 | fprintf(stderr, |
282 | format: "error: %s called on thread that has been destroyed (tid = 0x%"PRIx64 |
283 | ", ptid = 0x%"PRIx64 ")", |
284 | LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); |
285 | #else |
286 | Log *log = GetLog(LLDBLog::Thread); |
287 | if (log) |
288 | log->Error("%s called on thread that has been destroyed (tid = 0x%"PRIx64 |
289 | ", ptid = 0x%"PRIx64 ")", |
290 | LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); |
291 | #endif |
292 | return eStateRunning; |
293 | } |
294 |
Definitions
- ThreadPlan
- ~ThreadPlan
- GetTarget
- GetTarget
- GetThread
- PlanExplainsStop
- IsPlanComplete
- SetPlanComplete
- MischiefManaged
- ShouldReportStop
- ShouldReportRun
- ClearThreadCache
- StopOthers
- SetStopOthers
- WillResume
- GetNextID
- DidPush
- DidPop
- OkayToDiscard
- RunState
- IsUsuallyUnexplainedStopReason
- ThreadPlanNull
- ~ThreadPlanNull
- GetDescription
- ValidatePlan
- ShouldStop
- WillStop
- DoPlanExplainsStop
- MischiefManaged
Learn to use CMake with our Intro Training
Find out more