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"
150b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
160b57cec5SDimitry Andric #include "lldb/Utility/State.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric using namespace lldb;
190b57cec5SDimitry Andric using namespace lldb_private;
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric // ThreadPlan constructor
ThreadPlan(ThreadPlanKind kind,const char * name,Thread & thread,Vote report_stop_vote,Vote report_run_vote)220b57cec5SDimitry Andric ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread,
23*5f7ddb14SDimitry Andric                        Vote report_stop_vote, Vote report_run_vote)
245ffd83dbSDimitry Andric     : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
25*5f7ddb14SDimitry Andric       m_report_stop_vote(report_stop_vote), m_report_run_vote(report_run_vote),
260b57cec5SDimitry Andric       m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false),
275ffd83dbSDimitry Andric       m_thread(&thread), m_kind(kind), m_name(name), m_plan_complete_mutex(),
280b57cec5SDimitry Andric       m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false),
290b57cec5SDimitry Andric       m_plan_private(false), m_okay_to_discard(true), m_is_master_plan(false),
300b57cec5SDimitry Andric       m_plan_succeeded(true) {
310b57cec5SDimitry Andric   SetID(GetNextID());
320b57cec5SDimitry Andric }
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric // Destructor
350b57cec5SDimitry Andric ThreadPlan::~ThreadPlan() = default;
360b57cec5SDimitry Andric 
GetTarget()375ffd83dbSDimitry Andric Target &ThreadPlan::GetTarget() { return m_process.GetTarget(); }
385ffd83dbSDimitry Andric 
GetTarget() const395ffd83dbSDimitry Andric const Target &ThreadPlan::GetTarget() const { return m_process.GetTarget(); }
405ffd83dbSDimitry Andric 
GetThread()415ffd83dbSDimitry Andric Thread &ThreadPlan::GetThread() {
425ffd83dbSDimitry Andric   if (m_thread)
435ffd83dbSDimitry Andric     return *m_thread;
445ffd83dbSDimitry Andric 
455ffd83dbSDimitry Andric   ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid);
465ffd83dbSDimitry Andric   m_thread = thread_sp.get();
475ffd83dbSDimitry Andric   return *m_thread;
485ffd83dbSDimitry Andric }
495ffd83dbSDimitry Andric 
PlanExplainsStop(Event * event_ptr)500b57cec5SDimitry Andric bool ThreadPlan::PlanExplainsStop(Event *event_ptr) {
510b57cec5SDimitry Andric   if (m_cached_plan_explains_stop == eLazyBoolCalculate) {
520b57cec5SDimitry Andric     bool actual_value = DoPlanExplainsStop(event_ptr);
53*5f7ddb14SDimitry Andric     CachePlanExplainsStop(actual_value);
540b57cec5SDimitry Andric     return actual_value;
550b57cec5SDimitry Andric   } else {
560b57cec5SDimitry Andric     return m_cached_plan_explains_stop == eLazyBoolYes;
570b57cec5SDimitry Andric   }
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric 
IsPlanComplete()600b57cec5SDimitry Andric bool ThreadPlan::IsPlanComplete() {
610b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex);
620b57cec5SDimitry Andric   return m_plan_complete;
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric 
SetPlanComplete(bool success)650b57cec5SDimitry Andric void ThreadPlan::SetPlanComplete(bool success) {
660b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex);
670b57cec5SDimitry Andric   m_plan_complete = true;
680b57cec5SDimitry Andric   m_plan_succeeded = success;
690b57cec5SDimitry Andric }
700b57cec5SDimitry Andric 
MischiefManaged()710b57cec5SDimitry Andric bool ThreadPlan::MischiefManaged() {
720b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex);
730b57cec5SDimitry Andric   // Mark the plan is complete, but don't override the success flag.
740b57cec5SDimitry Andric   m_plan_complete = true;
750b57cec5SDimitry Andric   return true;
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric 
ShouldReportStop(Event * event_ptr)780b57cec5SDimitry Andric Vote ThreadPlan::ShouldReportStop(Event *event_ptr) {
790b57cec5SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
800b57cec5SDimitry Andric 
81*5f7ddb14SDimitry Andric   if (m_report_stop_vote == eVoteNoOpinion) {
820b57cec5SDimitry Andric     ThreadPlan *prev_plan = GetPreviousPlan();
830b57cec5SDimitry Andric     if (prev_plan) {
840b57cec5SDimitry Andric       Vote prev_vote = prev_plan->ShouldReportStop(event_ptr);
850b57cec5SDimitry Andric       LLDB_LOG(log, "returning previous thread plan vote: {0}", prev_vote);
860b57cec5SDimitry Andric       return prev_vote;
870b57cec5SDimitry Andric     }
880b57cec5SDimitry Andric   }
89*5f7ddb14SDimitry Andric   LLDB_LOG(log, "Returning vote: {0}", m_report_stop_vote);
90*5f7ddb14SDimitry Andric   return m_report_stop_vote;
910b57cec5SDimitry Andric }
920b57cec5SDimitry Andric 
ShouldReportRun(Event * event_ptr)930b57cec5SDimitry Andric Vote ThreadPlan::ShouldReportRun(Event *event_ptr) {
94*5f7ddb14SDimitry Andric   if (m_report_run_vote == eVoteNoOpinion) {
950b57cec5SDimitry Andric     ThreadPlan *prev_plan = GetPreviousPlan();
960b57cec5SDimitry Andric     if (prev_plan)
970b57cec5SDimitry Andric       return prev_plan->ShouldReportRun(event_ptr);
980b57cec5SDimitry Andric   }
99*5f7ddb14SDimitry Andric   return m_report_run_vote;
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric 
ClearThreadCache()102af732203SDimitry Andric void ThreadPlan::ClearThreadCache() { m_thread = nullptr; }
103af732203SDimitry Andric 
StopOthers()1040b57cec5SDimitry Andric bool ThreadPlan::StopOthers() {
1050b57cec5SDimitry Andric   ThreadPlan *prev_plan;
1060b57cec5SDimitry Andric   prev_plan = GetPreviousPlan();
1070b57cec5SDimitry Andric   return (prev_plan == nullptr) ? false : prev_plan->StopOthers();
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric 
SetStopOthers(bool new_value)1100b57cec5SDimitry Andric void ThreadPlan::SetStopOthers(bool new_value) {
1110b57cec5SDimitry Andric   // SetStopOthers doesn't work up the hierarchy.  You have to set the explicit
1120b57cec5SDimitry Andric   // ThreadPlan you want to affect.
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric 
WillResume(StateType resume_state,bool current_plan)1150b57cec5SDimitry Andric bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) {
1160b57cec5SDimitry Andric   m_cached_plan_explains_stop = eLazyBoolCalculate;
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   if (current_plan) {
1190b57cec5SDimitry Andric     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric     if (log) {
1225ffd83dbSDimitry Andric       RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();
1230b57cec5SDimitry Andric       assert(reg_ctx);
1240b57cec5SDimitry Andric       addr_t pc = reg_ctx->GetPC();
1250b57cec5SDimitry Andric       addr_t sp = reg_ctx->GetSP();
1260b57cec5SDimitry Andric       addr_t fp = reg_ctx->GetFP();
1279dba64beSDimitry Andric       LLDB_LOGF(
1289dba64beSDimitry Andric           log,
1290b57cec5SDimitry Andric           "%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64
1300b57cec5SDimitry Andric           ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", "
1310b57cec5SDimitry Andric           "plan = '%s', state = %s, stop others = %d",
1325ffd83dbSDimitry Andric           __FUNCTION__, GetThread().GetIndexID(),
1335ffd83dbSDimitry Andric           static_cast<void *>(&GetThread()), m_tid, static_cast<uint64_t>(pc),
1340b57cec5SDimitry Andric           static_cast<uint64_t>(sp), static_cast<uint64_t>(fp), m_name.c_str(),
1350b57cec5SDimitry Andric           StateAsCString(resume_state), StopOthers());
1360b57cec5SDimitry Andric     }
1370b57cec5SDimitry Andric   }
1385ffd83dbSDimitry Andric   bool success = DoWillResume(resume_state, current_plan);
139af732203SDimitry Andric   ClearThreadCache(); // We don't cache the thread pointer over resumes.  This
1405ffd83dbSDimitry Andric                       // Thread might go away, and another Thread represent
1415ffd83dbSDimitry Andric                       // the same underlying object on a later stop.
1425ffd83dbSDimitry Andric   return success;
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric 
GetNextID()1450b57cec5SDimitry Andric lldb::user_id_t ThreadPlan::GetNextID() {
1460b57cec5SDimitry Andric   static uint32_t g_nextPlanID = 0;
1470b57cec5SDimitry Andric   return ++g_nextPlanID;
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric 
DidPush()1500b57cec5SDimitry Andric void ThreadPlan::DidPush() {}
1510b57cec5SDimitry Andric 
WillPop()1520b57cec5SDimitry Andric void ThreadPlan::WillPop() {}
1530b57cec5SDimitry Andric 
OkayToDiscard()1540b57cec5SDimitry Andric bool ThreadPlan::OkayToDiscard() {
1550b57cec5SDimitry Andric   return IsMasterPlan() ? m_okay_to_discard : true;
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric 
RunState()1580b57cec5SDimitry Andric lldb::StateType ThreadPlan::RunState() {
159*5f7ddb14SDimitry Andric   if (m_tracer_sp && m_tracer_sp->TracingEnabled())
1600b57cec5SDimitry Andric     return eStateStepping;
1610b57cec5SDimitry Andric   else
1620b57cec5SDimitry Andric     return GetPlanRunState();
1630b57cec5SDimitry Andric }
1640b57cec5SDimitry Andric 
IsUsuallyUnexplainedStopReason(lldb::StopReason reason)1650b57cec5SDimitry Andric bool ThreadPlan::IsUsuallyUnexplainedStopReason(lldb::StopReason reason) {
1660b57cec5SDimitry Andric   switch (reason) {
1670b57cec5SDimitry Andric   case eStopReasonWatchpoint:
1680b57cec5SDimitry Andric   case eStopReasonSignal:
1690b57cec5SDimitry Andric   case eStopReasonException:
1700b57cec5SDimitry Andric   case eStopReasonExec:
1710b57cec5SDimitry Andric   case eStopReasonThreadExiting:
1720b57cec5SDimitry Andric   case eStopReasonInstrumentation:
1730b57cec5SDimitry Andric     return true;
1740b57cec5SDimitry Andric   default:
1750b57cec5SDimitry Andric     return false;
1760b57cec5SDimitry Andric   }
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric // ThreadPlanNull
1800b57cec5SDimitry Andric 
ThreadPlanNull(Thread & thread)1810b57cec5SDimitry Andric ThreadPlanNull::ThreadPlanNull(Thread &thread)
1820b57cec5SDimitry Andric     : ThreadPlan(ThreadPlan::eKindNull, "Null Thread Plan", thread,
1830b57cec5SDimitry Andric                  eVoteNoOpinion, eVoteNoOpinion) {}
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric ThreadPlanNull::~ThreadPlanNull() = default;
1860b57cec5SDimitry Andric 
GetDescription(Stream * s,lldb::DescriptionLevel level)1870b57cec5SDimitry Andric void ThreadPlanNull::GetDescription(Stream *s, lldb::DescriptionLevel level) {
1880b57cec5SDimitry Andric   s->PutCString("Null thread plan - thread has been destroyed.");
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric 
ValidatePlan(Stream * error)1910b57cec5SDimitry Andric bool ThreadPlanNull::ValidatePlan(Stream *error) {
1920b57cec5SDimitry Andric #ifdef LLDB_CONFIGURATION_DEBUG
1930b57cec5SDimitry Andric   fprintf(stderr,
1940b57cec5SDimitry Andric           "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
1950b57cec5SDimitry Andric           ", ptid = 0x%" PRIx64 ")",
1965ffd83dbSDimitry Andric           LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
1970b57cec5SDimitry Andric #else
1980b57cec5SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
1990b57cec5SDimitry Andric   if (log)
2000b57cec5SDimitry Andric     log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
2010b57cec5SDimitry Andric                ", ptid = 0x%" PRIx64 ")",
2025ffd83dbSDimitry Andric                LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2030b57cec5SDimitry Andric #endif
2040b57cec5SDimitry Andric   return true;
2050b57cec5SDimitry Andric }
2060b57cec5SDimitry Andric 
ShouldStop(Event * event_ptr)2070b57cec5SDimitry Andric bool ThreadPlanNull::ShouldStop(Event *event_ptr) {
2080b57cec5SDimitry Andric #ifdef LLDB_CONFIGURATION_DEBUG
2090b57cec5SDimitry Andric   fprintf(stderr,
2100b57cec5SDimitry Andric           "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
2110b57cec5SDimitry Andric           ", ptid = 0x%" PRIx64 ")",
2125ffd83dbSDimitry Andric           LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2130b57cec5SDimitry Andric #else
2140b57cec5SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
2150b57cec5SDimitry Andric   if (log)
2160b57cec5SDimitry Andric     log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
2170b57cec5SDimitry Andric                ", ptid = 0x%" PRIx64 ")",
2185ffd83dbSDimitry Andric                LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2190b57cec5SDimitry Andric #endif
2200b57cec5SDimitry Andric   return true;
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric 
WillStop()2230b57cec5SDimitry Andric bool ThreadPlanNull::WillStop() {
2240b57cec5SDimitry Andric #ifdef LLDB_CONFIGURATION_DEBUG
2250b57cec5SDimitry Andric   fprintf(stderr,
2260b57cec5SDimitry Andric           "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
2270b57cec5SDimitry Andric           ", ptid = 0x%" PRIx64 ")",
2285ffd83dbSDimitry Andric           LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2290b57cec5SDimitry Andric #else
2300b57cec5SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
2310b57cec5SDimitry Andric   if (log)
2320b57cec5SDimitry Andric     log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
2330b57cec5SDimitry Andric                ", ptid = 0x%" PRIx64 ")",
2345ffd83dbSDimitry Andric                LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2350b57cec5SDimitry Andric #endif
2360b57cec5SDimitry Andric   return true;
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric 
DoPlanExplainsStop(Event * event_ptr)2390b57cec5SDimitry Andric bool ThreadPlanNull::DoPlanExplainsStop(Event *event_ptr) {
2400b57cec5SDimitry Andric #ifdef LLDB_CONFIGURATION_DEBUG
2410b57cec5SDimitry Andric   fprintf(stderr,
2420b57cec5SDimitry Andric           "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
2430b57cec5SDimitry Andric           ", ptid = 0x%" PRIx64 ")",
2445ffd83dbSDimitry Andric           LLVM_PRETTY_FUNCTION, GetThread().GetID(), GetThread().GetProtocolID());
2450b57cec5SDimitry Andric #else
2460b57cec5SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
2470b57cec5SDimitry Andric   if (log)
2480b57cec5SDimitry Andric     log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
2490b57cec5SDimitry Andric                ", ptid = 0x%" PRIx64 ")",
2505ffd83dbSDimitry Andric                LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2510b57cec5SDimitry Andric #endif
2520b57cec5SDimitry Andric   return true;
2530b57cec5SDimitry Andric }
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric // The null plan is never done.
MischiefManaged()2560b57cec5SDimitry Andric bool ThreadPlanNull::MischiefManaged() {
2570b57cec5SDimitry Andric // The null plan is never done.
2580b57cec5SDimitry Andric #ifdef LLDB_CONFIGURATION_DEBUG
2590b57cec5SDimitry Andric   fprintf(stderr,
2600b57cec5SDimitry Andric           "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
2610b57cec5SDimitry Andric           ", ptid = 0x%" PRIx64 ")",
2625ffd83dbSDimitry Andric           LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2630b57cec5SDimitry Andric #else
2640b57cec5SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
2650b57cec5SDimitry Andric   if (log)
2660b57cec5SDimitry Andric     log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
2670b57cec5SDimitry Andric                ", ptid = 0x%" PRIx64 ")",
2685ffd83dbSDimitry Andric                LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2690b57cec5SDimitry Andric #endif
2700b57cec5SDimitry Andric   return false;
2710b57cec5SDimitry Andric }
2720b57cec5SDimitry Andric 
GetPlanRunState()2730b57cec5SDimitry Andric lldb::StateType ThreadPlanNull::GetPlanRunState() {
2740b57cec5SDimitry Andric // Not sure what to return here.  This is a dead thread.
2750b57cec5SDimitry Andric #ifdef LLDB_CONFIGURATION_DEBUG
2760b57cec5SDimitry Andric   fprintf(stderr,
2770b57cec5SDimitry Andric           "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
2780b57cec5SDimitry Andric           ", ptid = 0x%" PRIx64 ")",
2795ffd83dbSDimitry Andric           LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2800b57cec5SDimitry Andric #else
2810b57cec5SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
2820b57cec5SDimitry Andric   if (log)
2830b57cec5SDimitry Andric     log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
2840b57cec5SDimitry Andric                ", ptid = 0x%" PRIx64 ")",
2855ffd83dbSDimitry Andric                LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
2860b57cec5SDimitry Andric #endif
2870b57cec5SDimitry Andric   return eStateRunning;
2880b57cec5SDimitry Andric }
289