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 { 42fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 435ffd83dbSDimitry Andric s.IndentMore(); 445ffd83dbSDimitry Andric PrintOneStack(s, "Active plan stack", m_plans, desc_level, include_internal); 455ffd83dbSDimitry Andric PrintOneStack(s, "Completed plan stack", m_completed_plans, desc_level, 465ffd83dbSDimitry Andric include_internal); 475ffd83dbSDimitry Andric PrintOneStack(s, "Discarded plan stack", m_discarded_plans, desc_level, 485ffd83dbSDimitry Andric include_internal); 495ffd83dbSDimitry Andric s.IndentLess(); 505ffd83dbSDimitry Andric } 515ffd83dbSDimitry Andric 525ffd83dbSDimitry Andric void ThreadPlanStack::PrintOneStack(Stream &s, llvm::StringRef stack_name, 535ffd83dbSDimitry Andric const PlanStack &stack, 545ffd83dbSDimitry Andric lldb::DescriptionLevel desc_level, 555ffd83dbSDimitry Andric bool include_internal) const { 56fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 575ffd83dbSDimitry Andric // If the stack is empty, just exit: 585ffd83dbSDimitry Andric if (stack.empty()) 595ffd83dbSDimitry Andric return; 605ffd83dbSDimitry Andric 615ffd83dbSDimitry Andric // Make sure there are public completed plans: 625ffd83dbSDimitry Andric bool any_public = false; 635ffd83dbSDimitry Andric if (!include_internal) { 645ffd83dbSDimitry Andric for (auto plan : stack) { 655ffd83dbSDimitry Andric if (!plan->GetPrivate()) { 665ffd83dbSDimitry Andric any_public = true; 675ffd83dbSDimitry Andric break; 685ffd83dbSDimitry Andric } 695ffd83dbSDimitry Andric } 705ffd83dbSDimitry Andric } 715ffd83dbSDimitry Andric 725ffd83dbSDimitry Andric if (include_internal || any_public) { 735ffd83dbSDimitry Andric int print_idx = 0; 745ffd83dbSDimitry Andric s.Indent(); 755ffd83dbSDimitry Andric s << stack_name << ":\n"; 765ffd83dbSDimitry Andric for (auto plan : stack) { 775ffd83dbSDimitry Andric if (!include_internal && plan->GetPrivate()) 785ffd83dbSDimitry Andric continue; 795ffd83dbSDimitry Andric PrintPlanElement(s, plan, desc_level, print_idx++); 805ffd83dbSDimitry Andric } 815ffd83dbSDimitry Andric } 825ffd83dbSDimitry Andric } 835ffd83dbSDimitry Andric 845ffd83dbSDimitry Andric size_t ThreadPlanStack::CheckpointCompletedPlans() { 85fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 865ffd83dbSDimitry Andric m_completed_plan_checkpoint++; 875ffd83dbSDimitry Andric m_completed_plan_store.insert( 885ffd83dbSDimitry Andric std::make_pair(m_completed_plan_checkpoint, m_completed_plans)); 895ffd83dbSDimitry Andric return m_completed_plan_checkpoint; 905ffd83dbSDimitry Andric } 915ffd83dbSDimitry Andric 925ffd83dbSDimitry Andric void ThreadPlanStack::RestoreCompletedPlanCheckpoint(size_t checkpoint) { 93fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 945ffd83dbSDimitry Andric auto result = m_completed_plan_store.find(checkpoint); 955ffd83dbSDimitry Andric assert(result != m_completed_plan_store.end() && 965ffd83dbSDimitry Andric "Asked for a checkpoint that didn't exist"); 975ffd83dbSDimitry Andric m_completed_plans.swap((*result).second); 985ffd83dbSDimitry Andric m_completed_plan_store.erase(result); 995ffd83dbSDimitry Andric } 1005ffd83dbSDimitry Andric 1015ffd83dbSDimitry Andric void ThreadPlanStack::DiscardCompletedPlanCheckpoint(size_t checkpoint) { 102fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 1035ffd83dbSDimitry Andric m_completed_plan_store.erase(checkpoint); 1045ffd83dbSDimitry Andric } 1055ffd83dbSDimitry Andric 1065ffd83dbSDimitry Andric void ThreadPlanStack::ThreadDestroyed(Thread *thread) { 1075ffd83dbSDimitry Andric // Tell the plan stacks that this thread is going away: 108fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 1095ffd83dbSDimitry Andric for (ThreadPlanSP plan : m_plans) 1105ffd83dbSDimitry Andric plan->ThreadDestroyed(); 1115ffd83dbSDimitry Andric 1125ffd83dbSDimitry Andric for (ThreadPlanSP plan : m_discarded_plans) 1135ffd83dbSDimitry Andric plan->ThreadDestroyed(); 1145ffd83dbSDimitry Andric 1155ffd83dbSDimitry Andric for (ThreadPlanSP plan : m_completed_plans) 1165ffd83dbSDimitry Andric plan->ThreadDestroyed(); 1175ffd83dbSDimitry Andric 1185ffd83dbSDimitry Andric // Now clear the current plan stacks: 1195ffd83dbSDimitry Andric m_plans.clear(); 1205ffd83dbSDimitry Andric m_discarded_plans.clear(); 1215ffd83dbSDimitry Andric m_completed_plans.clear(); 1225ffd83dbSDimitry Andric 1235ffd83dbSDimitry Andric // Push a ThreadPlanNull on the plan stack. That way we can continue 1245ffd83dbSDimitry Andric // assuming that the plan stack is never empty, but if somebody errantly asks 1255ffd83dbSDimitry Andric // questions of a destroyed thread without checking first whether it is 1265ffd83dbSDimitry Andric // destroyed, they won't crash. 1275ffd83dbSDimitry Andric if (thread != nullptr) { 1285ffd83dbSDimitry Andric lldb::ThreadPlanSP null_plan_sp(new ThreadPlanNull(*thread)); 1295ffd83dbSDimitry Andric m_plans.push_back(null_plan_sp); 1305ffd83dbSDimitry Andric } 1315ffd83dbSDimitry Andric } 1325ffd83dbSDimitry Andric 1335ffd83dbSDimitry Andric void ThreadPlanStack::PushPlan(lldb::ThreadPlanSP new_plan_sp) { 1345ffd83dbSDimitry Andric // If the thread plan doesn't already have a tracer, give it its parent's 1355ffd83dbSDimitry Andric // tracer: 1365ffd83dbSDimitry Andric // The first plan has to be a base plan: 137fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 1385ffd83dbSDimitry Andric assert((m_plans.size() > 0 || new_plan_sp->IsBasePlan()) && 1395ffd83dbSDimitry Andric "Zeroth plan must be a base plan"); 1405ffd83dbSDimitry Andric 1415ffd83dbSDimitry Andric if (!new_plan_sp->GetThreadPlanTracer()) { 1425ffd83dbSDimitry Andric assert(!m_plans.empty()); 1435ffd83dbSDimitry Andric new_plan_sp->SetThreadPlanTracer(m_plans.back()->GetThreadPlanTracer()); 1445ffd83dbSDimitry Andric } 1455ffd83dbSDimitry Andric m_plans.push_back(new_plan_sp); 1465ffd83dbSDimitry Andric new_plan_sp->DidPush(); 1475ffd83dbSDimitry Andric } 1485ffd83dbSDimitry Andric 1495ffd83dbSDimitry Andric lldb::ThreadPlanSP ThreadPlanStack::PopPlan() { 150fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 1515ffd83dbSDimitry Andric assert(m_plans.size() > 1 && "Can't pop the base thread plan"); 1525ffd83dbSDimitry Andric 153349cc55cSDimitry Andric // Note that moving the top element of the vector would leave it in an 154349cc55cSDimitry Andric // undefined state, and break the guarantee that the stack's thread plans are 155349cc55cSDimitry Andric // all valid. 156349cc55cSDimitry Andric lldb::ThreadPlanSP plan_sp = m_plans.back(); 1575ffd83dbSDimitry Andric m_plans.pop_back(); 158349cc55cSDimitry Andric m_completed_plans.push_back(plan_sp); 159349cc55cSDimitry Andric plan_sp->DidPop(); 1605ffd83dbSDimitry Andric return plan_sp; 1615ffd83dbSDimitry Andric } 1625ffd83dbSDimitry Andric 1635ffd83dbSDimitry Andric lldb::ThreadPlanSP ThreadPlanStack::DiscardPlan() { 164fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 1655ffd83dbSDimitry Andric assert(m_plans.size() > 1 && "Can't discard the base thread plan"); 1665ffd83dbSDimitry Andric 167349cc55cSDimitry Andric // Note that moving the top element of the vector would leave it in an 168349cc55cSDimitry Andric // undefined state, and break the guarantee that the stack's thread plans are 169349cc55cSDimitry Andric // all valid. 170349cc55cSDimitry Andric lldb::ThreadPlanSP plan_sp = m_plans.back(); 1715ffd83dbSDimitry Andric m_plans.pop_back(); 172349cc55cSDimitry Andric m_discarded_plans.push_back(plan_sp); 173349cc55cSDimitry Andric plan_sp->DidPop(); 1745ffd83dbSDimitry Andric return plan_sp; 1755ffd83dbSDimitry Andric } 1765ffd83dbSDimitry Andric 1775ffd83dbSDimitry Andric // If the input plan is nullptr, discard all plans. Otherwise make sure this 1785ffd83dbSDimitry Andric // plan is in the stack, and if so discard up to and including it. 1795ffd83dbSDimitry Andric void ThreadPlanStack::DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr) { 180fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 1815ffd83dbSDimitry Andric int stack_size = m_plans.size(); 1825ffd83dbSDimitry Andric 1835ffd83dbSDimitry Andric if (up_to_plan_ptr == nullptr) { 1845ffd83dbSDimitry Andric for (int i = stack_size - 1; i > 0; i--) 1855ffd83dbSDimitry Andric DiscardPlan(); 1865ffd83dbSDimitry Andric return; 1875ffd83dbSDimitry Andric } 1885ffd83dbSDimitry Andric 1895ffd83dbSDimitry Andric bool found_it = false; 1905ffd83dbSDimitry Andric for (int i = stack_size - 1; i > 0; i--) { 1915ffd83dbSDimitry Andric if (m_plans[i].get() == up_to_plan_ptr) { 1925ffd83dbSDimitry Andric found_it = true; 1935ffd83dbSDimitry Andric break; 1945ffd83dbSDimitry Andric } 1955ffd83dbSDimitry Andric } 1965ffd83dbSDimitry Andric 1975ffd83dbSDimitry Andric if (found_it) { 1985ffd83dbSDimitry Andric bool last_one = false; 1995ffd83dbSDimitry Andric for (int i = stack_size - 1; i > 0 && !last_one; i--) { 2005ffd83dbSDimitry Andric if (GetCurrentPlan().get() == up_to_plan_ptr) 2015ffd83dbSDimitry Andric last_one = true; 2025ffd83dbSDimitry Andric DiscardPlan(); 2035ffd83dbSDimitry Andric } 2045ffd83dbSDimitry Andric } 2055ffd83dbSDimitry Andric } 2065ffd83dbSDimitry Andric 2075ffd83dbSDimitry Andric void ThreadPlanStack::DiscardAllPlans() { 208fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 2095ffd83dbSDimitry Andric int stack_size = m_plans.size(); 2105ffd83dbSDimitry Andric for (int i = stack_size - 1; i > 0; i--) { 2115ffd83dbSDimitry Andric DiscardPlan(); 2125ffd83dbSDimitry Andric } 2135ffd83dbSDimitry Andric } 2145ffd83dbSDimitry Andric 215349cc55cSDimitry Andric void ThreadPlanStack::DiscardConsultingControllingPlans() { 216fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 2175ffd83dbSDimitry Andric while (true) { 218349cc55cSDimitry Andric int controlling_plan_idx; 2195ffd83dbSDimitry Andric bool discard = true; 2205ffd83dbSDimitry Andric 221349cc55cSDimitry Andric // Find the first controlling plan, see if it wants discarding, and if yes 2225ffd83dbSDimitry Andric // discard up to it. 223349cc55cSDimitry Andric for (controlling_plan_idx = m_plans.size() - 1; controlling_plan_idx >= 0; 224349cc55cSDimitry Andric controlling_plan_idx--) { 225349cc55cSDimitry Andric if (m_plans[controlling_plan_idx]->IsControllingPlan()) { 226349cc55cSDimitry Andric discard = m_plans[controlling_plan_idx]->OkayToDiscard(); 2275ffd83dbSDimitry Andric break; 2285ffd83dbSDimitry Andric } 2295ffd83dbSDimitry Andric } 2305ffd83dbSDimitry Andric 231349cc55cSDimitry Andric // If the controlling plan doesn't want to get discarded, then we're done. 2325ffd83dbSDimitry Andric if (!discard) 2335ffd83dbSDimitry Andric return; 2345ffd83dbSDimitry Andric 2355ffd83dbSDimitry Andric // First pop all the dependent plans: 236349cc55cSDimitry Andric for (int i = m_plans.size() - 1; i > controlling_plan_idx; i--) { 2375ffd83dbSDimitry Andric DiscardPlan(); 2385ffd83dbSDimitry Andric } 2395ffd83dbSDimitry Andric 240349cc55cSDimitry Andric // Now discard the controlling plan itself. 2415ffd83dbSDimitry Andric // The bottom-most plan never gets discarded. "OkayToDiscard" for it 2425ffd83dbSDimitry Andric // means discard it's dependent plans, but not it... 243349cc55cSDimitry Andric if (controlling_plan_idx > 0) { 2445ffd83dbSDimitry Andric DiscardPlan(); 2455ffd83dbSDimitry Andric } 2465ffd83dbSDimitry Andric } 2475ffd83dbSDimitry Andric } 2485ffd83dbSDimitry Andric 2495ffd83dbSDimitry Andric lldb::ThreadPlanSP ThreadPlanStack::GetCurrentPlan() const { 250fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 2515ffd83dbSDimitry Andric assert(m_plans.size() != 0 && "There will always be a base plan."); 2525ffd83dbSDimitry Andric return m_plans.back(); 2535ffd83dbSDimitry Andric } 2545ffd83dbSDimitry Andric 2555ffd83dbSDimitry Andric lldb::ThreadPlanSP ThreadPlanStack::GetCompletedPlan(bool skip_private) const { 256fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 2575ffd83dbSDimitry Andric if (m_completed_plans.empty()) 2585ffd83dbSDimitry Andric return {}; 2595ffd83dbSDimitry Andric 2605ffd83dbSDimitry Andric if (!skip_private) 2615ffd83dbSDimitry Andric return m_completed_plans.back(); 2625ffd83dbSDimitry Andric 2635ffd83dbSDimitry Andric for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 2645ffd83dbSDimitry Andric lldb::ThreadPlanSP completed_plan_sp; 2655ffd83dbSDimitry Andric completed_plan_sp = m_completed_plans[i]; 2665ffd83dbSDimitry Andric if (!completed_plan_sp->GetPrivate()) 2675ffd83dbSDimitry Andric return completed_plan_sp; 2685ffd83dbSDimitry Andric } 2695ffd83dbSDimitry Andric return {}; 2705ffd83dbSDimitry Andric } 2715ffd83dbSDimitry Andric 2725ffd83dbSDimitry Andric lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx, 2735ffd83dbSDimitry Andric bool skip_private) const { 274fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 2755ffd83dbSDimitry Andric uint32_t idx = 0; 2765ffd83dbSDimitry Andric 2775ffd83dbSDimitry Andric for (lldb::ThreadPlanSP plan_sp : m_plans) { 2785ffd83dbSDimitry Andric if (skip_private && plan_sp->GetPrivate()) 2795ffd83dbSDimitry Andric continue; 2805ffd83dbSDimitry Andric if (idx == plan_idx) 2815ffd83dbSDimitry Andric return plan_sp; 2825ffd83dbSDimitry Andric idx++; 2835ffd83dbSDimitry Andric } 2845ffd83dbSDimitry Andric return {}; 2855ffd83dbSDimitry Andric } 2865ffd83dbSDimitry Andric 2875ffd83dbSDimitry Andric lldb::ValueObjectSP ThreadPlanStack::GetReturnValueObject() const { 288fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 2895ffd83dbSDimitry Andric if (m_completed_plans.empty()) 2905ffd83dbSDimitry Andric return {}; 2915ffd83dbSDimitry Andric 2925ffd83dbSDimitry Andric for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 2935ffd83dbSDimitry Andric lldb::ValueObjectSP return_valobj_sp; 2945ffd83dbSDimitry Andric return_valobj_sp = m_completed_plans[i]->GetReturnValueObject(); 2955ffd83dbSDimitry Andric if (return_valobj_sp) 2965ffd83dbSDimitry Andric return return_valobj_sp; 2975ffd83dbSDimitry Andric } 2985ffd83dbSDimitry Andric return {}; 2995ffd83dbSDimitry Andric } 3005ffd83dbSDimitry Andric 3015ffd83dbSDimitry Andric lldb::ExpressionVariableSP ThreadPlanStack::GetExpressionVariable() const { 302fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 3035ffd83dbSDimitry Andric if (m_completed_plans.empty()) 3045ffd83dbSDimitry Andric return {}; 3055ffd83dbSDimitry Andric 3065ffd83dbSDimitry Andric for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 3075ffd83dbSDimitry Andric lldb::ExpressionVariableSP expression_variable_sp; 3085ffd83dbSDimitry Andric expression_variable_sp = m_completed_plans[i]->GetExpressionVariable(); 3095ffd83dbSDimitry Andric if (expression_variable_sp) 3105ffd83dbSDimitry Andric return expression_variable_sp; 3115ffd83dbSDimitry Andric } 3125ffd83dbSDimitry Andric return {}; 3135ffd83dbSDimitry Andric } 3145ffd83dbSDimitry Andric bool ThreadPlanStack::AnyPlans() const { 315fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 3165ffd83dbSDimitry Andric // There is always a base plan... 3175ffd83dbSDimitry Andric return m_plans.size() > 1; 3185ffd83dbSDimitry Andric } 3195ffd83dbSDimitry Andric 3205ffd83dbSDimitry Andric bool ThreadPlanStack::AnyCompletedPlans() const { 321fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 3225ffd83dbSDimitry Andric return !m_completed_plans.empty(); 3235ffd83dbSDimitry Andric } 3245ffd83dbSDimitry Andric 3255ffd83dbSDimitry Andric bool ThreadPlanStack::AnyDiscardedPlans() const { 326fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 3275ffd83dbSDimitry Andric return !m_discarded_plans.empty(); 3285ffd83dbSDimitry Andric } 3295ffd83dbSDimitry Andric 3305ffd83dbSDimitry Andric bool ThreadPlanStack::IsPlanDone(ThreadPlan *in_plan) const { 331fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 3325ffd83dbSDimitry Andric for (auto plan : m_completed_plans) { 3335ffd83dbSDimitry Andric if (plan.get() == in_plan) 3345ffd83dbSDimitry Andric return true; 3355ffd83dbSDimitry Andric } 3365ffd83dbSDimitry Andric return false; 3375ffd83dbSDimitry Andric } 3385ffd83dbSDimitry Andric 3395ffd83dbSDimitry Andric bool ThreadPlanStack::WasPlanDiscarded(ThreadPlan *in_plan) const { 340fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 3415ffd83dbSDimitry Andric for (auto plan : m_discarded_plans) { 3425ffd83dbSDimitry Andric if (plan.get() == in_plan) 3435ffd83dbSDimitry Andric return true; 3445ffd83dbSDimitry Andric } 3455ffd83dbSDimitry Andric return false; 3465ffd83dbSDimitry Andric } 3475ffd83dbSDimitry Andric 3485ffd83dbSDimitry Andric ThreadPlan *ThreadPlanStack::GetPreviousPlan(ThreadPlan *current_plan) const { 349fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 3505ffd83dbSDimitry Andric if (current_plan == nullptr) 3515ffd83dbSDimitry Andric return nullptr; 3525ffd83dbSDimitry Andric 3535ffd83dbSDimitry Andric // Look first in the completed plans, if the plan is here and there is 3545ffd83dbSDimitry Andric // a completed plan above it, return that. 3555ffd83dbSDimitry Andric int stack_size = m_completed_plans.size(); 3565ffd83dbSDimitry Andric for (int i = stack_size - 1; i > 0; i--) { 3575ffd83dbSDimitry Andric if (current_plan == m_completed_plans[i].get()) 3585ffd83dbSDimitry Andric return m_completed_plans[i - 1].get(); 3595ffd83dbSDimitry Andric } 3605ffd83dbSDimitry Andric 3615ffd83dbSDimitry Andric // If this is the first completed plan, the previous one is the 3625ffd83dbSDimitry Andric // bottom of the regular plan stack. 3635ffd83dbSDimitry Andric if (stack_size > 0 && m_completed_plans[0].get() == current_plan) { 3645ffd83dbSDimitry Andric return GetCurrentPlan().get(); 3655ffd83dbSDimitry Andric } 3665ffd83dbSDimitry Andric 3675ffd83dbSDimitry Andric // Otherwise look for it in the regular plans. 3685ffd83dbSDimitry Andric stack_size = m_plans.size(); 3695ffd83dbSDimitry Andric for (int i = stack_size - 1; i > 0; i--) { 3705ffd83dbSDimitry Andric if (current_plan == m_plans[i].get()) 3715ffd83dbSDimitry Andric return m_plans[i - 1].get(); 3725ffd83dbSDimitry Andric } 3735ffd83dbSDimitry Andric return nullptr; 3745ffd83dbSDimitry Andric } 3755ffd83dbSDimitry Andric 3765ffd83dbSDimitry Andric ThreadPlan *ThreadPlanStack::GetInnermostExpression() const { 377fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 3785ffd83dbSDimitry Andric int stack_size = m_plans.size(); 3795ffd83dbSDimitry Andric 3805ffd83dbSDimitry Andric for (int i = stack_size - 1; i > 0; i--) { 3815ffd83dbSDimitry Andric if (m_plans[i]->GetKind() == ThreadPlan::eKindCallFunction) 3825ffd83dbSDimitry Andric return m_plans[i].get(); 3835ffd83dbSDimitry Andric } 3845ffd83dbSDimitry Andric return nullptr; 3855ffd83dbSDimitry Andric } 3865ffd83dbSDimitry Andric 387e8d8bef9SDimitry Andric void ThreadPlanStack::ClearThreadCache() { 388fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 389e8d8bef9SDimitry Andric for (lldb::ThreadPlanSP thread_plan_sp : m_plans) 390e8d8bef9SDimitry Andric thread_plan_sp->ClearThreadCache(); 391e8d8bef9SDimitry Andric } 392e8d8bef9SDimitry Andric 3935ffd83dbSDimitry Andric void ThreadPlanStack::WillResume() { 394fe6060f1SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); 3955ffd83dbSDimitry Andric m_completed_plans.clear(); 3965ffd83dbSDimitry Andric m_discarded_plans.clear(); 3975ffd83dbSDimitry Andric } 3985ffd83dbSDimitry Andric 3995ffd83dbSDimitry Andric void ThreadPlanStackMap::Update(ThreadList ¤t_threads, 4005ffd83dbSDimitry Andric bool delete_missing, 4015ffd83dbSDimitry Andric bool check_for_new) { 4025ffd83dbSDimitry Andric 403*81ad6265SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex); 4045ffd83dbSDimitry Andric // Now find all the new threads and add them to the map: 4055ffd83dbSDimitry Andric if (check_for_new) { 4065ffd83dbSDimitry Andric for (auto thread : current_threads.Threads()) { 4075ffd83dbSDimitry Andric lldb::tid_t cur_tid = thread->GetID(); 4085ffd83dbSDimitry Andric if (!Find(cur_tid)) { 4095ffd83dbSDimitry Andric AddThread(*thread.get()); 410fe6060f1SDimitry Andric thread->QueueBasePlan(true); 4115ffd83dbSDimitry Andric } 4125ffd83dbSDimitry Andric } 4135ffd83dbSDimitry Andric } 4145ffd83dbSDimitry Andric 4155ffd83dbSDimitry Andric // If we aren't reaping missing threads at this point, 4165ffd83dbSDimitry Andric // we are done. 4175ffd83dbSDimitry Andric if (!delete_missing) 4185ffd83dbSDimitry Andric return; 4195ffd83dbSDimitry Andric // Otherwise scan for absent TID's. 4205ffd83dbSDimitry Andric std::vector<lldb::tid_t> missing_threads; 4215ffd83dbSDimitry Andric // If we are going to delete plans from the plan stack, 4225ffd83dbSDimitry Andric // then scan for absent TID's: 423fe6060f1SDimitry Andric for (auto &thread_plans : m_plans_list) { 4245ffd83dbSDimitry Andric lldb::tid_t cur_tid = thread_plans.first; 4255ffd83dbSDimitry Andric ThreadSP thread_sp = current_threads.FindThreadByID(cur_tid); 4265ffd83dbSDimitry Andric if (!thread_sp) 4275ffd83dbSDimitry Andric missing_threads.push_back(cur_tid); 4285ffd83dbSDimitry Andric } 4295ffd83dbSDimitry Andric for (lldb::tid_t tid : missing_threads) { 4305ffd83dbSDimitry Andric RemoveTID(tid); 4315ffd83dbSDimitry Andric } 4325ffd83dbSDimitry Andric } 4335ffd83dbSDimitry Andric 4345ffd83dbSDimitry Andric void ThreadPlanStackMap::DumpPlans(Stream &strm, 4355ffd83dbSDimitry Andric lldb::DescriptionLevel desc_level, 4365ffd83dbSDimitry Andric bool internal, bool condense_if_trivial, 4375ffd83dbSDimitry Andric bool skip_unreported) { 438*81ad6265SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex); 439fe6060f1SDimitry Andric for (auto &elem : m_plans_list) { 4405ffd83dbSDimitry Andric lldb::tid_t tid = elem.first; 4415ffd83dbSDimitry Andric uint32_t index_id = 0; 4425ffd83dbSDimitry Andric ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); 4435ffd83dbSDimitry Andric 4445ffd83dbSDimitry Andric if (skip_unreported) { 4455ffd83dbSDimitry Andric if (!thread_sp) 4465ffd83dbSDimitry Andric continue; 4475ffd83dbSDimitry Andric } 4485ffd83dbSDimitry Andric if (thread_sp) 4495ffd83dbSDimitry Andric index_id = thread_sp->GetIndexID(); 4505ffd83dbSDimitry Andric 4515ffd83dbSDimitry Andric if (condense_if_trivial) { 4525ffd83dbSDimitry Andric if (!elem.second.AnyPlans() && !elem.second.AnyCompletedPlans() && 4535ffd83dbSDimitry Andric !elem.second.AnyDiscardedPlans()) { 4545ffd83dbSDimitry Andric strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid); 4555ffd83dbSDimitry Andric strm.IndentMore(); 4565ffd83dbSDimitry Andric strm.Indent(); 4575ffd83dbSDimitry Andric strm.Printf("No active thread plans\n"); 4585ffd83dbSDimitry Andric strm.IndentLess(); 4595ffd83dbSDimitry Andric return; 4605ffd83dbSDimitry Andric } 4615ffd83dbSDimitry Andric } 4625ffd83dbSDimitry Andric 4635ffd83dbSDimitry Andric strm.Indent(); 4645ffd83dbSDimitry Andric strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid); 4655ffd83dbSDimitry Andric 4665ffd83dbSDimitry Andric elem.second.DumpThreadPlans(strm, desc_level, internal); 4675ffd83dbSDimitry Andric } 4685ffd83dbSDimitry Andric } 4695ffd83dbSDimitry Andric 4705ffd83dbSDimitry Andric bool ThreadPlanStackMap::DumpPlansForTID(Stream &strm, lldb::tid_t tid, 4715ffd83dbSDimitry Andric lldb::DescriptionLevel desc_level, 4725ffd83dbSDimitry Andric bool internal, 4735ffd83dbSDimitry Andric bool condense_if_trivial, 4745ffd83dbSDimitry Andric bool skip_unreported) { 475*81ad6265SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex); 4765ffd83dbSDimitry Andric uint32_t index_id = 0; 4775ffd83dbSDimitry Andric ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); 4785ffd83dbSDimitry Andric 4795ffd83dbSDimitry Andric if (skip_unreported) { 4805ffd83dbSDimitry Andric if (!thread_sp) { 4815ffd83dbSDimitry Andric strm.Format("Unknown TID: {0}", tid); 4825ffd83dbSDimitry Andric return false; 4835ffd83dbSDimitry Andric } 4845ffd83dbSDimitry Andric } 4855ffd83dbSDimitry Andric 4865ffd83dbSDimitry Andric if (thread_sp) 4875ffd83dbSDimitry Andric index_id = thread_sp->GetIndexID(); 4885ffd83dbSDimitry Andric ThreadPlanStack *stack = Find(tid); 4895ffd83dbSDimitry Andric if (!stack) { 4905ffd83dbSDimitry Andric strm.Format("Unknown TID: {0}\n", tid); 4915ffd83dbSDimitry Andric return false; 4925ffd83dbSDimitry Andric } 4935ffd83dbSDimitry Andric 4945ffd83dbSDimitry Andric if (condense_if_trivial) { 4955ffd83dbSDimitry Andric if (!stack->AnyPlans() && !stack->AnyCompletedPlans() && 4965ffd83dbSDimitry Andric !stack->AnyDiscardedPlans()) { 4975ffd83dbSDimitry Andric strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid); 4985ffd83dbSDimitry Andric strm.IndentMore(); 4995ffd83dbSDimitry Andric strm.Indent(); 5005ffd83dbSDimitry Andric strm.Printf("No active thread plans\n"); 5015ffd83dbSDimitry Andric strm.IndentLess(); 5025ffd83dbSDimitry Andric return true; 5035ffd83dbSDimitry Andric } 5045ffd83dbSDimitry Andric } 5055ffd83dbSDimitry Andric 5065ffd83dbSDimitry Andric strm.Indent(); 5075ffd83dbSDimitry Andric strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid); 5085ffd83dbSDimitry Andric 5095ffd83dbSDimitry Andric stack->DumpThreadPlans(strm, desc_level, internal); 5105ffd83dbSDimitry Andric return true; 5115ffd83dbSDimitry Andric } 5125ffd83dbSDimitry Andric 5135ffd83dbSDimitry Andric bool ThreadPlanStackMap::PrunePlansForTID(lldb::tid_t tid) { 5145ffd83dbSDimitry Andric // We only remove the plans for unreported TID's. 515*81ad6265SDimitry Andric std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex); 5165ffd83dbSDimitry Andric ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); 5175ffd83dbSDimitry Andric if (thread_sp) 5185ffd83dbSDimitry Andric return false; 5195ffd83dbSDimitry Andric 5205ffd83dbSDimitry Andric return RemoveTID(tid); 5215ffd83dbSDimitry Andric } 522