15ffd83dbSDimitry Andric //===-- ThreadPlanStack.cpp -------------------------------------*- C++ -*-===// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric 95ffd83dbSDimitry Andric #include "lldb/Target/ThreadPlanStack.h" 105ffd83dbSDimitry Andric #include "lldb/Target/Process.h" 115ffd83dbSDimitry Andric #include "lldb/Target/Target.h" 125ffd83dbSDimitry Andric #include "lldb/Target/Thread.h" 135ffd83dbSDimitry Andric #include "lldb/Target/ThreadPlan.h" 145ffd83dbSDimitry Andric #include "lldb/Utility/Log.h" 155ffd83dbSDimitry Andric 165ffd83dbSDimitry Andric using namespace lldb; 175ffd83dbSDimitry Andric using namespace lldb_private; 185ffd83dbSDimitry Andric 195ffd83dbSDimitry Andric static void PrintPlanElement(Stream &s, const ThreadPlanSP &plan, 205ffd83dbSDimitry Andric lldb::DescriptionLevel desc_level, 215ffd83dbSDimitry Andric int32_t elem_idx) { 225ffd83dbSDimitry Andric s.IndentMore(); 235ffd83dbSDimitry Andric s.Indent(); 245ffd83dbSDimitry Andric s.Printf("Element %d: ", elem_idx); 255ffd83dbSDimitry Andric plan->GetDescription(&s, desc_level); 265ffd83dbSDimitry Andric s.EOL(); 275ffd83dbSDimitry Andric s.IndentLess(); 285ffd83dbSDimitry Andric } 295ffd83dbSDimitry Andric 305ffd83dbSDimitry Andric ThreadPlanStack::ThreadPlanStack(const Thread &thread, bool make_null) { 315ffd83dbSDimitry Andric if (make_null) { 325ffd83dbSDimitry Andric // The ThreadPlanNull doesn't do anything to the Thread, so this is actually 335ffd83dbSDimitry Andric // still a const operation. 345ffd83dbSDimitry Andric m_plans.push_back( 355ffd83dbSDimitry Andric ThreadPlanSP(new ThreadPlanNull(const_cast<Thread &>(thread)))); 365ffd83dbSDimitry Andric } 375ffd83dbSDimitry Andric } 385ffd83dbSDimitry Andric 395ffd83dbSDimitry Andric void ThreadPlanStack::DumpThreadPlans(Stream &s, 405ffd83dbSDimitry Andric lldb::DescriptionLevel desc_level, 415ffd83dbSDimitry Andric bool include_internal) const { 425ffd83dbSDimitry Andric s.IndentMore(); 435ffd83dbSDimitry Andric PrintOneStack(s, "Active plan stack", m_plans, desc_level, include_internal); 445ffd83dbSDimitry Andric PrintOneStack(s, "Completed plan stack", m_completed_plans, desc_level, 455ffd83dbSDimitry Andric include_internal); 465ffd83dbSDimitry Andric PrintOneStack(s, "Discarded plan stack", m_discarded_plans, desc_level, 475ffd83dbSDimitry Andric include_internal); 485ffd83dbSDimitry Andric s.IndentLess(); 495ffd83dbSDimitry Andric } 505ffd83dbSDimitry Andric 515ffd83dbSDimitry Andric void ThreadPlanStack::PrintOneStack(Stream &s, llvm::StringRef stack_name, 525ffd83dbSDimitry Andric const PlanStack &stack, 535ffd83dbSDimitry Andric lldb::DescriptionLevel desc_level, 545ffd83dbSDimitry Andric bool include_internal) const { 555ffd83dbSDimitry Andric // If the stack is empty, just exit: 565ffd83dbSDimitry Andric if (stack.empty()) 575ffd83dbSDimitry Andric return; 585ffd83dbSDimitry Andric 595ffd83dbSDimitry Andric // Make sure there are public completed plans: 605ffd83dbSDimitry Andric bool any_public = false; 615ffd83dbSDimitry Andric if (!include_internal) { 625ffd83dbSDimitry Andric for (auto plan : stack) { 635ffd83dbSDimitry Andric if (!plan->GetPrivate()) { 645ffd83dbSDimitry Andric any_public = true; 655ffd83dbSDimitry Andric break; 665ffd83dbSDimitry Andric } 675ffd83dbSDimitry Andric } 685ffd83dbSDimitry Andric } 695ffd83dbSDimitry Andric 705ffd83dbSDimitry Andric if (include_internal || any_public) { 715ffd83dbSDimitry Andric int print_idx = 0; 725ffd83dbSDimitry Andric s.Indent(); 735ffd83dbSDimitry Andric s << stack_name << ":\n"; 745ffd83dbSDimitry Andric for (auto plan : stack) { 755ffd83dbSDimitry Andric if (!include_internal && plan->GetPrivate()) 765ffd83dbSDimitry Andric continue; 775ffd83dbSDimitry Andric PrintPlanElement(s, plan, desc_level, print_idx++); 785ffd83dbSDimitry Andric } 795ffd83dbSDimitry Andric } 805ffd83dbSDimitry Andric } 815ffd83dbSDimitry Andric 825ffd83dbSDimitry Andric size_t ThreadPlanStack::CheckpointCompletedPlans() { 835ffd83dbSDimitry Andric m_completed_plan_checkpoint++; 845ffd83dbSDimitry Andric m_completed_plan_store.insert( 855ffd83dbSDimitry Andric std::make_pair(m_completed_plan_checkpoint, m_completed_plans)); 865ffd83dbSDimitry Andric return m_completed_plan_checkpoint; 875ffd83dbSDimitry Andric } 885ffd83dbSDimitry Andric 895ffd83dbSDimitry Andric void ThreadPlanStack::RestoreCompletedPlanCheckpoint(size_t checkpoint) { 905ffd83dbSDimitry Andric auto result = m_completed_plan_store.find(checkpoint); 915ffd83dbSDimitry Andric assert(result != m_completed_plan_store.end() && 925ffd83dbSDimitry Andric "Asked for a checkpoint that didn't exist"); 935ffd83dbSDimitry Andric m_completed_plans.swap((*result).second); 945ffd83dbSDimitry Andric m_completed_plan_store.erase(result); 955ffd83dbSDimitry Andric } 965ffd83dbSDimitry Andric 975ffd83dbSDimitry Andric void ThreadPlanStack::DiscardCompletedPlanCheckpoint(size_t checkpoint) { 985ffd83dbSDimitry Andric m_completed_plan_store.erase(checkpoint); 995ffd83dbSDimitry Andric } 1005ffd83dbSDimitry Andric 1015ffd83dbSDimitry Andric void ThreadPlanStack::ThreadDestroyed(Thread *thread) { 1025ffd83dbSDimitry Andric // Tell the plan stacks that this thread is going away: 1035ffd83dbSDimitry Andric for (ThreadPlanSP plan : m_plans) 1045ffd83dbSDimitry Andric plan->ThreadDestroyed(); 1055ffd83dbSDimitry Andric 1065ffd83dbSDimitry Andric for (ThreadPlanSP plan : m_discarded_plans) 1075ffd83dbSDimitry Andric plan->ThreadDestroyed(); 1085ffd83dbSDimitry Andric 1095ffd83dbSDimitry Andric for (ThreadPlanSP plan : m_completed_plans) 1105ffd83dbSDimitry Andric plan->ThreadDestroyed(); 1115ffd83dbSDimitry Andric 1125ffd83dbSDimitry Andric // Now clear the current plan stacks: 1135ffd83dbSDimitry Andric m_plans.clear(); 1145ffd83dbSDimitry Andric m_discarded_plans.clear(); 1155ffd83dbSDimitry Andric m_completed_plans.clear(); 1165ffd83dbSDimitry Andric 1175ffd83dbSDimitry Andric // Push a ThreadPlanNull on the plan stack. That way we can continue 1185ffd83dbSDimitry Andric // assuming that the plan stack is never empty, but if somebody errantly asks 1195ffd83dbSDimitry Andric // questions of a destroyed thread without checking first whether it is 1205ffd83dbSDimitry Andric // destroyed, they won't crash. 1215ffd83dbSDimitry Andric if (thread != nullptr) { 1225ffd83dbSDimitry Andric lldb::ThreadPlanSP null_plan_sp(new ThreadPlanNull(*thread)); 1235ffd83dbSDimitry Andric m_plans.push_back(null_plan_sp); 1245ffd83dbSDimitry Andric } 1255ffd83dbSDimitry Andric } 1265ffd83dbSDimitry Andric 1275ffd83dbSDimitry Andric void ThreadPlanStack::EnableTracer(bool value, bool single_stepping) { 1285ffd83dbSDimitry Andric for (ThreadPlanSP plan : m_plans) { 1295ffd83dbSDimitry Andric if (plan->GetThreadPlanTracer()) { 1305ffd83dbSDimitry Andric plan->GetThreadPlanTracer()->EnableTracing(value); 1315ffd83dbSDimitry Andric plan->GetThreadPlanTracer()->EnableSingleStep(single_stepping); 1325ffd83dbSDimitry Andric } 1335ffd83dbSDimitry Andric } 1345ffd83dbSDimitry Andric } 1355ffd83dbSDimitry Andric 1365ffd83dbSDimitry Andric void ThreadPlanStack::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) { 1375ffd83dbSDimitry Andric for (ThreadPlanSP plan : m_plans) 1385ffd83dbSDimitry Andric plan->SetThreadPlanTracer(tracer_sp); 1395ffd83dbSDimitry Andric } 1405ffd83dbSDimitry Andric 1415ffd83dbSDimitry Andric void ThreadPlanStack::PushPlan(lldb::ThreadPlanSP new_plan_sp) { 1425ffd83dbSDimitry Andric // If the thread plan doesn't already have a tracer, give it its parent's 1435ffd83dbSDimitry Andric // tracer: 1445ffd83dbSDimitry Andric // The first plan has to be a base plan: 1455ffd83dbSDimitry Andric assert((m_plans.size() > 0 || new_plan_sp->IsBasePlan()) && 1465ffd83dbSDimitry Andric "Zeroth plan must be a base plan"); 1475ffd83dbSDimitry Andric 1485ffd83dbSDimitry Andric if (!new_plan_sp->GetThreadPlanTracer()) { 1495ffd83dbSDimitry Andric assert(!m_plans.empty()); 1505ffd83dbSDimitry Andric new_plan_sp->SetThreadPlanTracer(m_plans.back()->GetThreadPlanTracer()); 1515ffd83dbSDimitry Andric } 1525ffd83dbSDimitry Andric m_plans.push_back(new_plan_sp); 1535ffd83dbSDimitry Andric new_plan_sp->DidPush(); 1545ffd83dbSDimitry Andric } 1555ffd83dbSDimitry Andric 1565ffd83dbSDimitry Andric lldb::ThreadPlanSP ThreadPlanStack::PopPlan() { 1575ffd83dbSDimitry Andric assert(m_plans.size() > 1 && "Can't pop the base thread plan"); 1585ffd83dbSDimitry Andric 1595ffd83dbSDimitry Andric lldb::ThreadPlanSP plan_sp = std::move(m_plans.back()); 1605ffd83dbSDimitry Andric m_completed_plans.push_back(plan_sp); 1615ffd83dbSDimitry Andric plan_sp->WillPop(); 1625ffd83dbSDimitry Andric m_plans.pop_back(); 1635ffd83dbSDimitry Andric return plan_sp; 1645ffd83dbSDimitry Andric } 1655ffd83dbSDimitry Andric 1665ffd83dbSDimitry Andric lldb::ThreadPlanSP ThreadPlanStack::DiscardPlan() { 1675ffd83dbSDimitry Andric assert(m_plans.size() > 1 && "Can't discard the base thread plan"); 1685ffd83dbSDimitry Andric 1695ffd83dbSDimitry Andric lldb::ThreadPlanSP plan_sp = std::move(m_plans.back()); 1705ffd83dbSDimitry Andric m_discarded_plans.push_back(plan_sp); 1715ffd83dbSDimitry Andric plan_sp->WillPop(); 1725ffd83dbSDimitry Andric m_plans.pop_back(); 1735ffd83dbSDimitry Andric return plan_sp; 1745ffd83dbSDimitry Andric } 1755ffd83dbSDimitry Andric 1765ffd83dbSDimitry Andric // If the input plan is nullptr, discard all plans. Otherwise make sure this 1775ffd83dbSDimitry Andric // plan is in the stack, and if so discard up to and including it. 1785ffd83dbSDimitry Andric void ThreadPlanStack::DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr) { 1795ffd83dbSDimitry Andric int stack_size = m_plans.size(); 1805ffd83dbSDimitry Andric 1815ffd83dbSDimitry Andric if (up_to_plan_ptr == nullptr) { 1825ffd83dbSDimitry Andric for (int i = stack_size - 1; i > 0; i--) 1835ffd83dbSDimitry Andric DiscardPlan(); 1845ffd83dbSDimitry Andric return; 1855ffd83dbSDimitry Andric } 1865ffd83dbSDimitry Andric 1875ffd83dbSDimitry Andric bool found_it = false; 1885ffd83dbSDimitry Andric for (int i = stack_size - 1; i > 0; i--) { 1895ffd83dbSDimitry Andric if (m_plans[i].get() == up_to_plan_ptr) { 1905ffd83dbSDimitry Andric found_it = true; 1915ffd83dbSDimitry Andric break; 1925ffd83dbSDimitry Andric } 1935ffd83dbSDimitry Andric } 1945ffd83dbSDimitry Andric 1955ffd83dbSDimitry Andric if (found_it) { 1965ffd83dbSDimitry Andric bool last_one = false; 1975ffd83dbSDimitry Andric for (int i = stack_size - 1; i > 0 && !last_one; i--) { 1985ffd83dbSDimitry Andric if (GetCurrentPlan().get() == up_to_plan_ptr) 1995ffd83dbSDimitry Andric last_one = true; 2005ffd83dbSDimitry Andric DiscardPlan(); 2015ffd83dbSDimitry Andric } 2025ffd83dbSDimitry Andric } 2035ffd83dbSDimitry Andric } 2045ffd83dbSDimitry Andric 2055ffd83dbSDimitry Andric void ThreadPlanStack::DiscardAllPlans() { 2065ffd83dbSDimitry Andric int stack_size = m_plans.size(); 2075ffd83dbSDimitry Andric for (int i = stack_size - 1; i > 0; i--) { 2085ffd83dbSDimitry Andric DiscardPlan(); 2095ffd83dbSDimitry Andric } 2105ffd83dbSDimitry Andric return; 2115ffd83dbSDimitry Andric } 2125ffd83dbSDimitry Andric 2135ffd83dbSDimitry Andric void ThreadPlanStack::DiscardConsultingMasterPlans() { 2145ffd83dbSDimitry Andric while (true) { 2155ffd83dbSDimitry Andric int master_plan_idx; 2165ffd83dbSDimitry Andric bool discard = true; 2175ffd83dbSDimitry Andric 2185ffd83dbSDimitry Andric // Find the first master plan, see if it wants discarding, and if yes 2195ffd83dbSDimitry Andric // discard up to it. 2205ffd83dbSDimitry Andric for (master_plan_idx = m_plans.size() - 1; master_plan_idx >= 0; 2215ffd83dbSDimitry Andric master_plan_idx--) { 2225ffd83dbSDimitry Andric if (m_plans[master_plan_idx]->IsMasterPlan()) { 2235ffd83dbSDimitry Andric discard = m_plans[master_plan_idx]->OkayToDiscard(); 2245ffd83dbSDimitry Andric break; 2255ffd83dbSDimitry Andric } 2265ffd83dbSDimitry Andric } 2275ffd83dbSDimitry Andric 2285ffd83dbSDimitry Andric // If the master plan doesn't want to get discarded, then we're done. 2295ffd83dbSDimitry Andric if (!discard) 2305ffd83dbSDimitry Andric return; 2315ffd83dbSDimitry Andric 2325ffd83dbSDimitry Andric // First pop all the dependent plans: 2335ffd83dbSDimitry Andric for (int i = m_plans.size() - 1; i > master_plan_idx; i--) { 2345ffd83dbSDimitry Andric DiscardPlan(); 2355ffd83dbSDimitry Andric } 2365ffd83dbSDimitry Andric 2375ffd83dbSDimitry Andric // Now discard the master plan itself. 2385ffd83dbSDimitry Andric // The bottom-most plan never gets discarded. "OkayToDiscard" for it 2395ffd83dbSDimitry Andric // means discard it's dependent plans, but not it... 2405ffd83dbSDimitry Andric if (master_plan_idx > 0) { 2415ffd83dbSDimitry Andric DiscardPlan(); 2425ffd83dbSDimitry Andric } 2435ffd83dbSDimitry Andric } 2445ffd83dbSDimitry Andric } 2455ffd83dbSDimitry Andric 2465ffd83dbSDimitry Andric lldb::ThreadPlanSP ThreadPlanStack::GetCurrentPlan() const { 2475ffd83dbSDimitry Andric assert(m_plans.size() != 0 && "There will always be a base plan."); 2485ffd83dbSDimitry Andric return m_plans.back(); 2495ffd83dbSDimitry Andric } 2505ffd83dbSDimitry Andric 2515ffd83dbSDimitry Andric lldb::ThreadPlanSP ThreadPlanStack::GetCompletedPlan(bool skip_private) const { 2525ffd83dbSDimitry Andric if (m_completed_plans.empty()) 2535ffd83dbSDimitry Andric return {}; 2545ffd83dbSDimitry Andric 2555ffd83dbSDimitry Andric if (!skip_private) 2565ffd83dbSDimitry Andric return m_completed_plans.back(); 2575ffd83dbSDimitry Andric 2585ffd83dbSDimitry Andric for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 2595ffd83dbSDimitry Andric lldb::ThreadPlanSP completed_plan_sp; 2605ffd83dbSDimitry Andric completed_plan_sp = m_completed_plans[i]; 2615ffd83dbSDimitry Andric if (!completed_plan_sp->GetPrivate()) 2625ffd83dbSDimitry Andric return completed_plan_sp; 2635ffd83dbSDimitry Andric } 2645ffd83dbSDimitry Andric return {}; 2655ffd83dbSDimitry Andric } 2665ffd83dbSDimitry Andric 2675ffd83dbSDimitry Andric lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx, 2685ffd83dbSDimitry Andric bool skip_private) const { 2695ffd83dbSDimitry Andric uint32_t idx = 0; 2705ffd83dbSDimitry Andric 2715ffd83dbSDimitry Andric for (lldb::ThreadPlanSP plan_sp : m_plans) { 2725ffd83dbSDimitry Andric if (skip_private && plan_sp->GetPrivate()) 2735ffd83dbSDimitry Andric continue; 2745ffd83dbSDimitry Andric if (idx == plan_idx) 2755ffd83dbSDimitry Andric return plan_sp; 2765ffd83dbSDimitry Andric idx++; 2775ffd83dbSDimitry Andric } 2785ffd83dbSDimitry Andric return {}; 2795ffd83dbSDimitry Andric } 2805ffd83dbSDimitry Andric 2815ffd83dbSDimitry Andric lldb::ValueObjectSP ThreadPlanStack::GetReturnValueObject() const { 2825ffd83dbSDimitry Andric if (m_completed_plans.empty()) 2835ffd83dbSDimitry Andric return {}; 2845ffd83dbSDimitry Andric 2855ffd83dbSDimitry Andric for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 2865ffd83dbSDimitry Andric lldb::ValueObjectSP return_valobj_sp; 2875ffd83dbSDimitry Andric return_valobj_sp = m_completed_plans[i]->GetReturnValueObject(); 2885ffd83dbSDimitry Andric if (return_valobj_sp) 2895ffd83dbSDimitry Andric return return_valobj_sp; 2905ffd83dbSDimitry Andric } 2915ffd83dbSDimitry Andric return {}; 2925ffd83dbSDimitry Andric } 2935ffd83dbSDimitry Andric 2945ffd83dbSDimitry Andric lldb::ExpressionVariableSP ThreadPlanStack::GetExpressionVariable() const { 2955ffd83dbSDimitry Andric if (m_completed_plans.empty()) 2965ffd83dbSDimitry Andric return {}; 2975ffd83dbSDimitry Andric 2985ffd83dbSDimitry Andric for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 2995ffd83dbSDimitry Andric lldb::ExpressionVariableSP expression_variable_sp; 3005ffd83dbSDimitry Andric expression_variable_sp = m_completed_plans[i]->GetExpressionVariable(); 3015ffd83dbSDimitry Andric if (expression_variable_sp) 3025ffd83dbSDimitry Andric return expression_variable_sp; 3035ffd83dbSDimitry Andric } 3045ffd83dbSDimitry Andric return {}; 3055ffd83dbSDimitry Andric } 3065ffd83dbSDimitry Andric bool ThreadPlanStack::AnyPlans() const { 3075ffd83dbSDimitry Andric // There is always a base plan... 3085ffd83dbSDimitry Andric return m_plans.size() > 1; 3095ffd83dbSDimitry Andric } 3105ffd83dbSDimitry Andric 3115ffd83dbSDimitry Andric bool ThreadPlanStack::AnyCompletedPlans() const { 3125ffd83dbSDimitry Andric return !m_completed_plans.empty(); 3135ffd83dbSDimitry Andric } 3145ffd83dbSDimitry Andric 3155ffd83dbSDimitry Andric bool ThreadPlanStack::AnyDiscardedPlans() const { 3165ffd83dbSDimitry Andric return !m_discarded_plans.empty(); 3175ffd83dbSDimitry Andric } 3185ffd83dbSDimitry Andric 3195ffd83dbSDimitry Andric bool ThreadPlanStack::IsPlanDone(ThreadPlan *in_plan) const { 3205ffd83dbSDimitry Andric for (auto plan : m_completed_plans) { 3215ffd83dbSDimitry Andric if (plan.get() == in_plan) 3225ffd83dbSDimitry Andric return true; 3235ffd83dbSDimitry Andric } 3245ffd83dbSDimitry Andric return false; 3255ffd83dbSDimitry Andric } 3265ffd83dbSDimitry Andric 3275ffd83dbSDimitry Andric bool ThreadPlanStack::WasPlanDiscarded(ThreadPlan *in_plan) const { 3285ffd83dbSDimitry Andric for (auto plan : m_discarded_plans) { 3295ffd83dbSDimitry Andric if (plan.get() == in_plan) 3305ffd83dbSDimitry Andric return true; 3315ffd83dbSDimitry Andric } 3325ffd83dbSDimitry Andric return false; 3335ffd83dbSDimitry Andric } 3345ffd83dbSDimitry Andric 3355ffd83dbSDimitry Andric ThreadPlan *ThreadPlanStack::GetPreviousPlan(ThreadPlan *current_plan) const { 3365ffd83dbSDimitry Andric if (current_plan == nullptr) 3375ffd83dbSDimitry Andric return nullptr; 3385ffd83dbSDimitry Andric 3395ffd83dbSDimitry Andric // Look first in the completed plans, if the plan is here and there is 3405ffd83dbSDimitry Andric // a completed plan above it, return that. 3415ffd83dbSDimitry Andric int stack_size = m_completed_plans.size(); 3425ffd83dbSDimitry Andric for (int i = stack_size - 1; i > 0; i--) { 3435ffd83dbSDimitry Andric if (current_plan == m_completed_plans[i].get()) 3445ffd83dbSDimitry Andric return m_completed_plans[i - 1].get(); 3455ffd83dbSDimitry Andric } 3465ffd83dbSDimitry Andric 3475ffd83dbSDimitry Andric // If this is the first completed plan, the previous one is the 3485ffd83dbSDimitry Andric // bottom of the regular plan stack. 3495ffd83dbSDimitry Andric if (stack_size > 0 && m_completed_plans[0].get() == current_plan) { 3505ffd83dbSDimitry Andric return GetCurrentPlan().get(); 3515ffd83dbSDimitry Andric } 3525ffd83dbSDimitry Andric 3535ffd83dbSDimitry Andric // Otherwise look for it in the regular plans. 3545ffd83dbSDimitry Andric stack_size = m_plans.size(); 3555ffd83dbSDimitry Andric for (int i = stack_size - 1; i > 0; i--) { 3565ffd83dbSDimitry Andric if (current_plan == m_plans[i].get()) 3575ffd83dbSDimitry Andric return m_plans[i - 1].get(); 3585ffd83dbSDimitry Andric } 3595ffd83dbSDimitry Andric return nullptr; 3605ffd83dbSDimitry Andric } 3615ffd83dbSDimitry Andric 3625ffd83dbSDimitry Andric ThreadPlan *ThreadPlanStack::GetInnermostExpression() const { 3635ffd83dbSDimitry Andric int stack_size = m_plans.size(); 3645ffd83dbSDimitry Andric 3655ffd83dbSDimitry Andric for (int i = stack_size - 1; i > 0; i--) { 3665ffd83dbSDimitry Andric if (m_plans[i]->GetKind() == ThreadPlan::eKindCallFunction) 3675ffd83dbSDimitry Andric return m_plans[i].get(); 3685ffd83dbSDimitry Andric } 3695ffd83dbSDimitry Andric return nullptr; 3705ffd83dbSDimitry Andric } 3715ffd83dbSDimitry Andric 372*e8d8bef9SDimitry Andric void ThreadPlanStack::ClearThreadCache() { 373*e8d8bef9SDimitry Andric for (lldb::ThreadPlanSP thread_plan_sp : m_plans) 374*e8d8bef9SDimitry Andric thread_plan_sp->ClearThreadCache(); 375*e8d8bef9SDimitry Andric } 376*e8d8bef9SDimitry Andric 3775ffd83dbSDimitry Andric void ThreadPlanStack::WillResume() { 3785ffd83dbSDimitry Andric m_completed_plans.clear(); 3795ffd83dbSDimitry Andric m_discarded_plans.clear(); 3805ffd83dbSDimitry Andric } 3815ffd83dbSDimitry Andric 3825ffd83dbSDimitry Andric void ThreadPlanStackMap::Update(ThreadList ¤t_threads, 3835ffd83dbSDimitry Andric bool delete_missing, 3845ffd83dbSDimitry Andric bool check_for_new) { 3855ffd83dbSDimitry Andric 3865ffd83dbSDimitry Andric // Now find all the new threads and add them to the map: 3875ffd83dbSDimitry Andric if (check_for_new) { 3885ffd83dbSDimitry Andric for (auto thread : current_threads.Threads()) { 3895ffd83dbSDimitry Andric lldb::tid_t cur_tid = thread->GetID(); 3905ffd83dbSDimitry Andric if (!Find(cur_tid)) { 3915ffd83dbSDimitry Andric AddThread(*thread.get()); 3925ffd83dbSDimitry Andric thread->QueueFundamentalPlan(true); 3935ffd83dbSDimitry Andric } 3945ffd83dbSDimitry Andric } 3955ffd83dbSDimitry Andric } 3965ffd83dbSDimitry Andric 3975ffd83dbSDimitry Andric // If we aren't reaping missing threads at this point, 3985ffd83dbSDimitry Andric // we are done. 3995ffd83dbSDimitry Andric if (!delete_missing) 4005ffd83dbSDimitry Andric return; 4015ffd83dbSDimitry Andric // Otherwise scan for absent TID's. 4025ffd83dbSDimitry Andric std::vector<lldb::tid_t> missing_threads; 4035ffd83dbSDimitry Andric // If we are going to delete plans from the plan stack, 4045ffd83dbSDimitry Andric // then scan for absent TID's: 4055ffd83dbSDimitry Andric for (auto thread_plans : m_plans_list) { 4065ffd83dbSDimitry Andric lldb::tid_t cur_tid = thread_plans.first; 4075ffd83dbSDimitry Andric ThreadSP thread_sp = current_threads.FindThreadByID(cur_tid); 4085ffd83dbSDimitry Andric if (!thread_sp) 4095ffd83dbSDimitry Andric missing_threads.push_back(cur_tid); 4105ffd83dbSDimitry Andric } 4115ffd83dbSDimitry Andric for (lldb::tid_t tid : missing_threads) { 4125ffd83dbSDimitry Andric RemoveTID(tid); 4135ffd83dbSDimitry Andric } 4145ffd83dbSDimitry Andric } 4155ffd83dbSDimitry Andric 4165ffd83dbSDimitry Andric void ThreadPlanStackMap::DumpPlans(Stream &strm, 4175ffd83dbSDimitry Andric lldb::DescriptionLevel desc_level, 4185ffd83dbSDimitry Andric bool internal, bool condense_if_trivial, 4195ffd83dbSDimitry Andric bool skip_unreported) { 4205ffd83dbSDimitry Andric for (auto elem : m_plans_list) { 4215ffd83dbSDimitry Andric lldb::tid_t tid = elem.first; 4225ffd83dbSDimitry Andric uint32_t index_id = 0; 4235ffd83dbSDimitry Andric ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); 4245ffd83dbSDimitry Andric 4255ffd83dbSDimitry Andric if (skip_unreported) { 4265ffd83dbSDimitry Andric if (!thread_sp) 4275ffd83dbSDimitry Andric continue; 4285ffd83dbSDimitry Andric } 4295ffd83dbSDimitry Andric if (thread_sp) 4305ffd83dbSDimitry Andric index_id = thread_sp->GetIndexID(); 4315ffd83dbSDimitry Andric 4325ffd83dbSDimitry Andric if (condense_if_trivial) { 4335ffd83dbSDimitry Andric if (!elem.second.AnyPlans() && !elem.second.AnyCompletedPlans() && 4345ffd83dbSDimitry Andric !elem.second.AnyDiscardedPlans()) { 4355ffd83dbSDimitry Andric strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid); 4365ffd83dbSDimitry Andric strm.IndentMore(); 4375ffd83dbSDimitry Andric strm.Indent(); 4385ffd83dbSDimitry Andric strm.Printf("No active thread plans\n"); 4395ffd83dbSDimitry Andric strm.IndentLess(); 4405ffd83dbSDimitry Andric return; 4415ffd83dbSDimitry Andric } 4425ffd83dbSDimitry Andric } 4435ffd83dbSDimitry Andric 4445ffd83dbSDimitry Andric strm.Indent(); 4455ffd83dbSDimitry Andric strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid); 4465ffd83dbSDimitry Andric 4475ffd83dbSDimitry Andric elem.second.DumpThreadPlans(strm, desc_level, internal); 4485ffd83dbSDimitry Andric } 4495ffd83dbSDimitry Andric } 4505ffd83dbSDimitry Andric 4515ffd83dbSDimitry Andric bool ThreadPlanStackMap::DumpPlansForTID(Stream &strm, lldb::tid_t tid, 4525ffd83dbSDimitry Andric lldb::DescriptionLevel desc_level, 4535ffd83dbSDimitry Andric bool internal, 4545ffd83dbSDimitry Andric bool condense_if_trivial, 4555ffd83dbSDimitry Andric bool skip_unreported) { 4565ffd83dbSDimitry Andric uint32_t index_id = 0; 4575ffd83dbSDimitry Andric ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); 4585ffd83dbSDimitry Andric 4595ffd83dbSDimitry Andric if (skip_unreported) { 4605ffd83dbSDimitry Andric if (!thread_sp) { 4615ffd83dbSDimitry Andric strm.Format("Unknown TID: {0}", tid); 4625ffd83dbSDimitry Andric return false; 4635ffd83dbSDimitry Andric } 4645ffd83dbSDimitry Andric } 4655ffd83dbSDimitry Andric 4665ffd83dbSDimitry Andric if (thread_sp) 4675ffd83dbSDimitry Andric index_id = thread_sp->GetIndexID(); 4685ffd83dbSDimitry Andric ThreadPlanStack *stack = Find(tid); 4695ffd83dbSDimitry Andric if (!stack) { 4705ffd83dbSDimitry Andric strm.Format("Unknown TID: {0}\n", tid); 4715ffd83dbSDimitry Andric return false; 4725ffd83dbSDimitry Andric } 4735ffd83dbSDimitry Andric 4745ffd83dbSDimitry Andric if (condense_if_trivial) { 4755ffd83dbSDimitry Andric if (!stack->AnyPlans() && !stack->AnyCompletedPlans() && 4765ffd83dbSDimitry Andric !stack->AnyDiscardedPlans()) { 4775ffd83dbSDimitry Andric strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid); 4785ffd83dbSDimitry Andric strm.IndentMore(); 4795ffd83dbSDimitry Andric strm.Indent(); 4805ffd83dbSDimitry Andric strm.Printf("No active thread plans\n"); 4815ffd83dbSDimitry Andric strm.IndentLess(); 4825ffd83dbSDimitry Andric return true; 4835ffd83dbSDimitry Andric } 4845ffd83dbSDimitry Andric } 4855ffd83dbSDimitry Andric 4865ffd83dbSDimitry Andric strm.Indent(); 4875ffd83dbSDimitry Andric strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid); 4885ffd83dbSDimitry Andric 4895ffd83dbSDimitry Andric stack->DumpThreadPlans(strm, desc_level, internal); 4905ffd83dbSDimitry Andric return true; 4915ffd83dbSDimitry Andric } 4925ffd83dbSDimitry Andric 4935ffd83dbSDimitry Andric bool ThreadPlanStackMap::PrunePlansForTID(lldb::tid_t tid) { 4945ffd83dbSDimitry Andric // We only remove the plans for unreported TID's. 4955ffd83dbSDimitry Andric ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); 4965ffd83dbSDimitry Andric if (thread_sp) 4975ffd83dbSDimitry Andric return false; 4985ffd83dbSDimitry Andric 4995ffd83dbSDimitry Andric return RemoveTID(tid); 5005ffd83dbSDimitry Andric } 501