1cfca06d7SDimitry Andric //===-- ThreadPlan.cpp ----------------------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste
9e81d9d49SDimitry Andric #include "lldb/Target/ThreadPlan.h"
10f034231aSEd Maste #include "lldb/Core/Debugger.h"
11f034231aSEd Maste #include "lldb/Target/Process.h"
1214f1b3e8SDimitry Andric #include "lldb/Target/RegisterContext.h"
13f034231aSEd Maste #include "lldb/Target/Target.h"
1414f1b3e8SDimitry Andric #include "lldb/Target/Thread.h"
15145449b1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
1674a628f7SDimitry Andric #include "lldb/Utility/Log.h"
1794994d37SDimitry Andric #include "lldb/Utility/State.h"
18f034231aSEd Maste
19f034231aSEd Maste using namespace lldb;
20f034231aSEd Maste using namespace lldb_private;
21f034231aSEd Maste
22f034231aSEd Maste // ThreadPlan constructor
ThreadPlan(ThreadPlanKind kind,const char * name,Thread & thread,Vote report_stop_vote,Vote report_run_vote)2314f1b3e8SDimitry Andric ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread,
24344a3780SDimitry Andric Vote report_stop_vote, Vote report_run_vote)
25cfca06d7SDimitry Andric : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
26344a3780SDimitry Andric m_report_stop_vote(report_stop_vote), m_report_run_vote(report_run_vote),
2794994d37SDimitry Andric m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false),
28cfca06d7SDimitry Andric m_thread(&thread), m_kind(kind), m_name(name), m_plan_complete_mutex(),
2914f1b3e8SDimitry Andric m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false),
30c0981da4SDimitry Andric m_plan_private(false), m_okay_to_discard(true),
31c0981da4SDimitry Andric m_is_controlling_plan(false), m_plan_succeeded(true) {
32f034231aSEd Maste SetID(GetNextID());
33f034231aSEd Maste }
34f034231aSEd Maste
35f034231aSEd Maste // Destructor
36e81d9d49SDimitry Andric ThreadPlan::~ThreadPlan() = default;
37f034231aSEd Maste
GetTarget()38cfca06d7SDimitry Andric Target &ThreadPlan::GetTarget() { return m_process.GetTarget(); }
39cfca06d7SDimitry Andric
GetTarget() const40cfca06d7SDimitry Andric const Target &ThreadPlan::GetTarget() const { return m_process.GetTarget(); }
41cfca06d7SDimitry Andric
GetThread()42cfca06d7SDimitry Andric Thread &ThreadPlan::GetThread() {
43cfca06d7SDimitry Andric if (m_thread)
44cfca06d7SDimitry Andric return *m_thread;
45cfca06d7SDimitry Andric
46cfca06d7SDimitry Andric ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid);
47cfca06d7SDimitry Andric m_thread = thread_sp.get();
48cfca06d7SDimitry Andric return *m_thread;
49cfca06d7SDimitry Andric }
50cfca06d7SDimitry Andric
PlanExplainsStop(Event * event_ptr)5114f1b3e8SDimitry Andric bool ThreadPlan::PlanExplainsStop(Event *event_ptr) {
5214f1b3e8SDimitry Andric if (m_cached_plan_explains_stop == eLazyBoolCalculate) {
53f034231aSEd Maste bool actual_value = DoPlanExplainsStop(event_ptr);
54344a3780SDimitry Andric CachePlanExplainsStop(actual_value);
55f034231aSEd Maste return actual_value;
5614f1b3e8SDimitry Andric } else {
57f034231aSEd Maste return m_cached_plan_explains_stop == eLazyBoolYes;
58f034231aSEd Maste }
59f034231aSEd Maste }
60f034231aSEd Maste
IsPlanComplete()6114f1b3e8SDimitry Andric bool ThreadPlan::IsPlanComplete() {
62f3fbd1c0SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex);
63f034231aSEd Maste return m_plan_complete;
64f034231aSEd Maste }
65f034231aSEd Maste
SetPlanComplete(bool success)6614f1b3e8SDimitry Andric void ThreadPlan::SetPlanComplete(bool success) {
67f3fbd1c0SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex);
68f034231aSEd Maste m_plan_complete = true;
69f034231aSEd Maste m_plan_succeeded = success;
70f034231aSEd Maste }
71f034231aSEd Maste
MischiefManaged()7214f1b3e8SDimitry Andric bool ThreadPlan::MischiefManaged() {
73f3fbd1c0SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex);
74f034231aSEd Maste // Mark the plan is complete, but don't override the success flag.
75f034231aSEd Maste m_plan_complete = true;
76f034231aSEd Maste return true;
77f034231aSEd Maste }
78f034231aSEd Maste
ShouldReportStop(Event * event_ptr)7914f1b3e8SDimitry Andric Vote ThreadPlan::ShouldReportStop(Event *event_ptr) {
80145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Step);
81f034231aSEd Maste
82344a3780SDimitry Andric if (m_report_stop_vote == eVoteNoOpinion) {
83f034231aSEd Maste ThreadPlan *prev_plan = GetPreviousPlan();
8414f1b3e8SDimitry Andric if (prev_plan) {
85f034231aSEd Maste Vote prev_vote = prev_plan->ShouldReportStop(event_ptr);
8674a628f7SDimitry Andric LLDB_LOG(log, "returning previous thread plan vote: {0}", prev_vote);
87f034231aSEd Maste return prev_vote;
88f034231aSEd Maste }
89f034231aSEd Maste }
90344a3780SDimitry Andric LLDB_LOG(log, "Returning vote: {0}", m_report_stop_vote);
91344a3780SDimitry Andric return m_report_stop_vote;
92f034231aSEd Maste }
93f034231aSEd Maste
ShouldReportRun(Event * event_ptr)9414f1b3e8SDimitry Andric Vote ThreadPlan::ShouldReportRun(Event *event_ptr) {
95344a3780SDimitry Andric if (m_report_run_vote == eVoteNoOpinion) {
96f034231aSEd Maste ThreadPlan *prev_plan = GetPreviousPlan();
97f034231aSEd Maste if (prev_plan)
98f034231aSEd Maste return prev_plan->ShouldReportRun(event_ptr);
99f034231aSEd Maste }
100344a3780SDimitry Andric return m_report_run_vote;
101f034231aSEd Maste }
102f034231aSEd Maste
ClearThreadCache()103b60736ecSDimitry Andric void ThreadPlan::ClearThreadCache() { m_thread = nullptr; }
104b60736ecSDimitry Andric
StopOthers()10514f1b3e8SDimitry Andric bool ThreadPlan::StopOthers() {
106f034231aSEd Maste ThreadPlan *prev_plan;
107f034231aSEd Maste prev_plan = GetPreviousPlan();
108e81d9d49SDimitry Andric return (prev_plan == nullptr) ? false : prev_plan->StopOthers();
109f034231aSEd Maste }
110f034231aSEd Maste
SetStopOthers(bool new_value)11114f1b3e8SDimitry Andric void ThreadPlan::SetStopOthers(bool new_value) {
112f73363f1SDimitry Andric // SetStopOthers doesn't work up the hierarchy. You have to set the explicit
113f73363f1SDimitry Andric // ThreadPlan you want to affect.
114f034231aSEd Maste }
115f034231aSEd Maste
WillResume(StateType resume_state,bool current_plan)11614f1b3e8SDimitry Andric bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) {
117f034231aSEd Maste m_cached_plan_explains_stop = eLazyBoolCalculate;
118f034231aSEd Maste
11914f1b3e8SDimitry Andric if (current_plan) {
120145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Step);
121f034231aSEd Maste
12214f1b3e8SDimitry Andric if (log) {
123cfca06d7SDimitry Andric RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();
1245e95aa85SEd Maste assert(reg_ctx);
125f034231aSEd Maste addr_t pc = reg_ctx->GetPC();
126f034231aSEd Maste addr_t sp = reg_ctx->GetSP();
127f034231aSEd Maste addr_t fp = reg_ctx->GetFP();
128ead24645SDimitry Andric LLDB_LOGF(
129ead24645SDimitry Andric log,
13014f1b3e8SDimitry Andric "%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64
13114f1b3e8SDimitry Andric ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", "
132f034231aSEd Maste "plan = '%s', state = %s, stop others = %d",
133cfca06d7SDimitry Andric __FUNCTION__, GetThread().GetIndexID(),
134cfca06d7SDimitry Andric static_cast<void *>(&GetThread()), m_tid, static_cast<uint64_t>(pc),
13514f1b3e8SDimitry Andric static_cast<uint64_t>(sp), static_cast<uint64_t>(fp), m_name.c_str(),
1360cac4ca3SEd Maste StateAsCString(resume_state), StopOthers());
137f034231aSEd Maste }
138f034231aSEd Maste }
139cfca06d7SDimitry Andric bool success = DoWillResume(resume_state, current_plan);
140b60736ecSDimitry Andric ClearThreadCache(); // We don't cache the thread pointer over resumes. This
141cfca06d7SDimitry Andric // Thread might go away, and another Thread represent
142cfca06d7SDimitry Andric // the same underlying object on a later stop.
143cfca06d7SDimitry Andric return success;
144f034231aSEd Maste }
145f034231aSEd Maste
GetNextID()14614f1b3e8SDimitry Andric lldb::user_id_t ThreadPlan::GetNextID() {
147f034231aSEd Maste static uint32_t g_nextPlanID = 0;
148f034231aSEd Maste return ++g_nextPlanID;
149f034231aSEd Maste }
150f034231aSEd Maste
DidPush()15114f1b3e8SDimitry Andric void ThreadPlan::DidPush() {}
152f034231aSEd Maste
DidPop()153c0981da4SDimitry Andric void ThreadPlan::DidPop() {}
154f034231aSEd Maste
OkayToDiscard()15514f1b3e8SDimitry Andric bool ThreadPlan::OkayToDiscard() {
156c0981da4SDimitry Andric return IsControllingPlan() ? m_okay_to_discard : true;
157f034231aSEd Maste }
158f034231aSEd Maste
RunState()15914f1b3e8SDimitry Andric lldb::StateType ThreadPlan::RunState() {
160344a3780SDimitry Andric if (m_tracer_sp && m_tracer_sp->TracingEnabled())
161f034231aSEd Maste return eStateStepping;
162f034231aSEd Maste else
163f034231aSEd Maste return GetPlanRunState();
164f034231aSEd Maste }
165f034231aSEd Maste
IsUsuallyUnexplainedStopReason(lldb::StopReason reason)16614f1b3e8SDimitry Andric bool ThreadPlan::IsUsuallyUnexplainedStopReason(lldb::StopReason reason) {
16714f1b3e8SDimitry Andric switch (reason) {
168e81d9d49SDimitry Andric case eStopReasonWatchpoint:
169e81d9d49SDimitry Andric case eStopReasonSignal:
170e81d9d49SDimitry Andric case eStopReasonException:
171e81d9d49SDimitry Andric case eStopReasonExec:
172e81d9d49SDimitry Andric case eStopReasonThreadExiting:
173e81d9d49SDimitry Andric case eStopReasonInstrumentation:
1747fa27ce4SDimitry Andric case eStopReasonFork:
1757fa27ce4SDimitry Andric case eStopReasonVFork:
1767fa27ce4SDimitry Andric case eStopReasonVForkDone:
177e81d9d49SDimitry Andric return true;
178e81d9d49SDimitry Andric default:
179e81d9d49SDimitry Andric return false;
180e81d9d49SDimitry Andric }
181e81d9d49SDimitry Andric }
182e81d9d49SDimitry Andric
183f034231aSEd Maste // ThreadPlanNull
184f034231aSEd Maste
ThreadPlanNull(Thread & thread)18514f1b3e8SDimitry Andric ThreadPlanNull::ThreadPlanNull(Thread &thread)
18614f1b3e8SDimitry Andric : ThreadPlan(ThreadPlan::eKindNull, "Null Thread Plan", thread,
18714f1b3e8SDimitry Andric eVoteNoOpinion, eVoteNoOpinion) {}
188f034231aSEd Maste
189e81d9d49SDimitry Andric ThreadPlanNull::~ThreadPlanNull() = default;
190f034231aSEd Maste
GetDescription(Stream * s,lldb::DescriptionLevel level)19114f1b3e8SDimitry Andric void ThreadPlanNull::GetDescription(Stream *s, lldb::DescriptionLevel level) {
192f034231aSEd Maste s->PutCString("Null thread plan - thread has been destroyed.");
193f034231aSEd Maste }
194f034231aSEd Maste
ValidatePlan(Stream * error)19514f1b3e8SDimitry Andric bool ThreadPlanNull::ValidatePlan(Stream *error) {
196f034231aSEd Maste #ifdef LLDB_CONFIGURATION_DEBUG
19714f1b3e8SDimitry Andric fprintf(stderr,
19814f1b3e8SDimitry Andric "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
19914f1b3e8SDimitry Andric ", ptid = 0x%" PRIx64 ")",
200cfca06d7SDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
201f034231aSEd Maste #else
202145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Thread);
203f034231aSEd Maste if (log)
20414f1b3e8SDimitry Andric log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
20514f1b3e8SDimitry Andric ", ptid = 0x%" PRIx64 ")",
206cfca06d7SDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
207f034231aSEd Maste #endif
208f034231aSEd Maste return true;
209f034231aSEd Maste }
210f034231aSEd Maste
ShouldStop(Event * event_ptr)21114f1b3e8SDimitry Andric bool ThreadPlanNull::ShouldStop(Event *event_ptr) {
212f034231aSEd Maste #ifdef LLDB_CONFIGURATION_DEBUG
21314f1b3e8SDimitry Andric fprintf(stderr,
21414f1b3e8SDimitry Andric "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
21514f1b3e8SDimitry Andric ", ptid = 0x%" PRIx64 ")",
216cfca06d7SDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
217f034231aSEd Maste #else
218145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Thread);
219f034231aSEd Maste if (log)
22014f1b3e8SDimitry Andric log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
22114f1b3e8SDimitry Andric ", ptid = 0x%" PRIx64 ")",
222cfca06d7SDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
223f034231aSEd Maste #endif
224f034231aSEd Maste return true;
225f034231aSEd Maste }
226f034231aSEd Maste
WillStop()22714f1b3e8SDimitry Andric bool ThreadPlanNull::WillStop() {
228f034231aSEd Maste #ifdef LLDB_CONFIGURATION_DEBUG
22914f1b3e8SDimitry Andric fprintf(stderr,
23014f1b3e8SDimitry Andric "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
23114f1b3e8SDimitry Andric ", ptid = 0x%" PRIx64 ")",
232cfca06d7SDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
233f034231aSEd Maste #else
234145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Thread);
235f034231aSEd Maste if (log)
23614f1b3e8SDimitry Andric log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
23714f1b3e8SDimitry Andric ", ptid = 0x%" PRIx64 ")",
238cfca06d7SDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
239f034231aSEd Maste #endif
240f034231aSEd Maste return true;
241f034231aSEd Maste }
242f034231aSEd Maste
DoPlanExplainsStop(Event * event_ptr)24314f1b3e8SDimitry Andric bool ThreadPlanNull::DoPlanExplainsStop(Event *event_ptr) {
244f034231aSEd Maste #ifdef LLDB_CONFIGURATION_DEBUG
24514f1b3e8SDimitry Andric fprintf(stderr,
24614f1b3e8SDimitry Andric "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
24714f1b3e8SDimitry Andric ", ptid = 0x%" PRIx64 ")",
248cfca06d7SDimitry Andric LLVM_PRETTY_FUNCTION, GetThread().GetID(), GetThread().GetProtocolID());
249f034231aSEd Maste #else
250145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Thread);
251f034231aSEd Maste if (log)
25214f1b3e8SDimitry Andric log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
25314f1b3e8SDimitry Andric ", ptid = 0x%" PRIx64 ")",
254cfca06d7SDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
255f034231aSEd Maste #endif
256f034231aSEd Maste return true;
257f034231aSEd Maste }
258f034231aSEd Maste
259f034231aSEd Maste // The null plan is never done.
MischiefManaged()26014f1b3e8SDimitry Andric bool ThreadPlanNull::MischiefManaged() {
261f034231aSEd Maste // The null plan is never done.
262f034231aSEd Maste #ifdef LLDB_CONFIGURATION_DEBUG
26314f1b3e8SDimitry Andric fprintf(stderr,
26414f1b3e8SDimitry Andric "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
26514f1b3e8SDimitry Andric ", ptid = 0x%" PRIx64 ")",
266cfca06d7SDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
267f034231aSEd Maste #else
268145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Thread);
269f034231aSEd Maste if (log)
27014f1b3e8SDimitry Andric log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
27114f1b3e8SDimitry Andric ", ptid = 0x%" PRIx64 ")",
272cfca06d7SDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
273f034231aSEd Maste #endif
274f034231aSEd Maste return false;
275f034231aSEd Maste }
276f034231aSEd Maste
GetPlanRunState()27714f1b3e8SDimitry Andric lldb::StateType ThreadPlanNull::GetPlanRunState() {
278f034231aSEd Maste // Not sure what to return here. This is a dead thread.
279f034231aSEd Maste #ifdef LLDB_CONFIGURATION_DEBUG
28014f1b3e8SDimitry Andric fprintf(stderr,
28114f1b3e8SDimitry Andric "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
28214f1b3e8SDimitry Andric ", ptid = 0x%" PRIx64 ")",
283cfca06d7SDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
284f034231aSEd Maste #else
285145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Thread);
286f034231aSEd Maste if (log)
28714f1b3e8SDimitry Andric log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
28814f1b3e8SDimitry Andric ", ptid = 0x%" PRIx64 ")",
289cfca06d7SDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
290f034231aSEd Maste #endif
291f034231aSEd Maste return eStateRunning;
292f034231aSEd Maste }
293