1*61e8e688SJim Ingham //===-- ThreadPlanStack.cpp -------------------------------------*- C++ -*-===// 2*61e8e688SJim Ingham // 3*61e8e688SJim Ingham // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*61e8e688SJim Ingham // See https://llvm.org/LICENSE.txt for license information. 5*61e8e688SJim Ingham // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*61e8e688SJim Ingham // 7*61e8e688SJim Ingham //===----------------------------------------------------------------------===// 8*61e8e688SJim Ingham 9*61e8e688SJim Ingham #include "lldb/Target/ThreadPlanStack.h" 10*61e8e688SJim Ingham #include "lldb/Target/Process.h" 11*61e8e688SJim Ingham #include "lldb/Target/Target.h" 12*61e8e688SJim Ingham #include "lldb/Target/Thread.h" 13*61e8e688SJim Ingham #include "lldb/Target/ThreadPlan.h" 14*61e8e688SJim Ingham #include "lldb/Utility/Log.h" 15*61e8e688SJim Ingham 16*61e8e688SJim Ingham using namespace lldb; 17*61e8e688SJim Ingham using namespace lldb_private; 18*61e8e688SJim Ingham 19*61e8e688SJim Ingham static void PrintPlanElement(Stream *s, const ThreadPlanSP &plan, 20*61e8e688SJim Ingham lldb::DescriptionLevel desc_level, 21*61e8e688SJim Ingham int32_t elem_idx) { 22*61e8e688SJim Ingham s->IndentMore(); 23*61e8e688SJim Ingham s->Indent(); 24*61e8e688SJim Ingham s->Printf("Element %d: ", elem_idx); 25*61e8e688SJim Ingham plan->GetDescription(s, desc_level); 26*61e8e688SJim Ingham s->EOL(); 27*61e8e688SJim Ingham s->IndentLess(); 28*61e8e688SJim Ingham } 29*61e8e688SJim Ingham 30*61e8e688SJim Ingham void ThreadPlanStack::DumpThreadPlans(Stream *s, 31*61e8e688SJim Ingham lldb::DescriptionLevel desc_level, 32*61e8e688SJim Ingham bool include_internal) const { 33*61e8e688SJim Ingham 34*61e8e688SJim Ingham uint32_t stack_size; 35*61e8e688SJim Ingham 36*61e8e688SJim Ingham s->IndentMore(); 37*61e8e688SJim Ingham s->Indent(); 38*61e8e688SJim Ingham s->Printf("Active plan stack:\n"); 39*61e8e688SJim Ingham int32_t print_idx = 0; 40*61e8e688SJim Ingham for (auto plan : m_plans) { 41*61e8e688SJim Ingham PrintPlanElement(s, plan, desc_level, print_idx++); 42*61e8e688SJim Ingham } 43*61e8e688SJim Ingham 44*61e8e688SJim Ingham if (AnyCompletedPlans()) { 45*61e8e688SJim Ingham print_idx = 0; 46*61e8e688SJim Ingham s->Indent(); 47*61e8e688SJim Ingham s->Printf("Completed Plan Stack:\n"); 48*61e8e688SJim Ingham for (auto plan : m_completed_plans) 49*61e8e688SJim Ingham PrintPlanElement(s, plan, desc_level, print_idx++); 50*61e8e688SJim Ingham } 51*61e8e688SJim Ingham 52*61e8e688SJim Ingham if (AnyDiscardedPlans()) { 53*61e8e688SJim Ingham print_idx = 0; 54*61e8e688SJim Ingham s->Indent(); 55*61e8e688SJim Ingham s->Printf("Discarded Plan Stack:\n"); 56*61e8e688SJim Ingham for (auto plan : m_discarded_plans) 57*61e8e688SJim Ingham PrintPlanElement(s, plan, desc_level, print_idx++); 58*61e8e688SJim Ingham } 59*61e8e688SJim Ingham 60*61e8e688SJim Ingham s->IndentLess(); 61*61e8e688SJim Ingham } 62*61e8e688SJim Ingham 63*61e8e688SJim Ingham size_t ThreadPlanStack::CheckpointCompletedPlans() { 64*61e8e688SJim Ingham m_completed_plan_checkpoint++; 65*61e8e688SJim Ingham m_completed_plan_store.insert( 66*61e8e688SJim Ingham std::make_pair(m_completed_plan_checkpoint, m_completed_plans)); 67*61e8e688SJim Ingham return m_completed_plan_checkpoint; 68*61e8e688SJim Ingham } 69*61e8e688SJim Ingham 70*61e8e688SJim Ingham void ThreadPlanStack::RestoreCompletedPlanCheckpoint(size_t checkpoint) { 71*61e8e688SJim Ingham auto result = m_completed_plan_store.find(checkpoint); 72*61e8e688SJim Ingham assert(result != m_completed_plan_store.end() && 73*61e8e688SJim Ingham "Asked for a checkpoint that didn't exist"); 74*61e8e688SJim Ingham m_completed_plans.swap((*result).second); 75*61e8e688SJim Ingham m_completed_plan_store.erase(result); 76*61e8e688SJim Ingham } 77*61e8e688SJim Ingham 78*61e8e688SJim Ingham void ThreadPlanStack::DiscardCompletedPlanCheckpoint(size_t checkpoint) { 79*61e8e688SJim Ingham m_completed_plan_store.erase(checkpoint); 80*61e8e688SJim Ingham } 81*61e8e688SJim Ingham 82*61e8e688SJim Ingham void ThreadPlanStack::ThreadDestroyed(Thread *thread) { 83*61e8e688SJim Ingham // Tell the plan stacks that this thread is going away: 84*61e8e688SJim Ingham for (ThreadPlanSP plan : m_plans) 85*61e8e688SJim Ingham plan->ThreadDestroyed(); 86*61e8e688SJim Ingham 87*61e8e688SJim Ingham for (ThreadPlanSP plan : m_discarded_plans) 88*61e8e688SJim Ingham plan->ThreadDestroyed(); 89*61e8e688SJim Ingham 90*61e8e688SJim Ingham for (ThreadPlanSP plan : m_completed_plans) 91*61e8e688SJim Ingham plan->ThreadDestroyed(); 92*61e8e688SJim Ingham 93*61e8e688SJim Ingham // Now clear the current plan stacks: 94*61e8e688SJim Ingham m_plans.clear(); 95*61e8e688SJim Ingham m_discarded_plans.clear(); 96*61e8e688SJim Ingham m_completed_plans.clear(); 97*61e8e688SJim Ingham 98*61e8e688SJim Ingham // Push a ThreadPlanNull on the plan stack. That way we can continue 99*61e8e688SJim Ingham // assuming that the plan stack is never empty, but if somebody errantly asks 100*61e8e688SJim Ingham // questions of a destroyed thread without checking first whether it is 101*61e8e688SJim Ingham // destroyed, they won't crash. 102*61e8e688SJim Ingham if (thread != nullptr) { 103*61e8e688SJim Ingham lldb::ThreadPlanSP null_plan_sp(new ThreadPlanNull(*thread)); 104*61e8e688SJim Ingham m_plans.push_back(null_plan_sp); 105*61e8e688SJim Ingham } 106*61e8e688SJim Ingham } 107*61e8e688SJim Ingham 108*61e8e688SJim Ingham void ThreadPlanStack::EnableTracer(bool value, bool single_stepping) { 109*61e8e688SJim Ingham for (ThreadPlanSP plan : m_plans) { 110*61e8e688SJim Ingham if (plan->GetThreadPlanTracer()) { 111*61e8e688SJim Ingham plan->GetThreadPlanTracer()->EnableTracing(value); 112*61e8e688SJim Ingham plan->GetThreadPlanTracer()->EnableSingleStep(single_stepping); 113*61e8e688SJim Ingham } 114*61e8e688SJim Ingham } 115*61e8e688SJim Ingham } 116*61e8e688SJim Ingham 117*61e8e688SJim Ingham void ThreadPlanStack::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) { 118*61e8e688SJim Ingham for (ThreadPlanSP plan : m_plans) 119*61e8e688SJim Ingham plan->SetThreadPlanTracer(tracer_sp); 120*61e8e688SJim Ingham } 121*61e8e688SJim Ingham 122*61e8e688SJim Ingham void ThreadPlanStack::PushPlan(lldb::ThreadPlanSP new_plan_sp) { 123*61e8e688SJim Ingham // If the thread plan doesn't already have a tracer, give it its parent's 124*61e8e688SJim Ingham // tracer: 125*61e8e688SJim Ingham // The first plan has to be a base plan: 126*61e8e688SJim Ingham assert(m_plans.size() > 0 || 127*61e8e688SJim Ingham new_plan_sp->IsBasePlan() && "Zeroth plan must be a base plan"); 128*61e8e688SJim Ingham 129*61e8e688SJim Ingham if (!new_plan_sp->GetThreadPlanTracer()) { 130*61e8e688SJim Ingham assert(!m_plans.empty()); 131*61e8e688SJim Ingham new_plan_sp->SetThreadPlanTracer(m_plans.back()->GetThreadPlanTracer()); 132*61e8e688SJim Ingham } 133*61e8e688SJim Ingham m_plans.push_back(new_plan_sp); 134*61e8e688SJim Ingham new_plan_sp->DidPush(); 135*61e8e688SJim Ingham } 136*61e8e688SJim Ingham 137*61e8e688SJim Ingham lldb::ThreadPlanSP ThreadPlanStack::PopPlan() { 138*61e8e688SJim Ingham assert(m_plans.size() > 1 && "Can't pop the base thread plan"); 139*61e8e688SJim Ingham 140*61e8e688SJim Ingham lldb::ThreadPlanSP &plan_sp = m_plans.back(); 141*61e8e688SJim Ingham m_completed_plans.push_back(plan_sp); 142*61e8e688SJim Ingham plan_sp->WillPop(); 143*61e8e688SJim Ingham m_plans.pop_back(); 144*61e8e688SJim Ingham return plan_sp; 145*61e8e688SJim Ingham } 146*61e8e688SJim Ingham 147*61e8e688SJim Ingham lldb::ThreadPlanSP ThreadPlanStack::DiscardPlan() { 148*61e8e688SJim Ingham assert(m_plans.size() > 1 && "Can't discard the base thread plan"); 149*61e8e688SJim Ingham 150*61e8e688SJim Ingham lldb::ThreadPlanSP &plan_sp = m_plans.back(); 151*61e8e688SJim Ingham m_discarded_plans.push_back(plan_sp); 152*61e8e688SJim Ingham plan_sp->WillPop(); 153*61e8e688SJim Ingham m_plans.pop_back(); 154*61e8e688SJim Ingham return plan_sp; 155*61e8e688SJim Ingham } 156*61e8e688SJim Ingham 157*61e8e688SJim Ingham // If the input plan is nullptr, discard all plans. Otherwise make sure this 158*61e8e688SJim Ingham // plan is in the stack, and if so discard up to and including it. 159*61e8e688SJim Ingham void ThreadPlanStack::DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr) { 160*61e8e688SJim Ingham int stack_size = m_plans.size(); 161*61e8e688SJim Ingham 162*61e8e688SJim Ingham if (up_to_plan_ptr == nullptr) { 163*61e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) 164*61e8e688SJim Ingham DiscardPlan(); 165*61e8e688SJim Ingham return; 166*61e8e688SJim Ingham } 167*61e8e688SJim Ingham 168*61e8e688SJim Ingham bool found_it = false; 169*61e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) { 170*61e8e688SJim Ingham if (m_plans[i].get() == up_to_plan_ptr) { 171*61e8e688SJim Ingham found_it = true; 172*61e8e688SJim Ingham break; 173*61e8e688SJim Ingham } 174*61e8e688SJim Ingham } 175*61e8e688SJim Ingham 176*61e8e688SJim Ingham if (found_it) { 177*61e8e688SJim Ingham bool last_one = false; 178*61e8e688SJim Ingham for (int i = stack_size - 1; i > 0 && !last_one; i--) { 179*61e8e688SJim Ingham if (GetCurrentPlan().get() == up_to_plan_ptr) 180*61e8e688SJim Ingham last_one = true; 181*61e8e688SJim Ingham DiscardPlan(); 182*61e8e688SJim Ingham } 183*61e8e688SJim Ingham } 184*61e8e688SJim Ingham } 185*61e8e688SJim Ingham 186*61e8e688SJim Ingham void ThreadPlanStack::DiscardAllPlans() { 187*61e8e688SJim Ingham int stack_size = m_plans.size(); 188*61e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) { 189*61e8e688SJim Ingham DiscardPlan(); 190*61e8e688SJim Ingham } 191*61e8e688SJim Ingham return; 192*61e8e688SJim Ingham } 193*61e8e688SJim Ingham 194*61e8e688SJim Ingham void ThreadPlanStack::DiscardConsultingMasterPlans() { 195*61e8e688SJim Ingham while (true) { 196*61e8e688SJim Ingham int master_plan_idx; 197*61e8e688SJim Ingham bool discard = true; 198*61e8e688SJim Ingham 199*61e8e688SJim Ingham // Find the first master plan, see if it wants discarding, and if yes 200*61e8e688SJim Ingham // discard up to it. 201*61e8e688SJim Ingham for (master_plan_idx = m_plans.size() - 1; master_plan_idx >= 0; 202*61e8e688SJim Ingham master_plan_idx--) { 203*61e8e688SJim Ingham if (m_plans[master_plan_idx]->IsMasterPlan()) { 204*61e8e688SJim Ingham discard = m_plans[master_plan_idx]->OkayToDiscard(); 205*61e8e688SJim Ingham break; 206*61e8e688SJim Ingham } 207*61e8e688SJim Ingham } 208*61e8e688SJim Ingham 209*61e8e688SJim Ingham // If the master plan doesn't want to get discarded, then we're done. 210*61e8e688SJim Ingham if (!discard) 211*61e8e688SJim Ingham return; 212*61e8e688SJim Ingham 213*61e8e688SJim Ingham // First pop all the dependent plans: 214*61e8e688SJim Ingham for (int i = m_plans.size() - 1; i > master_plan_idx; i--) { 215*61e8e688SJim Ingham DiscardPlan(); 216*61e8e688SJim Ingham } 217*61e8e688SJim Ingham 218*61e8e688SJim Ingham // Now discard the master plan itself. 219*61e8e688SJim Ingham // The bottom-most plan never gets discarded. "OkayToDiscard" for it 220*61e8e688SJim Ingham // means discard it's dependent plans, but not it... 221*61e8e688SJim Ingham if (master_plan_idx > 0) { 222*61e8e688SJim Ingham DiscardPlan(); 223*61e8e688SJim Ingham } 224*61e8e688SJim Ingham } 225*61e8e688SJim Ingham } 226*61e8e688SJim Ingham 227*61e8e688SJim Ingham lldb::ThreadPlanSP ThreadPlanStack::GetCurrentPlan() const { 228*61e8e688SJim Ingham assert(m_plans.size() != 0 && "There will always be a base plan."); 229*61e8e688SJim Ingham return m_plans.back(); 230*61e8e688SJim Ingham } 231*61e8e688SJim Ingham 232*61e8e688SJim Ingham lldb::ThreadPlanSP ThreadPlanStack::GetCompletedPlan(bool skip_private) const { 233*61e8e688SJim Ingham if (m_completed_plans.empty()) 234*61e8e688SJim Ingham return {}; 235*61e8e688SJim Ingham 236*61e8e688SJim Ingham if (!skip_private) 237*61e8e688SJim Ingham return m_completed_plans.back(); 238*61e8e688SJim Ingham 239*61e8e688SJim Ingham for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 240*61e8e688SJim Ingham lldb::ThreadPlanSP completed_plan_sp; 241*61e8e688SJim Ingham completed_plan_sp = m_completed_plans[i]; 242*61e8e688SJim Ingham if (!completed_plan_sp->GetPrivate()) 243*61e8e688SJim Ingham return completed_plan_sp; 244*61e8e688SJim Ingham } 245*61e8e688SJim Ingham return {}; 246*61e8e688SJim Ingham } 247*61e8e688SJim Ingham 248*61e8e688SJim Ingham lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx, 249*61e8e688SJim Ingham bool skip_private) const { 250*61e8e688SJim Ingham uint32_t idx = 0; 251*61e8e688SJim Ingham ThreadPlan *up_to_plan_ptr = nullptr; 252*61e8e688SJim Ingham 253*61e8e688SJim Ingham for (lldb::ThreadPlanSP plan_sp : m_plans) { 254*61e8e688SJim Ingham if (skip_private && plan_sp->GetPrivate()) 255*61e8e688SJim Ingham continue; 256*61e8e688SJim Ingham if (idx == plan_idx) 257*61e8e688SJim Ingham return plan_sp; 258*61e8e688SJim Ingham idx++; 259*61e8e688SJim Ingham } 260*61e8e688SJim Ingham return {}; 261*61e8e688SJim Ingham } 262*61e8e688SJim Ingham 263*61e8e688SJim Ingham lldb::ValueObjectSP ThreadPlanStack::GetReturnValueObject() const { 264*61e8e688SJim Ingham if (m_completed_plans.empty()) 265*61e8e688SJim Ingham return {}; 266*61e8e688SJim Ingham 267*61e8e688SJim Ingham for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 268*61e8e688SJim Ingham lldb::ValueObjectSP return_valobj_sp; 269*61e8e688SJim Ingham return_valobj_sp = m_completed_plans[i]->GetReturnValueObject(); 270*61e8e688SJim Ingham if (return_valobj_sp) 271*61e8e688SJim Ingham return return_valobj_sp; 272*61e8e688SJim Ingham } 273*61e8e688SJim Ingham return {}; 274*61e8e688SJim Ingham } 275*61e8e688SJim Ingham 276*61e8e688SJim Ingham lldb::ExpressionVariableSP ThreadPlanStack::GetExpressionVariable() const { 277*61e8e688SJim Ingham if (m_completed_plans.empty()) 278*61e8e688SJim Ingham return {}; 279*61e8e688SJim Ingham 280*61e8e688SJim Ingham for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 281*61e8e688SJim Ingham lldb::ExpressionVariableSP expression_variable_sp; 282*61e8e688SJim Ingham expression_variable_sp = m_completed_plans[i]->GetExpressionVariable(); 283*61e8e688SJim Ingham if (expression_variable_sp) 284*61e8e688SJim Ingham return expression_variable_sp; 285*61e8e688SJim Ingham } 286*61e8e688SJim Ingham return {}; 287*61e8e688SJim Ingham } 288*61e8e688SJim Ingham bool ThreadPlanStack::AnyPlans() const { 289*61e8e688SJim Ingham // There is always a base plan... 290*61e8e688SJim Ingham return m_plans.size() > 1; 291*61e8e688SJim Ingham } 292*61e8e688SJim Ingham 293*61e8e688SJim Ingham bool ThreadPlanStack::AnyCompletedPlans() const { 294*61e8e688SJim Ingham return !m_completed_plans.empty(); 295*61e8e688SJim Ingham } 296*61e8e688SJim Ingham 297*61e8e688SJim Ingham bool ThreadPlanStack::AnyDiscardedPlans() const { 298*61e8e688SJim Ingham return !m_discarded_plans.empty(); 299*61e8e688SJim Ingham } 300*61e8e688SJim Ingham 301*61e8e688SJim Ingham bool ThreadPlanStack::IsPlanDone(ThreadPlan *in_plan) const { 302*61e8e688SJim Ingham for (auto plan : m_completed_plans) { 303*61e8e688SJim Ingham if (plan.get() == in_plan) 304*61e8e688SJim Ingham return true; 305*61e8e688SJim Ingham } 306*61e8e688SJim Ingham return false; 307*61e8e688SJim Ingham } 308*61e8e688SJim Ingham 309*61e8e688SJim Ingham bool ThreadPlanStack::WasPlanDiscarded(ThreadPlan *in_plan) const { 310*61e8e688SJim Ingham for (auto plan : m_discarded_plans) { 311*61e8e688SJim Ingham if (plan.get() == in_plan) 312*61e8e688SJim Ingham return true; 313*61e8e688SJim Ingham } 314*61e8e688SJim Ingham return false; 315*61e8e688SJim Ingham } 316*61e8e688SJim Ingham 317*61e8e688SJim Ingham ThreadPlan *ThreadPlanStack::GetPreviousPlan(ThreadPlan *current_plan) const { 318*61e8e688SJim Ingham if (current_plan == nullptr) 319*61e8e688SJim Ingham return nullptr; 320*61e8e688SJim Ingham 321*61e8e688SJim Ingham // Look first in the completed plans, if the plan is here and there is 322*61e8e688SJim Ingham // a completed plan above it, return that. 323*61e8e688SJim Ingham int stack_size = m_completed_plans.size(); 324*61e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) { 325*61e8e688SJim Ingham if (current_plan == m_completed_plans[i].get()) 326*61e8e688SJim Ingham return m_completed_plans[i - 1].get(); 327*61e8e688SJim Ingham } 328*61e8e688SJim Ingham 329*61e8e688SJim Ingham // If this is the first completed plan, the previous one is the 330*61e8e688SJim Ingham // bottom of the regular plan stack. 331*61e8e688SJim Ingham if (stack_size > 0 && m_completed_plans[0].get() == current_plan) { 332*61e8e688SJim Ingham return GetCurrentPlan().get(); 333*61e8e688SJim Ingham } 334*61e8e688SJim Ingham 335*61e8e688SJim Ingham // Otherwise look for it in the regular plans. 336*61e8e688SJim Ingham stack_size = m_plans.size(); 337*61e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) { 338*61e8e688SJim Ingham if (current_plan == m_plans[i].get()) 339*61e8e688SJim Ingham return m_plans[i - 1].get(); 340*61e8e688SJim Ingham } 341*61e8e688SJim Ingham return nullptr; 342*61e8e688SJim Ingham } 343*61e8e688SJim Ingham 344*61e8e688SJim Ingham ThreadPlan *ThreadPlanStack::GetInnermostExpression() const { 345*61e8e688SJim Ingham int stack_size = m_plans.size(); 346*61e8e688SJim Ingham 347*61e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) { 348*61e8e688SJim Ingham if (m_plans[i]->GetKind() == ThreadPlan::eKindCallFunction) 349*61e8e688SJim Ingham return m_plans[i].get(); 350*61e8e688SJim Ingham } 351*61e8e688SJim Ingham return nullptr; 352*61e8e688SJim Ingham } 353*61e8e688SJim Ingham 354*61e8e688SJim Ingham void ThreadPlanStack::WillResume() { 355*61e8e688SJim Ingham m_completed_plans.clear(); 356*61e8e688SJim Ingham m_discarded_plans.clear(); 357*61e8e688SJim Ingham } 358*61e8e688SJim Ingham 359*61e8e688SJim Ingham const ThreadPlanStack::PlanStack & 360*61e8e688SJim Ingham ThreadPlanStack::GetStackOfKind(ThreadPlanStack::StackKind kind) const { 361*61e8e688SJim Ingham switch (kind) { 362*61e8e688SJim Ingham case ePlans: 363*61e8e688SJim Ingham return m_plans; 364*61e8e688SJim Ingham case eCompletedPlans: 365*61e8e688SJim Ingham return m_completed_plans; 366*61e8e688SJim Ingham case eDiscardedPlans: 367*61e8e688SJim Ingham return m_discarded_plans; 368*61e8e688SJim Ingham } 369*61e8e688SJim Ingham llvm_unreachable("Invalid StackKind value"); 370*61e8e688SJim Ingham } 371