15ffd83dbSDimitry Andric //===-- ThreadPlan.cpp ----------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "lldb/Target/ThreadPlan.h"
100b57cec5SDimitry Andric #include "lldb/Core/Debugger.h"
110b57cec5SDimitry Andric #include "lldb/Target/Process.h"
120b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
130b57cec5SDimitry Andric #include "lldb/Target/Target.h"
140b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
1581ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
160b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
170b57cec5SDimitry Andric #include "lldb/Utility/State.h"
180b57cec5SDimitry Andric
190b57cec5SDimitry Andric using namespace lldb;
200b57cec5SDimitry Andric using namespace lldb_private;
210b57cec5SDimitry Andric
220b57cec5SDimitry Andric // ThreadPlan constructor
ThreadPlan(ThreadPlanKind kind,const char * name,Thread & thread,Vote report_stop_vote,Vote report_run_vote)230b57cec5SDimitry Andric ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread,
24fe6060f1SDimitry Andric Vote report_stop_vote, Vote report_run_vote)
255ffd83dbSDimitry Andric : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
26fe6060f1SDimitry Andric m_report_stop_vote(report_stop_vote), m_report_run_vote(report_run_vote),
270b57cec5SDimitry Andric m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false),
285ffd83dbSDimitry Andric m_thread(&thread), m_kind(kind), m_name(name), m_plan_complete_mutex(),
290b57cec5SDimitry Andric m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false),
30349cc55cSDimitry Andric m_plan_private(false), m_okay_to_discard(true),
31349cc55cSDimitry Andric m_is_controlling_plan(false), m_plan_succeeded(true) {
320b57cec5SDimitry Andric SetID(GetNextID());
330b57cec5SDimitry Andric }
340b57cec5SDimitry Andric
350b57cec5SDimitry Andric // Destructor
360b57cec5SDimitry Andric ThreadPlan::~ThreadPlan() = default;
370b57cec5SDimitry Andric
GetTarget()385ffd83dbSDimitry Andric Target &ThreadPlan::GetTarget() { return m_process.GetTarget(); }
395ffd83dbSDimitry Andric
GetTarget() const405ffd83dbSDimitry Andric const Target &ThreadPlan::GetTarget() const { return m_process.GetTarget(); }
415ffd83dbSDimitry Andric
GetThread()425ffd83dbSDimitry Andric Thread &ThreadPlan::GetThread() {
435ffd83dbSDimitry Andric if (m_thread)
445ffd83dbSDimitry Andric return *m_thread;
455ffd83dbSDimitry Andric
465ffd83dbSDimitry Andric ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid);
475ffd83dbSDimitry Andric m_thread = thread_sp.get();
485ffd83dbSDimitry Andric return *m_thread;
495ffd83dbSDimitry Andric }
505ffd83dbSDimitry Andric
PlanExplainsStop(Event * event_ptr)510b57cec5SDimitry Andric bool ThreadPlan::PlanExplainsStop(Event *event_ptr) {
520b57cec5SDimitry Andric if (m_cached_plan_explains_stop == eLazyBoolCalculate) {
530b57cec5SDimitry Andric bool actual_value = DoPlanExplainsStop(event_ptr);
54fe6060f1SDimitry Andric CachePlanExplainsStop(actual_value);
550b57cec5SDimitry Andric return actual_value;
560b57cec5SDimitry Andric } else {
570b57cec5SDimitry Andric return m_cached_plan_explains_stop == eLazyBoolYes;
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric }
600b57cec5SDimitry Andric
IsPlanComplete()610b57cec5SDimitry Andric bool ThreadPlan::IsPlanComplete() {
620b57cec5SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex);
630b57cec5SDimitry Andric return m_plan_complete;
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric
SetPlanComplete(bool success)660b57cec5SDimitry Andric void ThreadPlan::SetPlanComplete(bool success) {
670b57cec5SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex);
680b57cec5SDimitry Andric m_plan_complete = true;
690b57cec5SDimitry Andric m_plan_succeeded = success;
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric
MischiefManaged()720b57cec5SDimitry Andric bool ThreadPlan::MischiefManaged() {
730b57cec5SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex);
740b57cec5SDimitry Andric // Mark the plan is complete, but don't override the success flag.
750b57cec5SDimitry Andric m_plan_complete = true;
760b57cec5SDimitry Andric return true;
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric
ShouldReportStop(Event * event_ptr)790b57cec5SDimitry Andric Vote ThreadPlan::ShouldReportStop(Event *event_ptr) {
8081ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Step);
810b57cec5SDimitry Andric
82fe6060f1SDimitry Andric if (m_report_stop_vote == eVoteNoOpinion) {
830b57cec5SDimitry Andric ThreadPlan *prev_plan = GetPreviousPlan();
840b57cec5SDimitry Andric if (prev_plan) {
850b57cec5SDimitry Andric Vote prev_vote = prev_plan->ShouldReportStop(event_ptr);
860b57cec5SDimitry Andric LLDB_LOG(log, "returning previous thread plan vote: {0}", prev_vote);
870b57cec5SDimitry Andric return prev_vote;
880b57cec5SDimitry Andric }
890b57cec5SDimitry Andric }
90fe6060f1SDimitry Andric LLDB_LOG(log, "Returning vote: {0}", m_report_stop_vote);
91fe6060f1SDimitry Andric return m_report_stop_vote;
920b57cec5SDimitry Andric }
930b57cec5SDimitry Andric
ShouldReportRun(Event * event_ptr)940b57cec5SDimitry Andric Vote ThreadPlan::ShouldReportRun(Event *event_ptr) {
95fe6060f1SDimitry Andric if (m_report_run_vote == eVoteNoOpinion) {
960b57cec5SDimitry Andric ThreadPlan *prev_plan = GetPreviousPlan();
970b57cec5SDimitry Andric if (prev_plan)
980b57cec5SDimitry Andric return prev_plan->ShouldReportRun(event_ptr);
990b57cec5SDimitry Andric }
100fe6060f1SDimitry Andric return m_report_run_vote;
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric
ClearThreadCache()103e8d8bef9SDimitry Andric void ThreadPlan::ClearThreadCache() { m_thread = nullptr; }
104e8d8bef9SDimitry Andric
StopOthers()1050b57cec5SDimitry Andric bool ThreadPlan::StopOthers() {
1060b57cec5SDimitry Andric ThreadPlan *prev_plan;
1070b57cec5SDimitry Andric prev_plan = GetPreviousPlan();
1080b57cec5SDimitry Andric return (prev_plan == nullptr) ? false : prev_plan->StopOthers();
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric
SetStopOthers(bool new_value)1110b57cec5SDimitry Andric void ThreadPlan::SetStopOthers(bool new_value) {
1120b57cec5SDimitry Andric // SetStopOthers doesn't work up the hierarchy. You have to set the explicit
1130b57cec5SDimitry Andric // ThreadPlan you want to affect.
1140b57cec5SDimitry Andric }
1150b57cec5SDimitry Andric
WillResume(StateType resume_state,bool current_plan)1160b57cec5SDimitry Andric bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) {
1170b57cec5SDimitry Andric m_cached_plan_explains_stop = eLazyBoolCalculate;
1180b57cec5SDimitry Andric
1190b57cec5SDimitry Andric if (current_plan) {
12081ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Step);
1210b57cec5SDimitry Andric
1220b57cec5SDimitry Andric if (log) {
1235ffd83dbSDimitry Andric RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();
1240b57cec5SDimitry Andric assert(reg_ctx);
1250b57cec5SDimitry Andric addr_t pc = reg_ctx->GetPC();
1260b57cec5SDimitry Andric addr_t sp = reg_ctx->GetSP();
1270b57cec5SDimitry Andric addr_t fp = reg_ctx->GetFP();
1289dba64beSDimitry Andric LLDB_LOGF(
1299dba64beSDimitry Andric log,
1300b57cec5SDimitry Andric "%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64
1310b57cec5SDimitry Andric ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", "
1320b57cec5SDimitry Andric "plan = '%s', state = %s, stop others = %d",
1335ffd83dbSDimitry Andric __FUNCTION__, GetThread().GetIndexID(),
1345ffd83dbSDimitry Andric static_cast<void *>(&GetThread()), m_tid, static_cast<uint64_t>(pc),
1350b57cec5SDimitry Andric static_cast<uint64_t>(sp), static_cast<uint64_t>(fp), m_name.c_str(),
1360b57cec5SDimitry Andric StateAsCString(resume_state), StopOthers());
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric }
1395ffd83dbSDimitry Andric bool success = DoWillResume(resume_state, current_plan);
140e8d8bef9SDimitry Andric ClearThreadCache(); // We don't cache the thread pointer over resumes. This
1415ffd83dbSDimitry Andric // Thread might go away, and another Thread represent
1425ffd83dbSDimitry Andric // the same underlying object on a later stop.
1435ffd83dbSDimitry Andric return success;
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric
GetNextID()1460b57cec5SDimitry Andric lldb::user_id_t ThreadPlan::GetNextID() {
1470b57cec5SDimitry Andric static uint32_t g_nextPlanID = 0;
1480b57cec5SDimitry Andric return ++g_nextPlanID;
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric
DidPush()1510b57cec5SDimitry Andric void ThreadPlan::DidPush() {}
1520b57cec5SDimitry Andric
DidPop()153349cc55cSDimitry Andric void ThreadPlan::DidPop() {}
1540b57cec5SDimitry Andric
OkayToDiscard()1550b57cec5SDimitry Andric bool ThreadPlan::OkayToDiscard() {
156349cc55cSDimitry Andric return IsControllingPlan() ? m_okay_to_discard : true;
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric
RunState()1590b57cec5SDimitry Andric lldb::StateType ThreadPlan::RunState() {
160fe6060f1SDimitry Andric if (m_tracer_sp && m_tracer_sp->TracingEnabled())
1610b57cec5SDimitry Andric return eStateStepping;
1620b57cec5SDimitry Andric else
1630b57cec5SDimitry Andric return GetPlanRunState();
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric
IsUsuallyUnexplainedStopReason(lldb::StopReason reason)1660b57cec5SDimitry Andric bool ThreadPlan::IsUsuallyUnexplainedStopReason(lldb::StopReason reason) {
1670b57cec5SDimitry Andric switch (reason) {
1680b57cec5SDimitry Andric case eStopReasonWatchpoint:
1690b57cec5SDimitry Andric case eStopReasonSignal:
1700b57cec5SDimitry Andric case eStopReasonException:
1710b57cec5SDimitry Andric case eStopReasonExec:
1720b57cec5SDimitry Andric case eStopReasonThreadExiting:
1730b57cec5SDimitry Andric case eStopReasonInstrumentation:
174*fe013be4SDimitry Andric case eStopReasonFork:
175*fe013be4SDimitry Andric case eStopReasonVFork:
176*fe013be4SDimitry Andric case eStopReasonVForkDone:
1770b57cec5SDimitry Andric return true;
1780b57cec5SDimitry Andric default:
1790b57cec5SDimitry Andric return false;
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric }
1820b57cec5SDimitry Andric
1830b57cec5SDimitry Andric // ThreadPlanNull
1840b57cec5SDimitry Andric
ThreadPlanNull(Thread & thread)1850b57cec5SDimitry Andric ThreadPlanNull::ThreadPlanNull(Thread &thread)
1860b57cec5SDimitry Andric : ThreadPlan(ThreadPlan::eKindNull, "Null Thread Plan", thread,
1870b57cec5SDimitry Andric eVoteNoOpinion, eVoteNoOpinion) {}
1880b57cec5SDimitry Andric
1890b57cec5SDimitry Andric ThreadPlanNull::~ThreadPlanNull() = default;
1900b57cec5SDimitry Andric
GetDescription(Stream * s,lldb::DescriptionLevel level)1910b57cec5SDimitry Andric void ThreadPlanNull::GetDescription(Stream *s, lldb::DescriptionLevel level) {
1920b57cec5SDimitry Andric s->PutCString("Null thread plan - thread has been destroyed.");
1930b57cec5SDimitry Andric }
1940b57cec5SDimitry Andric
ValidatePlan(Stream * error)1950b57cec5SDimitry Andric bool ThreadPlanNull::ValidatePlan(Stream *error) {
1960b57cec5SDimitry Andric #ifdef LLDB_CONFIGURATION_DEBUG
1970b57cec5SDimitry Andric fprintf(stderr,
1980b57cec5SDimitry Andric "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
1990b57cec5SDimitry Andric ", ptid = 0x%" PRIx64 ")",
2005ffd83dbSDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2010b57cec5SDimitry Andric #else
20281ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Thread);
2030b57cec5SDimitry Andric if (log)
2040b57cec5SDimitry Andric log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
2050b57cec5SDimitry Andric ", ptid = 0x%" PRIx64 ")",
2065ffd83dbSDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2070b57cec5SDimitry Andric #endif
2080b57cec5SDimitry Andric return true;
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric
ShouldStop(Event * event_ptr)2110b57cec5SDimitry Andric bool ThreadPlanNull::ShouldStop(Event *event_ptr) {
2120b57cec5SDimitry Andric #ifdef LLDB_CONFIGURATION_DEBUG
2130b57cec5SDimitry Andric fprintf(stderr,
2140b57cec5SDimitry Andric "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
2150b57cec5SDimitry Andric ", ptid = 0x%" PRIx64 ")",
2165ffd83dbSDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2170b57cec5SDimitry Andric #else
21881ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Thread);
2190b57cec5SDimitry Andric if (log)
2200b57cec5SDimitry Andric log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
2210b57cec5SDimitry Andric ", ptid = 0x%" PRIx64 ")",
2225ffd83dbSDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2230b57cec5SDimitry Andric #endif
2240b57cec5SDimitry Andric return true;
2250b57cec5SDimitry Andric }
2260b57cec5SDimitry Andric
WillStop()2270b57cec5SDimitry Andric bool ThreadPlanNull::WillStop() {
2280b57cec5SDimitry Andric #ifdef LLDB_CONFIGURATION_DEBUG
2290b57cec5SDimitry Andric fprintf(stderr,
2300b57cec5SDimitry Andric "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
2310b57cec5SDimitry Andric ", ptid = 0x%" PRIx64 ")",
2325ffd83dbSDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2330b57cec5SDimitry Andric #else
23481ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Thread);
2350b57cec5SDimitry Andric if (log)
2360b57cec5SDimitry Andric log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
2370b57cec5SDimitry Andric ", ptid = 0x%" PRIx64 ")",
2385ffd83dbSDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2390b57cec5SDimitry Andric #endif
2400b57cec5SDimitry Andric return true;
2410b57cec5SDimitry Andric }
2420b57cec5SDimitry Andric
DoPlanExplainsStop(Event * event_ptr)2430b57cec5SDimitry Andric bool ThreadPlanNull::DoPlanExplainsStop(Event *event_ptr) {
2440b57cec5SDimitry Andric #ifdef LLDB_CONFIGURATION_DEBUG
2450b57cec5SDimitry Andric fprintf(stderr,
2460b57cec5SDimitry Andric "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
2470b57cec5SDimitry Andric ", ptid = 0x%" PRIx64 ")",
2485ffd83dbSDimitry Andric LLVM_PRETTY_FUNCTION, GetThread().GetID(), GetThread().GetProtocolID());
2490b57cec5SDimitry Andric #else
25081ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Thread);
2510b57cec5SDimitry Andric if (log)
2520b57cec5SDimitry Andric log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
2530b57cec5SDimitry Andric ", ptid = 0x%" PRIx64 ")",
2545ffd83dbSDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2550b57cec5SDimitry Andric #endif
2560b57cec5SDimitry Andric return true;
2570b57cec5SDimitry Andric }
2580b57cec5SDimitry Andric
2590b57cec5SDimitry Andric // The null plan is never done.
MischiefManaged()2600b57cec5SDimitry Andric bool ThreadPlanNull::MischiefManaged() {
2610b57cec5SDimitry Andric // The null plan is never done.
2620b57cec5SDimitry Andric #ifdef LLDB_CONFIGURATION_DEBUG
2630b57cec5SDimitry Andric fprintf(stderr,
2640b57cec5SDimitry Andric "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
2650b57cec5SDimitry Andric ", ptid = 0x%" PRIx64 ")",
2665ffd83dbSDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2670b57cec5SDimitry Andric #else
26881ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Thread);
2690b57cec5SDimitry Andric if (log)
2700b57cec5SDimitry Andric log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
2710b57cec5SDimitry Andric ", ptid = 0x%" PRIx64 ")",
2725ffd83dbSDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2730b57cec5SDimitry Andric #endif
2740b57cec5SDimitry Andric return false;
2750b57cec5SDimitry Andric }
2760b57cec5SDimitry Andric
GetPlanRunState()2770b57cec5SDimitry Andric lldb::StateType ThreadPlanNull::GetPlanRunState() {
2780b57cec5SDimitry Andric // Not sure what to return here. This is a dead thread.
2790b57cec5SDimitry Andric #ifdef LLDB_CONFIGURATION_DEBUG
2800b57cec5SDimitry Andric fprintf(stderr,
2810b57cec5SDimitry Andric "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
2820b57cec5SDimitry Andric ", ptid = 0x%" PRIx64 ")",
2835ffd83dbSDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2840b57cec5SDimitry Andric #else
28581ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Thread);
2860b57cec5SDimitry Andric if (log)
2870b57cec5SDimitry Andric log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
2880b57cec5SDimitry Andric ", ptid = 0x%" PRIx64 ")",
2895ffd83dbSDimitry Andric LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2900b57cec5SDimitry Andric #endif
2910b57cec5SDimitry Andric return eStateRunning;
2920b57cec5SDimitry Andric }
293