130fdc8d8SChris Lattner //===-- ThreadPlan.cpp ------------------------------------------*- C++ -*-===// 230fdc8d8SChris Lattner // 330fdc8d8SChris Lattner // The LLVM Compiler Infrastructure 430fdc8d8SChris Lattner // 530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source 630fdc8d8SChris Lattner // License. See LICENSE.TXT for details. 730fdc8d8SChris Lattner // 830fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 930fdc8d8SChris Lattner 1030fdc8d8SChris Lattner // C Includes 1130fdc8d8SChris Lattner // C++ Includes 1230fdc8d8SChris Lattner // Other libraries and framework includes 1330fdc8d8SChris Lattner // Project includes 14e65b2cf2SEugene Zelenko #include "lldb/Target/ThreadPlan.h" 1506e827ccSJim Ingham #include "lldb/Core/Debugger.h" 1630fdc8d8SChris Lattner #include "lldb/Core/State.h" 1706e827ccSJim Ingham #include "lldb/Target/Process.h" 18b9c1b51eSKate Stone #include "lldb/Target/RegisterContext.h" 1906e827ccSJim Ingham #include "lldb/Target/Target.h" 20b9c1b51eSKate Stone #include "lldb/Target/Thread.h" 21*6f9e6901SZachary Turner #include "lldb/Utility/Log.h" 2230fdc8d8SChris Lattner 2330fdc8d8SChris Lattner using namespace lldb; 2430fdc8d8SChris Lattner using namespace lldb_private; 2530fdc8d8SChris Lattner 2630fdc8d8SChris Lattner //---------------------------------------------------------------------- 2730fdc8d8SChris Lattner // ThreadPlan constructor 2830fdc8d8SChris Lattner //---------------------------------------------------------------------- 29b9c1b51eSKate Stone ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, 30b9c1b51eSKate Stone Vote stop_vote, Vote run_vote) 31b9c1b51eSKate Stone : m_thread(thread), m_stop_vote(stop_vote), m_run_vote(run_vote), 32b9c1b51eSKate Stone m_kind(kind), m_name(name), m_plan_complete_mutex(), 33b9c1b51eSKate Stone m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false), 34b9c1b51eSKate Stone m_plan_private(false), m_okay_to_discard(true), m_is_master_plan(false), 35b9c1b51eSKate Stone m_plan_succeeded(true) { 3630fdc8d8SChris Lattner SetID(GetNextID()); 3730fdc8d8SChris Lattner } 3830fdc8d8SChris Lattner 3930fdc8d8SChris Lattner //---------------------------------------------------------------------- 4030fdc8d8SChris Lattner // Destructor 4130fdc8d8SChris Lattner //---------------------------------------------------------------------- 42e65b2cf2SEugene Zelenko ThreadPlan::~ThreadPlan() = default; 4330fdc8d8SChris Lattner 44b9c1b51eSKate Stone bool ThreadPlan::PlanExplainsStop(Event *event_ptr) { 45b9c1b51eSKate Stone if (m_cached_plan_explains_stop == eLazyBoolCalculate) { 46221d51cfSJim Ingham bool actual_value = DoPlanExplainsStop(event_ptr); 47221d51cfSJim Ingham m_cached_plan_explains_stop = actual_value ? eLazyBoolYes : eLazyBoolNo; 48221d51cfSJim Ingham return actual_value; 49b9c1b51eSKate Stone } else { 50221d51cfSJim Ingham return m_cached_plan_explains_stop == eLazyBoolYes; 51221d51cfSJim Ingham } 52221d51cfSJim Ingham } 53221d51cfSJim Ingham 54b9c1b51eSKate Stone bool ThreadPlan::IsPlanComplete() { 5516ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); 5630fdc8d8SChris Lattner return m_plan_complete; 5730fdc8d8SChris Lattner } 5830fdc8d8SChris Lattner 59b9c1b51eSKate Stone void ThreadPlan::SetPlanComplete(bool success) { 6016ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); 6130fdc8d8SChris Lattner m_plan_complete = true; 62fbbfe6ecSJim Ingham m_plan_succeeded = success; 6330fdc8d8SChris Lattner } 6430fdc8d8SChris Lattner 65b9c1b51eSKate Stone bool ThreadPlan::MischiefManaged() { 6616ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); 6718de2fdcSJim Ingham // Mark the plan is complete, but don't override the success flag. 6830fdc8d8SChris Lattner m_plan_complete = true; 6930fdc8d8SChris Lattner return true; 7030fdc8d8SChris Lattner } 7130fdc8d8SChris Lattner 72b9c1b51eSKate Stone Vote ThreadPlan::ShouldReportStop(Event *event_ptr) { 735160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 742cad65a5SGreg Clayton 75b9c1b51eSKate Stone if (m_stop_vote == eVoteNoOpinion) { 7630fdc8d8SChris Lattner ThreadPlan *prev_plan = GetPreviousPlan(); 77b9c1b51eSKate Stone if (prev_plan) { 782cad65a5SGreg Clayton Vote prev_vote = prev_plan->ShouldReportStop(event_ptr); 7905d382c5SPavel Labath LLDB_LOG(log, "returning previous thread plan vote: {0}", prev_vote); 802cad65a5SGreg Clayton return prev_vote; 8130fdc8d8SChris Lattner } 822cad65a5SGreg Clayton } 8305d382c5SPavel Labath LLDB_LOG(log, "Returning vote: {0}", m_stop_vote); 8430fdc8d8SChris Lattner return m_stop_vote; 8530fdc8d8SChris Lattner } 8630fdc8d8SChris Lattner 87b9c1b51eSKate Stone Vote ThreadPlan::ShouldReportRun(Event *event_ptr) { 88b9c1b51eSKate Stone if (m_run_vote == eVoteNoOpinion) { 8930fdc8d8SChris Lattner ThreadPlan *prev_plan = GetPreviousPlan(); 9030fdc8d8SChris Lattner if (prev_plan) 9130fdc8d8SChris Lattner return prev_plan->ShouldReportRun(event_ptr); 9230fdc8d8SChris Lattner } 9330fdc8d8SChris Lattner return m_run_vote; 9430fdc8d8SChris Lattner } 9530fdc8d8SChris Lattner 96b9c1b51eSKate Stone bool ThreadPlan::StopOthers() { 9730fdc8d8SChris Lattner ThreadPlan *prev_plan; 9830fdc8d8SChris Lattner prev_plan = GetPreviousPlan(); 99e65b2cf2SEugene Zelenko return (prev_plan == nullptr) ? false : prev_plan->StopOthers(); 10030fdc8d8SChris Lattner } 10130fdc8d8SChris Lattner 102b9c1b51eSKate Stone void ThreadPlan::SetStopOthers(bool new_value) { 103f48169bbSJim Ingham // SetStopOthers doesn't work up the hierarchy. You have to set the 104f48169bbSJim Ingham // explicit ThreadPlan you want to affect. 105f48169bbSJim Ingham } 106f48169bbSJim Ingham 107b9c1b51eSKate Stone bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) { 108221d51cfSJim Ingham m_cached_plan_explains_stop = eLazyBoolCalculate; 109221d51cfSJim Ingham 110b9c1b51eSKate Stone if (current_plan) { 1115160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 11230fdc8d8SChris Lattner 113b9c1b51eSKate Stone if (log) { 1145ccbd294SGreg Clayton RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); 115ff1b5c42SEd Maste assert(reg_ctx); 1162cad65a5SGreg Clayton addr_t pc = reg_ctx->GetPC(); 1172cad65a5SGreg Clayton addr_t sp = reg_ctx->GetSP(); 1182cad65a5SGreg Clayton addr_t fp = reg_ctx->GetFP(); 119b9c1b51eSKate Stone log->Printf( 120b9c1b51eSKate Stone "%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64 121b9c1b51eSKate Stone ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", " 122b5c0d1ccSJim Ingham "plan = '%s', state = %s, stop others = %d", 123b9c1b51eSKate Stone __FUNCTION__, m_thread.GetIndexID(), static_cast<void *>(&m_thread), 124b9c1b51eSKate Stone m_thread.GetID(), static_cast<uint64_t>(pc), 125b9c1b51eSKate Stone static_cast<uint64_t>(sp), static_cast<uint64_t>(fp), m_name.c_str(), 126324a1036SSaleem Abdulrasool StateAsCString(resume_state), StopOthers()); 1272cad65a5SGreg Clayton } 12830fdc8d8SChris Lattner } 129221d51cfSJim Ingham return DoWillResume(resume_state, current_plan); 13030fdc8d8SChris Lattner } 13130fdc8d8SChris Lattner 132b9c1b51eSKate Stone lldb::user_id_t ThreadPlan::GetNextID() { 13330fdc8d8SChris Lattner static uint32_t g_nextPlanID = 0; 13430fdc8d8SChris Lattner return ++g_nextPlanID; 13530fdc8d8SChris Lattner } 13630fdc8d8SChris Lattner 137b9c1b51eSKate Stone void ThreadPlan::DidPush() {} 13830fdc8d8SChris Lattner 139b9c1b51eSKate Stone void ThreadPlan::WillPop() {} 14030fdc8d8SChris Lattner 141b9c1b51eSKate Stone bool ThreadPlan::OkayToDiscard() { 142e65b2cf2SEugene Zelenko return IsMasterPlan() ? m_okay_to_discard : true; 14330fdc8d8SChris Lattner } 14430fdc8d8SChris Lattner 145b9c1b51eSKate Stone lldb::StateType ThreadPlan::RunState() { 146b9c1b51eSKate Stone if (m_tracer_sp && m_tracer_sp->TracingEnabled() && 147b9c1b51eSKate Stone m_tracer_sp->SingleStepEnabled()) 14806e827ccSJim Ingham return eStateStepping; 14906e827ccSJim Ingham else 15006e827ccSJim Ingham return GetPlanRunState(); 15106e827ccSJim Ingham } 1526e10f149SGreg Clayton 153b9c1b51eSKate Stone bool ThreadPlan::IsUsuallyUnexplainedStopReason(lldb::StopReason reason) { 154b9c1b51eSKate Stone switch (reason) { 1559b03fa0cSJim Ingham case eStopReasonWatchpoint: 1569b03fa0cSJim Ingham case eStopReasonSignal: 1579b03fa0cSJim Ingham case eStopReasonException: 1589b03fa0cSJim Ingham case eStopReasonExec: 1599b03fa0cSJim Ingham case eStopReasonThreadExiting: 1609b03fa0cSJim Ingham case eStopReasonInstrumentation: 1619b03fa0cSJim Ingham return true; 1629b03fa0cSJim Ingham default: 1639b03fa0cSJim Ingham return false; 1649b03fa0cSJim Ingham } 1659b03fa0cSJim Ingham } 1669b03fa0cSJim Ingham 1676e10f149SGreg Clayton //---------------------------------------------------------------------- 1686e10f149SGreg Clayton // ThreadPlanNull 1696e10f149SGreg Clayton //---------------------------------------------------------------------- 1706e10f149SGreg Clayton 171b9c1b51eSKate Stone ThreadPlanNull::ThreadPlanNull(Thread &thread) 172b9c1b51eSKate Stone : ThreadPlan(ThreadPlan::eKindNull, "Null Thread Plan", thread, 173b9c1b51eSKate Stone eVoteNoOpinion, eVoteNoOpinion) {} 1746e10f149SGreg Clayton 175e65b2cf2SEugene Zelenko ThreadPlanNull::~ThreadPlanNull() = default; 1766e10f149SGreg Clayton 177b9c1b51eSKate Stone void ThreadPlanNull::GetDescription(Stream *s, lldb::DescriptionLevel level) { 1786e10f149SGreg Clayton s->PutCString("Null thread plan - thread has been destroyed."); 1796e10f149SGreg Clayton } 1806e10f149SGreg Clayton 181b9c1b51eSKate Stone bool ThreadPlanNull::ValidatePlan(Stream *error) { 1826e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 183b9c1b51eSKate Stone fprintf(stderr, 184b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 185b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 186b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 1876e10f149SGreg Clayton #else 1886e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 1896e10f149SGreg Clayton if (log) 190b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 191b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 192b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), 1936e10f149SGreg Clayton m_thread.GetProtocolID()); 1946e10f149SGreg Clayton #endif 1956e10f149SGreg Clayton return true; 1966e10f149SGreg Clayton } 1976e10f149SGreg Clayton 198b9c1b51eSKate Stone bool ThreadPlanNull::ShouldStop(Event *event_ptr) { 1996e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 200b9c1b51eSKate Stone fprintf(stderr, 201b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 202b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 203b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 2046e10f149SGreg Clayton #else 2056e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 2066e10f149SGreg Clayton if (log) 207b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 208b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 209b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), 2106e10f149SGreg Clayton m_thread.GetProtocolID()); 2116e10f149SGreg Clayton #endif 2126e10f149SGreg Clayton return true; 2136e10f149SGreg Clayton } 2146e10f149SGreg Clayton 215b9c1b51eSKate Stone bool ThreadPlanNull::WillStop() { 2166e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 217b9c1b51eSKate Stone fprintf(stderr, 218b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 219b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 220b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 2216e10f149SGreg Clayton #else 2226e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 2236e10f149SGreg Clayton if (log) 224b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 225b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 226b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), 2276e10f149SGreg Clayton m_thread.GetProtocolID()); 2286e10f149SGreg Clayton #endif 2296e10f149SGreg Clayton return true; 2306e10f149SGreg Clayton } 2316e10f149SGreg Clayton 232b9c1b51eSKate Stone bool ThreadPlanNull::DoPlanExplainsStop(Event *event_ptr) { 2336e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 234b9c1b51eSKate Stone fprintf(stderr, 235b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 236b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 237b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 2386e10f149SGreg Clayton #else 2396e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 2406e10f149SGreg Clayton if (log) 241b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 242b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 243b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), 2446e10f149SGreg Clayton m_thread.GetProtocolID()); 2456e10f149SGreg Clayton #endif 2466e10f149SGreg Clayton return true; 2476e10f149SGreg Clayton } 2486e10f149SGreg Clayton 2496e10f149SGreg Clayton // The null plan is never done. 250b9c1b51eSKate Stone bool ThreadPlanNull::MischiefManaged() { 2516e10f149SGreg Clayton // The null plan is never done. 2526e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 253b9c1b51eSKate Stone fprintf(stderr, 254b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 255b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 256b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 2576e10f149SGreg Clayton #else 2586e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 2596e10f149SGreg Clayton if (log) 260b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 261b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 262b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), 2636e10f149SGreg Clayton m_thread.GetProtocolID()); 2646e10f149SGreg Clayton #endif 2656e10f149SGreg Clayton return false; 2666e10f149SGreg Clayton } 2676e10f149SGreg Clayton 268b9c1b51eSKate Stone lldb::StateType ThreadPlanNull::GetPlanRunState() { 2696e10f149SGreg Clayton // Not sure what to return here. This is a dead thread. 2706e10f149SGreg Clayton #ifdef LLDB_CONFIGURATION_DEBUG 271b9c1b51eSKate Stone fprintf(stderr, 272b9c1b51eSKate Stone "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 273b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 274b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 2756e10f149SGreg Clayton #else 2766e10f149SGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 2776e10f149SGreg Clayton if (log) 278b9c1b51eSKate Stone log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 279b9c1b51eSKate Stone ", ptid = 0x%" PRIx64 ")", 280b9c1b51eSKate Stone LLVM_PRETTY_FUNCTION, m_thread.GetID(), 2816e10f149SGreg Clayton m_thread.GetProtocolID()); 2826e10f149SGreg Clayton #endif 2836e10f149SGreg Clayton return eStateRunning; 2846e10f149SGreg Clayton } 285