180814287SRaphael Isemann //===-- ThreadPlan.cpp ----------------------------------------------------===// 230fdc8d8SChris Lattner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 630fdc8d8SChris Lattner // 730fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 830fdc8d8SChris Lattner 9e65b2cf2SEugene Zelenko #include "lldb/Target/ThreadPlan.h" 1006e827ccSJim Ingham #include "lldb/Core/Debugger.h" 1106e827ccSJim Ingham #include "lldb/Target/Process.h" 12b9c1b51eSKate Stone #include "lldb/Target/RegisterContext.h" 1306e827ccSJim Ingham #include "lldb/Target/Target.h" 14b9c1b51eSKate Stone #include "lldb/Target/Thread.h" 156f9e6901SZachary Turner #include "lldb/Utility/Log.h" 16d821c997SPavel Labath #include "lldb/Utility/State.h" 1730fdc8d8SChris Lattner 1830fdc8d8SChris Lattner using namespace lldb; 1930fdc8d8SChris Lattner using namespace lldb_private; 2030fdc8d8SChris Lattner 2130fdc8d8SChris Lattner // ThreadPlan constructor 22b9c1b51eSKate Stone ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, 239d3b9e57SDave Lee Vote report_stop_vote, Vote report_run_vote) 24e4598dc0SJim Ingham : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), 259d3b9e57SDave Lee m_report_stop_vote(report_stop_vote), m_report_run_vote(report_run_vote), 26e103ae92SJonas Devlieghere m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false), 273ccd454cSEric Christopher m_thread(&thread), m_kind(kind), m_name(name), m_plan_complete_mutex(), 28b9c1b51eSKate Stone m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false), 29*04cbfa95SQuinn Pham m_plan_private(false), m_okay_to_discard(true), 30*04cbfa95SQuinn Pham m_is_controlling_plan(false), m_plan_succeeded(true) { 3130fdc8d8SChris Lattner SetID(GetNextID()); 3230fdc8d8SChris Lattner } 3330fdc8d8SChris Lattner 3430fdc8d8SChris Lattner // Destructor 35e65b2cf2SEugene Zelenko ThreadPlan::~ThreadPlan() = default; 3630fdc8d8SChris Lattner 3761e8e688SJim Ingham Target &ThreadPlan::GetTarget() { return m_process.GetTarget(); } 3861e8e688SJim Ingham 3961e8e688SJim Ingham const Target &ThreadPlan::GetTarget() const { return m_process.GetTarget(); } 4061e8e688SJim Ingham 41e4598dc0SJim Ingham Thread &ThreadPlan::GetThread() { 42e4598dc0SJim Ingham if (m_thread) 43e4598dc0SJim Ingham return *m_thread; 44e4598dc0SJim Ingham 45e4598dc0SJim Ingham ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid); 46e4598dc0SJim Ingham m_thread = thread_sp.get(); 47e4598dc0SJim Ingham return *m_thread; 48e4598dc0SJim Ingham } 49e4598dc0SJim Ingham 50b9c1b51eSKate Stone bool ThreadPlan::PlanExplainsStop(Event *event_ptr) { 51b9c1b51eSKate Stone if (m_cached_plan_explains_stop == eLazyBoolCalculate) { 52221d51cfSJim Ingham bool actual_value = DoPlanExplainsStop(event_ptr); 53606c3be8SDave Lee CachePlanExplainsStop(actual_value); 54221d51cfSJim Ingham return actual_value; 55b9c1b51eSKate Stone } else { 56221d51cfSJim Ingham return m_cached_plan_explains_stop == eLazyBoolYes; 57221d51cfSJim Ingham } 58221d51cfSJim Ingham } 59221d51cfSJim Ingham 60b9c1b51eSKate Stone bool ThreadPlan::IsPlanComplete() { 6116ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); 6230fdc8d8SChris Lattner return m_plan_complete; 6330fdc8d8SChris Lattner } 6430fdc8d8SChris Lattner 65b9c1b51eSKate Stone void ThreadPlan::SetPlanComplete(bool success) { 6616ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); 6730fdc8d8SChris Lattner m_plan_complete = true; 68fbbfe6ecSJim Ingham m_plan_succeeded = success; 6930fdc8d8SChris Lattner } 7030fdc8d8SChris Lattner 71b9c1b51eSKate Stone bool ThreadPlan::MischiefManaged() { 7216ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); 7318de2fdcSJim Ingham // Mark the plan is complete, but don't override the success flag. 7430fdc8d8SChris Lattner m_plan_complete = true; 7530fdc8d8SChris Lattner return true; 7630fdc8d8SChris Lattner } 7730fdc8d8SChris Lattner 78b9c1b51eSKate Stone Vote ThreadPlan::ShouldReportStop(Event *event_ptr) { 795160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 802cad65a5SGreg Clayton 819d3b9e57SDave Lee if (m_report_stop_vote == eVoteNoOpinion) { 8230fdc8d8SChris Lattner ThreadPlan *prev_plan = GetPreviousPlan(); 83b9c1b51eSKate Stone if (prev_plan) { 842cad65a5SGreg Clayton Vote prev_vote = prev_plan->ShouldReportStop(event_ptr); 8505d382c5SPavel Labath LLDB_LOG(log, "returning previous thread plan vote: {0}", prev_vote); 862cad65a5SGreg Clayton return prev_vote; 8730fdc8d8SChris Lattner } 882cad65a5SGreg Clayton } 899d3b9e57SDave Lee LLDB_LOG(log, "Returning vote: {0}", m_report_stop_vote); 909d3b9e57SDave Lee return m_report_stop_vote; 9130fdc8d8SChris Lattner } 9230fdc8d8SChris Lattner 93b9c1b51eSKate Stone Vote ThreadPlan::ShouldReportRun(Event *event_ptr) { 949d3b9e57SDave Lee if (m_report_run_vote == eVoteNoOpinion) { 9530fdc8d8SChris Lattner ThreadPlan *prev_plan = GetPreviousPlan(); 9630fdc8d8SChris Lattner if (prev_plan) 9730fdc8d8SChris Lattner return prev_plan->ShouldReportRun(event_ptr); 9830fdc8d8SChris Lattner } 999d3b9e57SDave Lee return m_report_run_vote; 10030fdc8d8SChris Lattner } 10130fdc8d8SChris Lattner 1024bb62448SWalter Erquinigo void ThreadPlan::ClearThreadCache() { m_thread = nullptr; } 1034bb62448SWalter Erquinigo 104b9c1b51eSKate Stone bool ThreadPlan::StopOthers() { 10530fdc8d8SChris Lattner ThreadPlan *prev_plan; 10630fdc8d8SChris Lattner prev_plan = GetPreviousPlan(); 107e65b2cf2SEugene Zelenko return (prev_plan == nullptr) ? false : prev_plan->StopOthers(); 10830fdc8d8SChris Lattner } 10930fdc8d8SChris Lattner 110b9c1b51eSKate Stone void ThreadPlan::SetStopOthers(bool new_value) { 11105097246SAdrian Prantl // SetStopOthers doesn't work up the hierarchy. You have to set the explicit 11205097246SAdrian Prantl // ThreadPlan you want to affect. 113f48169bbSJim Ingham } 114f48169bbSJim Ingham 115b9c1b51eSKate Stone bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) { 116221d51cfSJim Ingham m_cached_plan_explains_stop = eLazyBoolCalculate; 117221d51cfSJim Ingham 118b9c1b51eSKate Stone if (current_plan) { 1195160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 12030fdc8d8SChris Lattner 121b9c1b51eSKate Stone if (log) { 122e4598dc0SJim Ingham RegisterContext *reg_ctx = GetThread().GetRegisterContext().get(); 123ff1b5c42SEd Maste assert(reg_ctx); 1242cad65a5SGreg Clayton addr_t pc = reg_ctx->GetPC(); 1252cad65a5SGreg Clayton addr_t sp = reg_ctx->GetSP(); 1262cad65a5SGreg Clayton addr_t fp = reg_ctx->GetFP(); 12763e5fb76SJonas Devlieghere LLDB_LOGF( 12863e5fb76SJonas Devlieghere log, 129b9c1b51eSKate Stone "%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64 130b9c1b51eSKate Stone ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", " 131b5c0d1ccSJim Ingham "plan = '%s', state = %s, stop others = %d", 132e4598dc0SJim Ingham __FUNCTION__, GetThread().GetIndexID(), 133e4598dc0SJim Ingham static_cast<void *>(&GetThread()), m_tid, static_cast<uint64_t>(pc), 134b9c1b51eSKate Stone static_cast<uint64_t>(sp), static_cast<uint64_t>(fp), m_name.c_str(), 135324a1036SSaleem Abdulrasool StateAsCString(resume_state), StopOthers()); 1362cad65a5SGreg Clayton } 13730fdc8d8SChris Lattner } 1381893065dSJim Ingham bool success = DoWillResume(resume_state, current_plan); 1394bb62448SWalter Erquinigo ClearThreadCache(); // We don't cache the thread pointer over resumes. This 1401893065dSJim Ingham // Thread might go away, and another Thread represent 1411893065dSJim Ingham // the same underlying object on a later stop. 1421893065dSJim Ingham return success; 14330fdc8d8SChris Lattner } 14430fdc8d8SChris Lattner 145b9c1b51eSKate Stone lldb::user_id_t ThreadPlan::GetNextID() { 14630fdc8d8SChris Lattner static uint32_t g_nextPlanID = 0; 14730fdc8d8SChris Lattner return ++g_nextPlanID; 14830fdc8d8SChris Lattner } 14930fdc8d8SChris Lattner 150b9c1b51eSKate Stone void ThreadPlan::DidPush() {} 15130fdc8d8SChris Lattner 15241d0b20cSDave Lee void ThreadPlan::DidPop() {} 15330fdc8d8SChris Lattner 154b9c1b51eSKate Stone bool ThreadPlan::OkayToDiscard() { 155*04cbfa95SQuinn Pham return IsControllingPlan() ? m_okay_to_discard : true; 15630fdc8d8SChris Lattner } 15730fdc8d8SChris Lattner 158b9c1b51eSKate Stone lldb::StateType ThreadPlan::RunState() { 15922f0aa0dSDave Lee if (m_tracer_sp && m_tracer_sp->TracingEnabled()) 16006e827ccSJim Ingham return eStateStepping; 16106e827ccSJim Ingham else 16206e827ccSJim Ingham return GetPlanRunState(); 16306e827ccSJim Ingham } 1646e10f149SGreg Clayton 165b9c1b51eSKate Stone bool ThreadPlan::IsUsuallyUnexplainedStopReason(lldb::StopReason reason) { 166b9c1b51eSKate Stone switch (reason) { 1679b03fa0cSJim Ingham case eStopReasonWatchpoint: 1689b03fa0cSJim Ingham case eStopReasonSignal: 1699b03fa0cSJim Ingham case eStopReasonException: 1709b03fa0cSJim Ingham case eStopReasonExec: 1719b03fa0cSJim Ingham case eStopReasonThreadExiting: 1729b03fa0cSJim Ingham case eStopReasonInstrumentation: 1739b03fa0cSJim Ingham return true; 1749b03fa0cSJim Ingham default: 1759b03fa0cSJim Ingham return false; 1769b03fa0cSJim Ingham } 1779b03fa0cSJim Ingham } 1789b03fa0cSJim Ingham 1796e10f149SGreg Clayton // ThreadPlanNull 1806e10f149SGreg Clayton 181b9c1b51eSKate Stone ThreadPlanNull::ThreadPlanNull(Thread &thread) 182b9c1b51eSKate Stone : ThreadPlan(ThreadPlan::eKindNull, "Null Thread Plan", thread, 183b9c1b51eSKate Stone eVoteNoOpinion, eVoteNoOpinion) {} 1846e10f149SGreg Clayton 185e65b2cf2SEugene Zelenko ThreadPlanNull::~ThreadPlanNull() = default; 1866e10f149SGreg Clayton 187b9c1b51eSKate Stone void ThreadPlanNull::GetDescription(Stream *s, lldb::DescriptionLevel level) { 1886e10f149SGreg Clayton s->PutCString("Null thread plan - thread has been destroyed."); 1896e10f149SGreg Clayton } 1906e10f149SGreg Clayton 191b9c1b51eSKate Stone bool ThreadPlanNull::ValidatePlan(Stream *error) { 1926e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 193b9c1b51eSKate Stone fprintf(stderr, 194b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 195b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 196e4598dc0SJim Ingham LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 1976e10f149SGreg Clayton #else 1986e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 1996e10f149SGreg Clayton if (log) 200b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 201b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 202e4598dc0SJim Ingham LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 2036e10f149SGreg Clayton #endif 2046e10f149SGreg Clayton return true; 2056e10f149SGreg Clayton } 2066e10f149SGreg Clayton 207b9c1b51eSKate Stone bool ThreadPlanNull::ShouldStop(Event *event_ptr) { 2086e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 209b9c1b51eSKate Stone fprintf(stderr, 210b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 211b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 212e4598dc0SJim Ingham LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 2136e10f149SGreg Clayton #else 2146e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 2156e10f149SGreg Clayton if (log) 216b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 217b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 218e4598dc0SJim Ingham LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 2196e10f149SGreg Clayton #endif 2206e10f149SGreg Clayton return true; 2216e10f149SGreg Clayton } 2226e10f149SGreg Clayton 223b9c1b51eSKate Stone bool ThreadPlanNull::WillStop() { 2246e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 225b9c1b51eSKate Stone fprintf(stderr, 226b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 227b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 228e4598dc0SJim Ingham LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 2296e10f149SGreg Clayton #else 2306e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 2316e10f149SGreg Clayton if (log) 232b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 233b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 234e4598dc0SJim Ingham LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 2356e10f149SGreg Clayton #endif 2366e10f149SGreg Clayton return true; 2376e10f149SGreg Clayton } 2386e10f149SGreg Clayton 239b9c1b51eSKate Stone bool ThreadPlanNull::DoPlanExplainsStop(Event *event_ptr) { 2406e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 241b9c1b51eSKate Stone fprintf(stderr, 242b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 243b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 24496612252SWalter Erquinigo LLVM_PRETTY_FUNCTION, GetThread().GetID(), GetThread().GetProtocolID()); 2456e10f149SGreg Clayton #else 2466e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 2476e10f149SGreg Clayton if (log) 248b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 249b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 250e4598dc0SJim Ingham LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 2516e10f149SGreg Clayton #endif 2526e10f149SGreg Clayton return true; 2536e10f149SGreg Clayton } 2546e10f149SGreg Clayton 2556e10f149SGreg Clayton // The null plan is never done. 256b9c1b51eSKate Stone bool ThreadPlanNull::MischiefManaged() { 2576e10f149SGreg Clayton // The null plan is never done. 2586e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 259b9c1b51eSKate Stone fprintf(stderr, 260b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 261b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 262e4598dc0SJim Ingham LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 2636e10f149SGreg Clayton #else 2646e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 2656e10f149SGreg Clayton if (log) 266b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 267b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 268e4598dc0SJim Ingham LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 2696e10f149SGreg Clayton #endif 2706e10f149SGreg Clayton return false; 2716e10f149SGreg Clayton } 2726e10f149SGreg Clayton 273b9c1b51eSKate Stone lldb::StateType ThreadPlanNull::GetPlanRunState() { 2746e10f149SGreg Clayton // Not sure what to return here. This is a dead thread. 2756e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 276b9c1b51eSKate Stone fprintf(stderr, 277b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 278b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 279e4598dc0SJim Ingham LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 2806e10f149SGreg Clayton #else 2816e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 2826e10f149SGreg Clayton if (log) 283b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 284b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 285e4598dc0SJim Ingham LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 2866e10f149SGreg Clayton #endif 2876e10f149SGreg Clayton return eStateRunning; 2886e10f149SGreg Clayton } 289