1*061da546Spatrick //===-- ThreadPlan.cpp ------------------------------------------*- C++ -*-===// 2*061da546Spatrick // 3*061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*061da546Spatrick // See https://llvm.org/LICENSE.txt for license information. 5*061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*061da546Spatrick // 7*061da546Spatrick //===----------------------------------------------------------------------===// 8*061da546Spatrick 9*061da546Spatrick #include "lldb/Target/ThreadPlan.h" 10*061da546Spatrick #include "lldb/Core/Debugger.h" 11*061da546Spatrick #include "lldb/Target/Process.h" 12*061da546Spatrick #include "lldb/Target/RegisterContext.h" 13*061da546Spatrick #include "lldb/Target/Target.h" 14*061da546Spatrick #include "lldb/Target/Thread.h" 15*061da546Spatrick #include "lldb/Utility/Log.h" 16*061da546Spatrick #include "lldb/Utility/State.h" 17*061da546Spatrick 18*061da546Spatrick using namespace lldb; 19*061da546Spatrick using namespace lldb_private; 20*061da546Spatrick 21*061da546Spatrick // ThreadPlan constructor 22*061da546Spatrick ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, 23*061da546Spatrick Vote stop_vote, Vote run_vote) 24*061da546Spatrick : m_thread(thread), m_stop_vote(stop_vote), m_run_vote(run_vote), 25*061da546Spatrick m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false), 26*061da546Spatrick m_kind(kind), m_name(name), m_plan_complete_mutex(), 27*061da546Spatrick m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false), 28*061da546Spatrick m_plan_private(false), m_okay_to_discard(true), m_is_master_plan(false), 29*061da546Spatrick m_plan_succeeded(true) { 30*061da546Spatrick SetID(GetNextID()); 31*061da546Spatrick } 32*061da546Spatrick 33*061da546Spatrick // Destructor 34*061da546Spatrick ThreadPlan::~ThreadPlan() = default; 35*061da546Spatrick 36*061da546Spatrick bool ThreadPlan::PlanExplainsStop(Event *event_ptr) { 37*061da546Spatrick if (m_cached_plan_explains_stop == eLazyBoolCalculate) { 38*061da546Spatrick bool actual_value = DoPlanExplainsStop(event_ptr); 39*061da546Spatrick m_cached_plan_explains_stop = actual_value ? eLazyBoolYes : eLazyBoolNo; 40*061da546Spatrick return actual_value; 41*061da546Spatrick } else { 42*061da546Spatrick return m_cached_plan_explains_stop == eLazyBoolYes; 43*061da546Spatrick } 44*061da546Spatrick } 45*061da546Spatrick 46*061da546Spatrick bool ThreadPlan::IsPlanComplete() { 47*061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); 48*061da546Spatrick return m_plan_complete; 49*061da546Spatrick } 50*061da546Spatrick 51*061da546Spatrick void ThreadPlan::SetPlanComplete(bool success) { 52*061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); 53*061da546Spatrick m_plan_complete = true; 54*061da546Spatrick m_plan_succeeded = success; 55*061da546Spatrick } 56*061da546Spatrick 57*061da546Spatrick bool ThreadPlan::MischiefManaged() { 58*061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); 59*061da546Spatrick // Mark the plan is complete, but don't override the success flag. 60*061da546Spatrick m_plan_complete = true; 61*061da546Spatrick return true; 62*061da546Spatrick } 63*061da546Spatrick 64*061da546Spatrick Vote ThreadPlan::ShouldReportStop(Event *event_ptr) { 65*061da546Spatrick Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 66*061da546Spatrick 67*061da546Spatrick if (m_stop_vote == eVoteNoOpinion) { 68*061da546Spatrick ThreadPlan *prev_plan = GetPreviousPlan(); 69*061da546Spatrick if (prev_plan) { 70*061da546Spatrick Vote prev_vote = prev_plan->ShouldReportStop(event_ptr); 71*061da546Spatrick LLDB_LOG(log, "returning previous thread plan vote: {0}", prev_vote); 72*061da546Spatrick return prev_vote; 73*061da546Spatrick } 74*061da546Spatrick } 75*061da546Spatrick LLDB_LOG(log, "Returning vote: {0}", m_stop_vote); 76*061da546Spatrick return m_stop_vote; 77*061da546Spatrick } 78*061da546Spatrick 79*061da546Spatrick Vote ThreadPlan::ShouldReportRun(Event *event_ptr) { 80*061da546Spatrick if (m_run_vote == eVoteNoOpinion) { 81*061da546Spatrick ThreadPlan *prev_plan = GetPreviousPlan(); 82*061da546Spatrick if (prev_plan) 83*061da546Spatrick return prev_plan->ShouldReportRun(event_ptr); 84*061da546Spatrick } 85*061da546Spatrick return m_run_vote; 86*061da546Spatrick } 87*061da546Spatrick 88*061da546Spatrick bool ThreadPlan::StopOthers() { 89*061da546Spatrick ThreadPlan *prev_plan; 90*061da546Spatrick prev_plan = GetPreviousPlan(); 91*061da546Spatrick return (prev_plan == nullptr) ? false : prev_plan->StopOthers(); 92*061da546Spatrick } 93*061da546Spatrick 94*061da546Spatrick void ThreadPlan::SetStopOthers(bool new_value) { 95*061da546Spatrick // SetStopOthers doesn't work up the hierarchy. You have to set the explicit 96*061da546Spatrick // ThreadPlan you want to affect. 97*061da546Spatrick } 98*061da546Spatrick 99*061da546Spatrick bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) { 100*061da546Spatrick m_cached_plan_explains_stop = eLazyBoolCalculate; 101*061da546Spatrick 102*061da546Spatrick if (current_plan) { 103*061da546Spatrick Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 104*061da546Spatrick 105*061da546Spatrick if (log) { 106*061da546Spatrick RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); 107*061da546Spatrick assert(reg_ctx); 108*061da546Spatrick addr_t pc = reg_ctx->GetPC(); 109*061da546Spatrick addr_t sp = reg_ctx->GetSP(); 110*061da546Spatrick addr_t fp = reg_ctx->GetFP(); 111*061da546Spatrick LLDB_LOGF( 112*061da546Spatrick log, 113*061da546Spatrick "%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64 114*061da546Spatrick ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", " 115*061da546Spatrick "plan = '%s', state = %s, stop others = %d", 116*061da546Spatrick __FUNCTION__, m_thread.GetIndexID(), static_cast<void *>(&m_thread), 117*061da546Spatrick m_thread.GetID(), static_cast<uint64_t>(pc), 118*061da546Spatrick static_cast<uint64_t>(sp), static_cast<uint64_t>(fp), m_name.c_str(), 119*061da546Spatrick StateAsCString(resume_state), StopOthers()); 120*061da546Spatrick } 121*061da546Spatrick } 122*061da546Spatrick return DoWillResume(resume_state, current_plan); 123*061da546Spatrick } 124*061da546Spatrick 125*061da546Spatrick lldb::user_id_t ThreadPlan::GetNextID() { 126*061da546Spatrick static uint32_t g_nextPlanID = 0; 127*061da546Spatrick return ++g_nextPlanID; 128*061da546Spatrick } 129*061da546Spatrick 130*061da546Spatrick void ThreadPlan::DidPush() {} 131*061da546Spatrick 132*061da546Spatrick void ThreadPlan::WillPop() {} 133*061da546Spatrick 134*061da546Spatrick bool ThreadPlan::OkayToDiscard() { 135*061da546Spatrick return IsMasterPlan() ? m_okay_to_discard : true; 136*061da546Spatrick } 137*061da546Spatrick 138*061da546Spatrick lldb::StateType ThreadPlan::RunState() { 139*061da546Spatrick if (m_tracer_sp && m_tracer_sp->TracingEnabled() && 140*061da546Spatrick m_tracer_sp->SingleStepEnabled()) 141*061da546Spatrick return eStateStepping; 142*061da546Spatrick else 143*061da546Spatrick return GetPlanRunState(); 144*061da546Spatrick } 145*061da546Spatrick 146*061da546Spatrick bool ThreadPlan::IsUsuallyUnexplainedStopReason(lldb::StopReason reason) { 147*061da546Spatrick switch (reason) { 148*061da546Spatrick case eStopReasonWatchpoint: 149*061da546Spatrick case eStopReasonSignal: 150*061da546Spatrick case eStopReasonException: 151*061da546Spatrick case eStopReasonExec: 152*061da546Spatrick case eStopReasonThreadExiting: 153*061da546Spatrick case eStopReasonInstrumentation: 154*061da546Spatrick return true; 155*061da546Spatrick default: 156*061da546Spatrick return false; 157*061da546Spatrick } 158*061da546Spatrick } 159*061da546Spatrick 160*061da546Spatrick // ThreadPlanNull 161*061da546Spatrick 162*061da546Spatrick ThreadPlanNull::ThreadPlanNull(Thread &thread) 163*061da546Spatrick : ThreadPlan(ThreadPlan::eKindNull, "Null Thread Plan", thread, 164*061da546Spatrick eVoteNoOpinion, eVoteNoOpinion) {} 165*061da546Spatrick 166*061da546Spatrick ThreadPlanNull::~ThreadPlanNull() = default; 167*061da546Spatrick 168*061da546Spatrick void ThreadPlanNull::GetDescription(Stream *s, lldb::DescriptionLevel level) { 169*061da546Spatrick s->PutCString("Null thread plan - thread has been destroyed."); 170*061da546Spatrick } 171*061da546Spatrick 172*061da546Spatrick bool ThreadPlanNull::ValidatePlan(Stream *error) { 173*061da546Spatrick #ifdef LLDB_CONFIGURATION_DEBUG 174*061da546Spatrick fprintf(stderr, 175*061da546Spatrick "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 176*061da546Spatrick ", ptid = 0x%" PRIx64 ")", 177*061da546Spatrick LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 178*061da546Spatrick #else 179*061da546Spatrick Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 180*061da546Spatrick if (log) 181*061da546Spatrick log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 182*061da546Spatrick ", ptid = 0x%" PRIx64 ")", 183*061da546Spatrick LLVM_PRETTY_FUNCTION, m_thread.GetID(), 184*061da546Spatrick m_thread.GetProtocolID()); 185*061da546Spatrick #endif 186*061da546Spatrick return true; 187*061da546Spatrick } 188*061da546Spatrick 189*061da546Spatrick bool ThreadPlanNull::ShouldStop(Event *event_ptr) { 190*061da546Spatrick #ifdef LLDB_CONFIGURATION_DEBUG 191*061da546Spatrick fprintf(stderr, 192*061da546Spatrick "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 193*061da546Spatrick ", ptid = 0x%" PRIx64 ")", 194*061da546Spatrick LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 195*061da546Spatrick #else 196*061da546Spatrick Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 197*061da546Spatrick if (log) 198*061da546Spatrick log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 199*061da546Spatrick ", ptid = 0x%" PRIx64 ")", 200*061da546Spatrick LLVM_PRETTY_FUNCTION, m_thread.GetID(), 201*061da546Spatrick m_thread.GetProtocolID()); 202*061da546Spatrick #endif 203*061da546Spatrick return true; 204*061da546Spatrick } 205*061da546Spatrick 206*061da546Spatrick bool ThreadPlanNull::WillStop() { 207*061da546Spatrick #ifdef LLDB_CONFIGURATION_DEBUG 208*061da546Spatrick fprintf(stderr, 209*061da546Spatrick "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 210*061da546Spatrick ", ptid = 0x%" PRIx64 ")", 211*061da546Spatrick LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 212*061da546Spatrick #else 213*061da546Spatrick Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 214*061da546Spatrick if (log) 215*061da546Spatrick log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 216*061da546Spatrick ", ptid = 0x%" PRIx64 ")", 217*061da546Spatrick LLVM_PRETTY_FUNCTION, m_thread.GetID(), 218*061da546Spatrick m_thread.GetProtocolID()); 219*061da546Spatrick #endif 220*061da546Spatrick return true; 221*061da546Spatrick } 222*061da546Spatrick 223*061da546Spatrick bool ThreadPlanNull::DoPlanExplainsStop(Event *event_ptr) { 224*061da546Spatrick #ifdef LLDB_CONFIGURATION_DEBUG 225*061da546Spatrick fprintf(stderr, 226*061da546Spatrick "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 227*061da546Spatrick ", ptid = 0x%" PRIx64 ")", 228*061da546Spatrick LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 229*061da546Spatrick #else 230*061da546Spatrick Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 231*061da546Spatrick if (log) 232*061da546Spatrick log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 233*061da546Spatrick ", ptid = 0x%" PRIx64 ")", 234*061da546Spatrick LLVM_PRETTY_FUNCTION, m_thread.GetID(), 235*061da546Spatrick m_thread.GetProtocolID()); 236*061da546Spatrick #endif 237*061da546Spatrick return true; 238*061da546Spatrick } 239*061da546Spatrick 240*061da546Spatrick // The null plan is never done. 241*061da546Spatrick bool ThreadPlanNull::MischiefManaged() { 242*061da546Spatrick // The null plan is never done. 243*061da546Spatrick #ifdef LLDB_CONFIGURATION_DEBUG 244*061da546Spatrick fprintf(stderr, 245*061da546Spatrick "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 246*061da546Spatrick ", ptid = 0x%" PRIx64 ")", 247*061da546Spatrick LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 248*061da546Spatrick #else 249*061da546Spatrick Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 250*061da546Spatrick if (log) 251*061da546Spatrick log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 252*061da546Spatrick ", ptid = 0x%" PRIx64 ")", 253*061da546Spatrick LLVM_PRETTY_FUNCTION, m_thread.GetID(), 254*061da546Spatrick m_thread.GetProtocolID()); 255*061da546Spatrick #endif 256*061da546Spatrick return false; 257*061da546Spatrick } 258*061da546Spatrick 259*061da546Spatrick lldb::StateType ThreadPlanNull::GetPlanRunState() { 260*061da546Spatrick // Not sure what to return here. This is a dead thread. 261*061da546Spatrick #ifdef LLDB_CONFIGURATION_DEBUG 262*061da546Spatrick fprintf(stderr, 263*061da546Spatrick "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 264*061da546Spatrick ", ptid = 0x%" PRIx64 ")", 265*061da546Spatrick LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 266*061da546Spatrick #else 267*061da546Spatrick Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 268*061da546Spatrick if (log) 269*061da546Spatrick log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 270*061da546Spatrick ", ptid = 0x%" PRIx64 ")", 271*061da546Spatrick LLVM_PRETTY_FUNCTION, m_thread.GetID(), 272*061da546Spatrick m_thread.GetProtocolID()); 273*061da546Spatrick #endif 274*061da546Spatrick return eStateRunning; 275*061da546Spatrick } 276