130fdc8d8SChris Lattner //===-- ThreadPlan.cpp ------------------------------------------*- C++ -*-===// 230fdc8d8SChris Lattner // 3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 5*2946cd70SChandler 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 //---------------------------------------------------------------------- 2230fdc8d8SChris Lattner // ThreadPlan constructor 2330fdc8d8SChris Lattner //---------------------------------------------------------------------- 24b9c1b51eSKate Stone ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, 25b9c1b51eSKate Stone Vote stop_vote, Vote run_vote) 26b9c1b51eSKate Stone : m_thread(thread), m_stop_vote(stop_vote), m_run_vote(run_vote), 27e103ae92SJonas Devlieghere m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false), 28b9c1b51eSKate Stone m_kind(kind), m_name(name), m_plan_complete_mutex(), 29b9c1b51eSKate Stone m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false), 30b9c1b51eSKate Stone m_plan_private(false), m_okay_to_discard(true), m_is_master_plan(false), 31b9c1b51eSKate Stone m_plan_succeeded(true) { 3230fdc8d8SChris Lattner SetID(GetNextID()); 3330fdc8d8SChris Lattner } 3430fdc8d8SChris Lattner 3530fdc8d8SChris Lattner //---------------------------------------------------------------------- 3630fdc8d8SChris Lattner // Destructor 3730fdc8d8SChris Lattner //---------------------------------------------------------------------- 38e65b2cf2SEugene Zelenko ThreadPlan::~ThreadPlan() = default; 3930fdc8d8SChris Lattner 40b9c1b51eSKate Stone bool ThreadPlan::PlanExplainsStop(Event *event_ptr) { 41b9c1b51eSKate Stone if (m_cached_plan_explains_stop == eLazyBoolCalculate) { 42221d51cfSJim Ingham bool actual_value = DoPlanExplainsStop(event_ptr); 43221d51cfSJim Ingham m_cached_plan_explains_stop = actual_value ? eLazyBoolYes : eLazyBoolNo; 44221d51cfSJim Ingham return actual_value; 45b9c1b51eSKate Stone } else { 46221d51cfSJim Ingham return m_cached_plan_explains_stop == eLazyBoolYes; 47221d51cfSJim Ingham } 48221d51cfSJim Ingham } 49221d51cfSJim Ingham 50b9c1b51eSKate Stone bool ThreadPlan::IsPlanComplete() { 5116ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); 5230fdc8d8SChris Lattner return m_plan_complete; 5330fdc8d8SChris Lattner } 5430fdc8d8SChris Lattner 55b9c1b51eSKate Stone void ThreadPlan::SetPlanComplete(bool success) { 5616ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); 5730fdc8d8SChris Lattner m_plan_complete = true; 58fbbfe6ecSJim Ingham m_plan_succeeded = success; 5930fdc8d8SChris Lattner } 6030fdc8d8SChris Lattner 61b9c1b51eSKate Stone bool ThreadPlan::MischiefManaged() { 6216ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); 6318de2fdcSJim Ingham // Mark the plan is complete, but don't override the success flag. 6430fdc8d8SChris Lattner m_plan_complete = true; 6530fdc8d8SChris Lattner return true; 6630fdc8d8SChris Lattner } 6730fdc8d8SChris Lattner 68b9c1b51eSKate Stone Vote ThreadPlan::ShouldReportStop(Event *event_ptr) { 695160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 702cad65a5SGreg Clayton 71b9c1b51eSKate Stone if (m_stop_vote == eVoteNoOpinion) { 7230fdc8d8SChris Lattner ThreadPlan *prev_plan = GetPreviousPlan(); 73b9c1b51eSKate Stone if (prev_plan) { 742cad65a5SGreg Clayton Vote prev_vote = prev_plan->ShouldReportStop(event_ptr); 7505d382c5SPavel Labath LLDB_LOG(log, "returning previous thread plan vote: {0}", prev_vote); 762cad65a5SGreg Clayton return prev_vote; 7730fdc8d8SChris Lattner } 782cad65a5SGreg Clayton } 7905d382c5SPavel Labath LLDB_LOG(log, "Returning vote: {0}", m_stop_vote); 8030fdc8d8SChris Lattner return m_stop_vote; 8130fdc8d8SChris Lattner } 8230fdc8d8SChris Lattner 83b9c1b51eSKate Stone Vote ThreadPlan::ShouldReportRun(Event *event_ptr) { 84b9c1b51eSKate Stone if (m_run_vote == eVoteNoOpinion) { 8530fdc8d8SChris Lattner ThreadPlan *prev_plan = GetPreviousPlan(); 8630fdc8d8SChris Lattner if (prev_plan) 8730fdc8d8SChris Lattner return prev_plan->ShouldReportRun(event_ptr); 8830fdc8d8SChris Lattner } 8930fdc8d8SChris Lattner return m_run_vote; 9030fdc8d8SChris Lattner } 9130fdc8d8SChris Lattner 92b9c1b51eSKate Stone bool ThreadPlan::StopOthers() { 9330fdc8d8SChris Lattner ThreadPlan *prev_plan; 9430fdc8d8SChris Lattner prev_plan = GetPreviousPlan(); 95e65b2cf2SEugene Zelenko return (prev_plan == nullptr) ? false : prev_plan->StopOthers(); 9630fdc8d8SChris Lattner } 9730fdc8d8SChris Lattner 98b9c1b51eSKate Stone void ThreadPlan::SetStopOthers(bool new_value) { 9905097246SAdrian Prantl // SetStopOthers doesn't work up the hierarchy. You have to set the explicit 10005097246SAdrian Prantl // ThreadPlan you want to affect. 101f48169bbSJim Ingham } 102f48169bbSJim Ingham 103b9c1b51eSKate Stone bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) { 104221d51cfSJim Ingham m_cached_plan_explains_stop = eLazyBoolCalculate; 105221d51cfSJim Ingham 106b9c1b51eSKate Stone if (current_plan) { 1075160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 10830fdc8d8SChris Lattner 109b9c1b51eSKate Stone if (log) { 1105ccbd294SGreg Clayton RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); 111ff1b5c42SEd Maste assert(reg_ctx); 1122cad65a5SGreg Clayton addr_t pc = reg_ctx->GetPC(); 1132cad65a5SGreg Clayton addr_t sp = reg_ctx->GetSP(); 1142cad65a5SGreg Clayton addr_t fp = reg_ctx->GetFP(); 115b9c1b51eSKate Stone log->Printf( 116b9c1b51eSKate Stone "%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64 117b9c1b51eSKate Stone ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", " 118b5c0d1ccSJim Ingham "plan = '%s', state = %s, stop others = %d", 119b9c1b51eSKate Stone __FUNCTION__, m_thread.GetIndexID(), static_cast<void *>(&m_thread), 120b9c1b51eSKate Stone m_thread.GetID(), static_cast<uint64_t>(pc), 121b9c1b51eSKate Stone static_cast<uint64_t>(sp), static_cast<uint64_t>(fp), m_name.c_str(), 122324a1036SSaleem Abdulrasool StateAsCString(resume_state), StopOthers()); 1232cad65a5SGreg Clayton } 12430fdc8d8SChris Lattner } 125221d51cfSJim Ingham return DoWillResume(resume_state, current_plan); 12630fdc8d8SChris Lattner } 12730fdc8d8SChris Lattner 128b9c1b51eSKate Stone lldb::user_id_t ThreadPlan::GetNextID() { 12930fdc8d8SChris Lattner static uint32_t g_nextPlanID = 0; 13030fdc8d8SChris Lattner return ++g_nextPlanID; 13130fdc8d8SChris Lattner } 13230fdc8d8SChris Lattner 133b9c1b51eSKate Stone void ThreadPlan::DidPush() {} 13430fdc8d8SChris Lattner 135b9c1b51eSKate Stone void ThreadPlan::WillPop() {} 13630fdc8d8SChris Lattner 137b9c1b51eSKate Stone bool ThreadPlan::OkayToDiscard() { 138e65b2cf2SEugene Zelenko return IsMasterPlan() ? m_okay_to_discard : true; 13930fdc8d8SChris Lattner } 14030fdc8d8SChris Lattner 141b9c1b51eSKate Stone lldb::StateType ThreadPlan::RunState() { 142b9c1b51eSKate Stone if (m_tracer_sp && m_tracer_sp->TracingEnabled() && 143b9c1b51eSKate Stone m_tracer_sp->SingleStepEnabled()) 14406e827ccSJim Ingham return eStateStepping; 14506e827ccSJim Ingham else 14606e827ccSJim Ingham return GetPlanRunState(); 14706e827ccSJim Ingham } 1486e10f149SGreg Clayton 149b9c1b51eSKate Stone bool ThreadPlan::IsUsuallyUnexplainedStopReason(lldb::StopReason reason) { 150b9c1b51eSKate Stone switch (reason) { 1519b03fa0cSJim Ingham case eStopReasonWatchpoint: 1529b03fa0cSJim Ingham case eStopReasonSignal: 1539b03fa0cSJim Ingham case eStopReasonException: 1549b03fa0cSJim Ingham case eStopReasonExec: 1559b03fa0cSJim Ingham case eStopReasonThreadExiting: 1569b03fa0cSJim Ingham case eStopReasonInstrumentation: 1579b03fa0cSJim Ingham return true; 1589b03fa0cSJim Ingham default: 1599b03fa0cSJim Ingham return false; 1609b03fa0cSJim Ingham } 1619b03fa0cSJim Ingham } 1629b03fa0cSJim Ingham 1636e10f149SGreg Clayton //---------------------------------------------------------------------- 1646e10f149SGreg Clayton // ThreadPlanNull 1656e10f149SGreg Clayton //---------------------------------------------------------------------- 1666e10f149SGreg Clayton 167b9c1b51eSKate Stone ThreadPlanNull::ThreadPlanNull(Thread &thread) 168b9c1b51eSKate Stone : ThreadPlan(ThreadPlan::eKindNull, "Null Thread Plan", thread, 169b9c1b51eSKate Stone eVoteNoOpinion, eVoteNoOpinion) {} 1706e10f149SGreg Clayton 171e65b2cf2SEugene Zelenko ThreadPlanNull::~ThreadPlanNull() = default; 1726e10f149SGreg Clayton 173b9c1b51eSKate Stone void ThreadPlanNull::GetDescription(Stream *s, lldb::DescriptionLevel level) { 1746e10f149SGreg Clayton s->PutCString("Null thread plan - thread has been destroyed."); 1756e10f149SGreg Clayton } 1766e10f149SGreg Clayton 177b9c1b51eSKate Stone bool ThreadPlanNull::ValidatePlan(Stream *error) { 1786e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 179b9c1b51eSKate Stone fprintf(stderr, 180b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 181b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 182b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 1836e10f149SGreg Clayton #else 1846e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 1856e10f149SGreg Clayton if (log) 186b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 187b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 188b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), 1896e10f149SGreg Clayton m_thread.GetProtocolID()); 1906e10f149SGreg Clayton #endif 1916e10f149SGreg Clayton return true; 1926e10f149SGreg Clayton } 1936e10f149SGreg Clayton 194b9c1b51eSKate Stone bool ThreadPlanNull::ShouldStop(Event *event_ptr) { 1956e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 196b9c1b51eSKate Stone fprintf(stderr, 197b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 198b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 199b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 2006e10f149SGreg Clayton #else 2016e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 2026e10f149SGreg Clayton if (log) 203b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 204b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 205b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), 2066e10f149SGreg Clayton m_thread.GetProtocolID()); 2076e10f149SGreg Clayton #endif 2086e10f149SGreg Clayton return true; 2096e10f149SGreg Clayton } 2106e10f149SGreg Clayton 211b9c1b51eSKate Stone bool ThreadPlanNull::WillStop() { 2126e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 213b9c1b51eSKate Stone fprintf(stderr, 214b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 215b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 216b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 2176e10f149SGreg Clayton #else 2186e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 2196e10f149SGreg Clayton if (log) 220b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 221b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 222b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), 2236e10f149SGreg Clayton m_thread.GetProtocolID()); 2246e10f149SGreg Clayton #endif 2256e10f149SGreg Clayton return true; 2266e10f149SGreg Clayton } 2276e10f149SGreg Clayton 228b9c1b51eSKate Stone bool ThreadPlanNull::DoPlanExplainsStop(Event *event_ptr) { 2296e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 230b9c1b51eSKate Stone fprintf(stderr, 231b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 232b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 233b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 2346e10f149SGreg Clayton #else 2356e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 2366e10f149SGreg Clayton if (log) 237b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 238b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 239b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), 2406e10f149SGreg Clayton m_thread.GetProtocolID()); 2416e10f149SGreg Clayton #endif 2426e10f149SGreg Clayton return true; 2436e10f149SGreg Clayton } 2446e10f149SGreg Clayton 2456e10f149SGreg Clayton // The null plan is never done. 246b9c1b51eSKate Stone bool ThreadPlanNull::MischiefManaged() { 2476e10f149SGreg Clayton // The null plan is never done. 2486e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 249b9c1b51eSKate Stone fprintf(stderr, 250b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 251b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 252b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 2536e10f149SGreg Clayton #else 2546e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 2556e10f149SGreg Clayton if (log) 256b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 257b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 258b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), 2596e10f149SGreg Clayton m_thread.GetProtocolID()); 2606e10f149SGreg Clayton #endif 2616e10f149SGreg Clayton return false; 2626e10f149SGreg Clayton } 2636e10f149SGreg Clayton 264b9c1b51eSKate Stone lldb::StateType ThreadPlanNull::GetPlanRunState() { 2656e10f149SGreg Clayton // Not sure what to return here. This is a dead thread. 2666e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 267b9c1b51eSKate Stone fprintf(stderr, 268b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 269b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 270b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 2716e10f149SGreg Clayton #else 2726e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 2736e10f149SGreg Clayton if (log) 274b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 275b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 276b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), 2776e10f149SGreg Clayton m_thread.GetProtocolID()); 2786e10f149SGreg Clayton #endif 2796e10f149SGreg Clayton return eStateRunning; 2806e10f149SGreg Clayton } 281