161e8e688SJim Ingham //===-- ThreadPlanStack.cpp -------------------------------------*- C++ -*-===// 261e8e688SJim Ingham // 361e8e688SJim Ingham // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 461e8e688SJim Ingham // See https://llvm.org/LICENSE.txt for license information. 561e8e688SJim Ingham // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 661e8e688SJim Ingham // 761e8e688SJim Ingham //===----------------------------------------------------------------------===// 861e8e688SJim Ingham 961e8e688SJim Ingham #include "lldb/Target/ThreadPlanStack.h" 1061e8e688SJim Ingham #include "lldb/Target/Process.h" 1161e8e688SJim Ingham #include "lldb/Target/Target.h" 1261e8e688SJim Ingham #include "lldb/Target/Thread.h" 1361e8e688SJim Ingham #include "lldb/Target/ThreadPlan.h" 1461e8e688SJim Ingham #include "lldb/Utility/Log.h" 1561e8e688SJim Ingham 1661e8e688SJim Ingham using namespace lldb; 1761e8e688SJim Ingham using namespace lldb_private; 1861e8e688SJim Ingham 19*1893065dSJim Ingham static void PrintPlanElement(Stream &s, const ThreadPlanSP &plan, 2061e8e688SJim Ingham lldb::DescriptionLevel desc_level, 2161e8e688SJim Ingham int32_t elem_idx) { 22*1893065dSJim Ingham s.IndentMore(); 23*1893065dSJim Ingham s.Indent(); 24*1893065dSJim Ingham s.Printf("Element %d: ", elem_idx); 25*1893065dSJim Ingham plan->GetDescription(&s, desc_level); 26*1893065dSJim Ingham s.EOL(); 27*1893065dSJim Ingham s.IndentLess(); 2861e8e688SJim Ingham } 2961e8e688SJim Ingham 30*1893065dSJim Ingham ThreadPlanStack::ThreadPlanStack(const Thread &thread, bool make_null) { 31*1893065dSJim Ingham if (make_null) { 32*1893065dSJim Ingham // The ThreadPlanNull doesn't do anything to the Thread, so this is actually 33*1893065dSJim Ingham // still a const operation. 34*1893065dSJim Ingham m_plans.push_back( 35*1893065dSJim Ingham ThreadPlanSP(new ThreadPlanNull(const_cast<Thread &>(thread)))); 36*1893065dSJim Ingham } 37*1893065dSJim Ingham } 38*1893065dSJim Ingham 39*1893065dSJim Ingham void ThreadPlanStack::DumpThreadPlans(Stream &s, 4061e8e688SJim Ingham lldb::DescriptionLevel desc_level, 4161e8e688SJim Ingham bool include_internal) const { 4261e8e688SJim Ingham 4361e8e688SJim Ingham uint32_t stack_size; 4461e8e688SJim Ingham 45*1893065dSJim Ingham s.IndentMore(); 46*1893065dSJim Ingham PrintOneStack(s, "Active plan stack", m_plans, desc_level, include_internal); 47*1893065dSJim Ingham PrintOneStack(s, "Completed plan stack", m_completed_plans, desc_level, 48*1893065dSJim Ingham include_internal); 49*1893065dSJim Ingham PrintOneStack(s, "Discarded plan stack", m_discarded_plans, desc_level, 50*1893065dSJim Ingham include_internal); 51*1893065dSJim Ingham s.IndentLess(); 5261e8e688SJim Ingham } 5361e8e688SJim Ingham 54*1893065dSJim Ingham void ThreadPlanStack::PrintOneStack(Stream &s, llvm::StringRef stack_name, 55*1893065dSJim Ingham const PlanStack &stack, 56*1893065dSJim Ingham lldb::DescriptionLevel desc_level, 57*1893065dSJim Ingham bool include_internal) const { 58*1893065dSJim Ingham // If the stack is empty, just exit: 59*1893065dSJim Ingham if (stack.empty()) 60*1893065dSJim Ingham return; 61*1893065dSJim Ingham 62*1893065dSJim Ingham // Make sure there are public completed plans: 63*1893065dSJim Ingham bool any_public = false; 64*1893065dSJim Ingham if (!include_internal) { 65*1893065dSJim Ingham for (auto plan : stack) { 66*1893065dSJim Ingham if (!plan->GetPrivate()) { 67*1893065dSJim Ingham any_public = true; 68*1893065dSJim Ingham break; 69*1893065dSJim Ingham } 70*1893065dSJim Ingham } 7161e8e688SJim Ingham } 7261e8e688SJim Ingham 73*1893065dSJim Ingham if (include_internal || any_public) { 74*1893065dSJim Ingham int print_idx = 0; 75*1893065dSJim Ingham s.Indent(); 76*1893065dSJim Ingham s.Printf("%s:\n", stack_name); 77*1893065dSJim Ingham for (auto plan : stack) { 78*1893065dSJim Ingham if (!include_internal && plan->GetPrivate()) 79*1893065dSJim Ingham continue; 8061e8e688SJim Ingham PrintPlanElement(s, plan, desc_level, print_idx++); 8161e8e688SJim Ingham } 82*1893065dSJim Ingham } 8361e8e688SJim Ingham } 8461e8e688SJim Ingham 8561e8e688SJim Ingham size_t ThreadPlanStack::CheckpointCompletedPlans() { 8661e8e688SJim Ingham m_completed_plan_checkpoint++; 8761e8e688SJim Ingham m_completed_plan_store.insert( 8861e8e688SJim Ingham std::make_pair(m_completed_plan_checkpoint, m_completed_plans)); 8961e8e688SJim Ingham return m_completed_plan_checkpoint; 9061e8e688SJim Ingham } 9161e8e688SJim Ingham 9261e8e688SJim Ingham void ThreadPlanStack::RestoreCompletedPlanCheckpoint(size_t checkpoint) { 9361e8e688SJim Ingham auto result = m_completed_plan_store.find(checkpoint); 9461e8e688SJim Ingham assert(result != m_completed_plan_store.end() && 9561e8e688SJim Ingham "Asked for a checkpoint that didn't exist"); 9661e8e688SJim Ingham m_completed_plans.swap((*result).second); 9761e8e688SJim Ingham m_completed_plan_store.erase(result); 9861e8e688SJim Ingham } 9961e8e688SJim Ingham 10061e8e688SJim Ingham void ThreadPlanStack::DiscardCompletedPlanCheckpoint(size_t checkpoint) { 10161e8e688SJim Ingham m_completed_plan_store.erase(checkpoint); 10261e8e688SJim Ingham } 10361e8e688SJim Ingham 10461e8e688SJim Ingham void ThreadPlanStack::ThreadDestroyed(Thread *thread) { 10561e8e688SJim Ingham // Tell the plan stacks that this thread is going away: 10661e8e688SJim Ingham for (ThreadPlanSP plan : m_plans) 10761e8e688SJim Ingham plan->ThreadDestroyed(); 10861e8e688SJim Ingham 10961e8e688SJim Ingham for (ThreadPlanSP plan : m_discarded_plans) 11061e8e688SJim Ingham plan->ThreadDestroyed(); 11161e8e688SJim Ingham 11261e8e688SJim Ingham for (ThreadPlanSP plan : m_completed_plans) 11361e8e688SJim Ingham plan->ThreadDestroyed(); 11461e8e688SJim Ingham 11561e8e688SJim Ingham // Now clear the current plan stacks: 11661e8e688SJim Ingham m_plans.clear(); 11761e8e688SJim Ingham m_discarded_plans.clear(); 11861e8e688SJim Ingham m_completed_plans.clear(); 11961e8e688SJim Ingham 12061e8e688SJim Ingham // Push a ThreadPlanNull on the plan stack. That way we can continue 12161e8e688SJim Ingham // assuming that the plan stack is never empty, but if somebody errantly asks 12261e8e688SJim Ingham // questions of a destroyed thread without checking first whether it is 12361e8e688SJim Ingham // destroyed, they won't crash. 12461e8e688SJim Ingham if (thread != nullptr) { 12561e8e688SJim Ingham lldb::ThreadPlanSP null_plan_sp(new ThreadPlanNull(*thread)); 12661e8e688SJim Ingham m_plans.push_back(null_plan_sp); 12761e8e688SJim Ingham } 12861e8e688SJim Ingham } 12961e8e688SJim Ingham 13061e8e688SJim Ingham void ThreadPlanStack::EnableTracer(bool value, bool single_stepping) { 13161e8e688SJim Ingham for (ThreadPlanSP plan : m_plans) { 13261e8e688SJim Ingham if (plan->GetThreadPlanTracer()) { 13361e8e688SJim Ingham plan->GetThreadPlanTracer()->EnableTracing(value); 13461e8e688SJim Ingham plan->GetThreadPlanTracer()->EnableSingleStep(single_stepping); 13561e8e688SJim Ingham } 13661e8e688SJim Ingham } 13761e8e688SJim Ingham } 13861e8e688SJim Ingham 13961e8e688SJim Ingham void ThreadPlanStack::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) { 14061e8e688SJim Ingham for (ThreadPlanSP plan : m_plans) 14161e8e688SJim Ingham plan->SetThreadPlanTracer(tracer_sp); 14261e8e688SJim Ingham } 14361e8e688SJim Ingham 14461e8e688SJim Ingham void ThreadPlanStack::PushPlan(lldb::ThreadPlanSP new_plan_sp) { 14561e8e688SJim Ingham // If the thread plan doesn't already have a tracer, give it its parent's 14661e8e688SJim Ingham // tracer: 14761e8e688SJim Ingham // The first plan has to be a base plan: 14861e8e688SJim Ingham assert(m_plans.size() > 0 || 14961e8e688SJim Ingham new_plan_sp->IsBasePlan() && "Zeroth plan must be a base plan"); 15061e8e688SJim Ingham 15161e8e688SJim Ingham if (!new_plan_sp->GetThreadPlanTracer()) { 15261e8e688SJim Ingham assert(!m_plans.empty()); 15361e8e688SJim Ingham new_plan_sp->SetThreadPlanTracer(m_plans.back()->GetThreadPlanTracer()); 15461e8e688SJim Ingham } 15561e8e688SJim Ingham m_plans.push_back(new_plan_sp); 15661e8e688SJim Ingham new_plan_sp->DidPush(); 15761e8e688SJim Ingham } 15861e8e688SJim Ingham 15961e8e688SJim Ingham lldb::ThreadPlanSP ThreadPlanStack::PopPlan() { 16061e8e688SJim Ingham assert(m_plans.size() > 1 && "Can't pop the base thread plan"); 16161e8e688SJim Ingham 16261e8e688SJim Ingham lldb::ThreadPlanSP &plan_sp = m_plans.back(); 16361e8e688SJim Ingham m_completed_plans.push_back(plan_sp); 16461e8e688SJim Ingham plan_sp->WillPop(); 16561e8e688SJim Ingham m_plans.pop_back(); 16661e8e688SJim Ingham return plan_sp; 16761e8e688SJim Ingham } 16861e8e688SJim Ingham 16961e8e688SJim Ingham lldb::ThreadPlanSP ThreadPlanStack::DiscardPlan() { 17061e8e688SJim Ingham assert(m_plans.size() > 1 && "Can't discard the base thread plan"); 17161e8e688SJim Ingham 17261e8e688SJim Ingham lldb::ThreadPlanSP &plan_sp = m_plans.back(); 17361e8e688SJim Ingham m_discarded_plans.push_back(plan_sp); 17461e8e688SJim Ingham plan_sp->WillPop(); 17561e8e688SJim Ingham m_plans.pop_back(); 17661e8e688SJim Ingham return plan_sp; 17761e8e688SJim Ingham } 17861e8e688SJim Ingham 17961e8e688SJim Ingham // If the input plan is nullptr, discard all plans. Otherwise make sure this 18061e8e688SJim Ingham // plan is in the stack, and if so discard up to and including it. 18161e8e688SJim Ingham void ThreadPlanStack::DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr) { 18261e8e688SJim Ingham int stack_size = m_plans.size(); 18361e8e688SJim Ingham 18461e8e688SJim Ingham if (up_to_plan_ptr == nullptr) { 18561e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) 18661e8e688SJim Ingham DiscardPlan(); 18761e8e688SJim Ingham return; 18861e8e688SJim Ingham } 18961e8e688SJim Ingham 19061e8e688SJim Ingham bool found_it = false; 19161e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) { 19261e8e688SJim Ingham if (m_plans[i].get() == up_to_plan_ptr) { 19361e8e688SJim Ingham found_it = true; 19461e8e688SJim Ingham break; 19561e8e688SJim Ingham } 19661e8e688SJim Ingham } 19761e8e688SJim Ingham 19861e8e688SJim Ingham if (found_it) { 19961e8e688SJim Ingham bool last_one = false; 20061e8e688SJim Ingham for (int i = stack_size - 1; i > 0 && !last_one; i--) { 20161e8e688SJim Ingham if (GetCurrentPlan().get() == up_to_plan_ptr) 20261e8e688SJim Ingham last_one = true; 20361e8e688SJim Ingham DiscardPlan(); 20461e8e688SJim Ingham } 20561e8e688SJim Ingham } 20661e8e688SJim Ingham } 20761e8e688SJim Ingham 20861e8e688SJim Ingham void ThreadPlanStack::DiscardAllPlans() { 20961e8e688SJim Ingham int stack_size = m_plans.size(); 21061e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) { 21161e8e688SJim Ingham DiscardPlan(); 21261e8e688SJim Ingham } 21361e8e688SJim Ingham return; 21461e8e688SJim Ingham } 21561e8e688SJim Ingham 21661e8e688SJim Ingham void ThreadPlanStack::DiscardConsultingMasterPlans() { 21761e8e688SJim Ingham while (true) { 21861e8e688SJim Ingham int master_plan_idx; 21961e8e688SJim Ingham bool discard = true; 22061e8e688SJim Ingham 22161e8e688SJim Ingham // Find the first master plan, see if it wants discarding, and if yes 22261e8e688SJim Ingham // discard up to it. 22361e8e688SJim Ingham for (master_plan_idx = m_plans.size() - 1; master_plan_idx >= 0; 22461e8e688SJim Ingham master_plan_idx--) { 22561e8e688SJim Ingham if (m_plans[master_plan_idx]->IsMasterPlan()) { 22661e8e688SJim Ingham discard = m_plans[master_plan_idx]->OkayToDiscard(); 22761e8e688SJim Ingham break; 22861e8e688SJim Ingham } 22961e8e688SJim Ingham } 23061e8e688SJim Ingham 23161e8e688SJim Ingham // If the master plan doesn't want to get discarded, then we're done. 23261e8e688SJim Ingham if (!discard) 23361e8e688SJim Ingham return; 23461e8e688SJim Ingham 23561e8e688SJim Ingham // First pop all the dependent plans: 23661e8e688SJim Ingham for (int i = m_plans.size() - 1; i > master_plan_idx; i--) { 23761e8e688SJim Ingham DiscardPlan(); 23861e8e688SJim Ingham } 23961e8e688SJim Ingham 24061e8e688SJim Ingham // Now discard the master plan itself. 24161e8e688SJim Ingham // The bottom-most plan never gets discarded. "OkayToDiscard" for it 24261e8e688SJim Ingham // means discard it's dependent plans, but not it... 24361e8e688SJim Ingham if (master_plan_idx > 0) { 24461e8e688SJim Ingham DiscardPlan(); 24561e8e688SJim Ingham } 24661e8e688SJim Ingham } 24761e8e688SJim Ingham } 24861e8e688SJim Ingham 24961e8e688SJim Ingham lldb::ThreadPlanSP ThreadPlanStack::GetCurrentPlan() const { 25061e8e688SJim Ingham assert(m_plans.size() != 0 && "There will always be a base plan."); 25161e8e688SJim Ingham return m_plans.back(); 25261e8e688SJim Ingham } 25361e8e688SJim Ingham 25461e8e688SJim Ingham lldb::ThreadPlanSP ThreadPlanStack::GetCompletedPlan(bool skip_private) const { 25561e8e688SJim Ingham if (m_completed_plans.empty()) 25661e8e688SJim Ingham return {}; 25761e8e688SJim Ingham 25861e8e688SJim Ingham if (!skip_private) 25961e8e688SJim Ingham return m_completed_plans.back(); 26061e8e688SJim Ingham 26161e8e688SJim Ingham for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 26261e8e688SJim Ingham lldb::ThreadPlanSP completed_plan_sp; 26361e8e688SJim Ingham completed_plan_sp = m_completed_plans[i]; 26461e8e688SJim Ingham if (!completed_plan_sp->GetPrivate()) 26561e8e688SJim Ingham return completed_plan_sp; 26661e8e688SJim Ingham } 26761e8e688SJim Ingham return {}; 26861e8e688SJim Ingham } 26961e8e688SJim Ingham 27061e8e688SJim Ingham lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx, 27161e8e688SJim Ingham bool skip_private) const { 27261e8e688SJim Ingham uint32_t idx = 0; 27361e8e688SJim Ingham ThreadPlan *up_to_plan_ptr = nullptr; 27461e8e688SJim Ingham 27561e8e688SJim Ingham for (lldb::ThreadPlanSP plan_sp : m_plans) { 27661e8e688SJim Ingham if (skip_private && plan_sp->GetPrivate()) 27761e8e688SJim Ingham continue; 27861e8e688SJim Ingham if (idx == plan_idx) 27961e8e688SJim Ingham return plan_sp; 28061e8e688SJim Ingham idx++; 28161e8e688SJim Ingham } 28261e8e688SJim Ingham return {}; 28361e8e688SJim Ingham } 28461e8e688SJim Ingham 28561e8e688SJim Ingham lldb::ValueObjectSP ThreadPlanStack::GetReturnValueObject() const { 28661e8e688SJim Ingham if (m_completed_plans.empty()) 28761e8e688SJim Ingham return {}; 28861e8e688SJim Ingham 28961e8e688SJim Ingham for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 29061e8e688SJim Ingham lldb::ValueObjectSP return_valobj_sp; 29161e8e688SJim Ingham return_valobj_sp = m_completed_plans[i]->GetReturnValueObject(); 29261e8e688SJim Ingham if (return_valobj_sp) 29361e8e688SJim Ingham return return_valobj_sp; 29461e8e688SJim Ingham } 29561e8e688SJim Ingham return {}; 29661e8e688SJim Ingham } 29761e8e688SJim Ingham 29861e8e688SJim Ingham lldb::ExpressionVariableSP ThreadPlanStack::GetExpressionVariable() const { 29961e8e688SJim Ingham if (m_completed_plans.empty()) 30061e8e688SJim Ingham return {}; 30161e8e688SJim Ingham 30261e8e688SJim Ingham for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 30361e8e688SJim Ingham lldb::ExpressionVariableSP expression_variable_sp; 30461e8e688SJim Ingham expression_variable_sp = m_completed_plans[i]->GetExpressionVariable(); 30561e8e688SJim Ingham if (expression_variable_sp) 30661e8e688SJim Ingham return expression_variable_sp; 30761e8e688SJim Ingham } 30861e8e688SJim Ingham return {}; 30961e8e688SJim Ingham } 31061e8e688SJim Ingham bool ThreadPlanStack::AnyPlans() const { 31161e8e688SJim Ingham // There is always a base plan... 31261e8e688SJim Ingham return m_plans.size() > 1; 31361e8e688SJim Ingham } 31461e8e688SJim Ingham 31561e8e688SJim Ingham bool ThreadPlanStack::AnyCompletedPlans() const { 31661e8e688SJim Ingham return !m_completed_plans.empty(); 31761e8e688SJim Ingham } 31861e8e688SJim Ingham 31961e8e688SJim Ingham bool ThreadPlanStack::AnyDiscardedPlans() const { 32061e8e688SJim Ingham return !m_discarded_plans.empty(); 32161e8e688SJim Ingham } 32261e8e688SJim Ingham 32361e8e688SJim Ingham bool ThreadPlanStack::IsPlanDone(ThreadPlan *in_plan) const { 32461e8e688SJim Ingham for (auto plan : m_completed_plans) { 32561e8e688SJim Ingham if (plan.get() == in_plan) 32661e8e688SJim Ingham return true; 32761e8e688SJim Ingham } 32861e8e688SJim Ingham return false; 32961e8e688SJim Ingham } 33061e8e688SJim Ingham 33161e8e688SJim Ingham bool ThreadPlanStack::WasPlanDiscarded(ThreadPlan *in_plan) const { 33261e8e688SJim Ingham for (auto plan : m_discarded_plans) { 33361e8e688SJim Ingham if (plan.get() == in_plan) 33461e8e688SJim Ingham return true; 33561e8e688SJim Ingham } 33661e8e688SJim Ingham return false; 33761e8e688SJim Ingham } 33861e8e688SJim Ingham 33961e8e688SJim Ingham ThreadPlan *ThreadPlanStack::GetPreviousPlan(ThreadPlan *current_plan) const { 34061e8e688SJim Ingham if (current_plan == nullptr) 34161e8e688SJim Ingham return nullptr; 34261e8e688SJim Ingham 34361e8e688SJim Ingham // Look first in the completed plans, if the plan is here and there is 34461e8e688SJim Ingham // a completed plan above it, return that. 34561e8e688SJim Ingham int stack_size = m_completed_plans.size(); 34661e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) { 34761e8e688SJim Ingham if (current_plan == m_completed_plans[i].get()) 34861e8e688SJim Ingham return m_completed_plans[i - 1].get(); 34961e8e688SJim Ingham } 35061e8e688SJim Ingham 35161e8e688SJim Ingham // If this is the first completed plan, the previous one is the 35261e8e688SJim Ingham // bottom of the regular plan stack. 35361e8e688SJim Ingham if (stack_size > 0 && m_completed_plans[0].get() == current_plan) { 35461e8e688SJim Ingham return GetCurrentPlan().get(); 35561e8e688SJim Ingham } 35661e8e688SJim Ingham 35761e8e688SJim Ingham // Otherwise look for it in the regular plans. 35861e8e688SJim Ingham stack_size = m_plans.size(); 35961e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) { 36061e8e688SJim Ingham if (current_plan == m_plans[i].get()) 36161e8e688SJim Ingham return m_plans[i - 1].get(); 36261e8e688SJim Ingham } 36361e8e688SJim Ingham return nullptr; 36461e8e688SJim Ingham } 36561e8e688SJim Ingham 36661e8e688SJim Ingham ThreadPlan *ThreadPlanStack::GetInnermostExpression() const { 36761e8e688SJim Ingham int stack_size = m_plans.size(); 36861e8e688SJim Ingham 36961e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) { 37061e8e688SJim Ingham if (m_plans[i]->GetKind() == ThreadPlan::eKindCallFunction) 37161e8e688SJim Ingham return m_plans[i].get(); 37261e8e688SJim Ingham } 37361e8e688SJim Ingham return nullptr; 37461e8e688SJim Ingham } 37561e8e688SJim Ingham 37661e8e688SJim Ingham void ThreadPlanStack::WillResume() { 37761e8e688SJim Ingham m_completed_plans.clear(); 37861e8e688SJim Ingham m_discarded_plans.clear(); 37961e8e688SJim Ingham } 38061e8e688SJim Ingham 38161e8e688SJim Ingham const ThreadPlanStack::PlanStack & 38261e8e688SJim Ingham ThreadPlanStack::GetStackOfKind(ThreadPlanStack::StackKind kind) const { 38361e8e688SJim Ingham switch (kind) { 38461e8e688SJim Ingham case ePlans: 38561e8e688SJim Ingham return m_plans; 38661e8e688SJim Ingham case eCompletedPlans: 38761e8e688SJim Ingham return m_completed_plans; 38861e8e688SJim Ingham case eDiscardedPlans: 38961e8e688SJim Ingham return m_discarded_plans; 39061e8e688SJim Ingham } 39161e8e688SJim Ingham llvm_unreachable("Invalid StackKind value"); 39261e8e688SJim Ingham } 393*1893065dSJim Ingham 394*1893065dSJim Ingham void ThreadPlanStackMap::Update(ThreadList ¤t_threads, 395*1893065dSJim Ingham bool delete_missing, 396*1893065dSJim Ingham bool check_for_new) { 397*1893065dSJim Ingham 398*1893065dSJim Ingham // Now find all the new threads and add them to the map: 399*1893065dSJim Ingham if (check_for_new) { 400*1893065dSJim Ingham for (auto thread : current_threads.Threads()) { 401*1893065dSJim Ingham lldb::tid_t cur_tid = thread->GetID(); 402*1893065dSJim Ingham if (!Find(cur_tid)) { 403*1893065dSJim Ingham AddThread(*thread.get()); 404*1893065dSJim Ingham thread->QueueFundamentalPlan(true); 405*1893065dSJim Ingham } 406*1893065dSJim Ingham } 407*1893065dSJim Ingham } 408*1893065dSJim Ingham 409*1893065dSJim Ingham // If we aren't reaping missing threads at this point, 410*1893065dSJim Ingham // we are done. 411*1893065dSJim Ingham if (!delete_missing) 412*1893065dSJim Ingham return; 413*1893065dSJim Ingham // Otherwise scan for absent TID's. 414*1893065dSJim Ingham std::vector<lldb::tid_t> missing_threads; 415*1893065dSJim Ingham // If we are going to delete plans from the plan stack, 416*1893065dSJim Ingham // then scan for absent TID's: 417*1893065dSJim Ingham for (auto thread_plans : m_plans_list) { 418*1893065dSJim Ingham lldb::tid_t cur_tid = thread_plans.first; 419*1893065dSJim Ingham ThreadSP thread_sp = current_threads.FindThreadByID(cur_tid); 420*1893065dSJim Ingham if (!thread_sp) 421*1893065dSJim Ingham missing_threads.push_back(cur_tid); 422*1893065dSJim Ingham } 423*1893065dSJim Ingham for (lldb::tid_t tid : missing_threads) { 424*1893065dSJim Ingham RemoveTID(tid); 425*1893065dSJim Ingham } 426*1893065dSJim Ingham } 427*1893065dSJim Ingham 428*1893065dSJim Ingham void ThreadPlanStackMap::DumpPlans(Stream &strm, 429*1893065dSJim Ingham lldb::DescriptionLevel desc_level, 430*1893065dSJim Ingham bool internal, bool condense_if_trivial, 431*1893065dSJim Ingham bool skip_unreported) { 432*1893065dSJim Ingham for (auto elem : m_plans_list) { 433*1893065dSJim Ingham lldb::tid_t tid = elem.first; 434*1893065dSJim Ingham uint32_t index_id = 0; 435*1893065dSJim Ingham ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); 436*1893065dSJim Ingham 437*1893065dSJim Ingham if (skip_unreported) { 438*1893065dSJim Ingham if (!thread_sp) 439*1893065dSJim Ingham continue; 440*1893065dSJim Ingham } 441*1893065dSJim Ingham if (thread_sp) 442*1893065dSJim Ingham index_id = thread_sp->GetIndexID(); 443*1893065dSJim Ingham 444*1893065dSJim Ingham if (condense_if_trivial) { 445*1893065dSJim Ingham if (!elem.second.AnyPlans() && !elem.second.AnyCompletedPlans() && 446*1893065dSJim Ingham !elem.second.AnyDiscardedPlans()) { 447*1893065dSJim Ingham strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid); 448*1893065dSJim Ingham strm.IndentMore(); 449*1893065dSJim Ingham strm.Indent(); 450*1893065dSJim Ingham strm.Printf("No active thread plans\n"); 451*1893065dSJim Ingham strm.IndentLess(); 452*1893065dSJim Ingham return; 453*1893065dSJim Ingham } 454*1893065dSJim Ingham } 455*1893065dSJim Ingham 456*1893065dSJim Ingham strm.Indent(); 457*1893065dSJim Ingham strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid); 458*1893065dSJim Ingham 459*1893065dSJim Ingham elem.second.DumpThreadPlans(strm, desc_level, internal); 460*1893065dSJim Ingham } 461*1893065dSJim Ingham } 462*1893065dSJim Ingham 463*1893065dSJim Ingham bool ThreadPlanStackMap::DumpPlansForTID(Stream &strm, lldb::tid_t tid, 464*1893065dSJim Ingham lldb::DescriptionLevel desc_level, 465*1893065dSJim Ingham bool internal, 466*1893065dSJim Ingham bool condense_if_trivial, 467*1893065dSJim Ingham bool skip_unreported) { 468*1893065dSJim Ingham uint32_t index_id = 0; 469*1893065dSJim Ingham ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); 470*1893065dSJim Ingham 471*1893065dSJim Ingham if (skip_unreported) { 472*1893065dSJim Ingham if (!thread_sp) { 473*1893065dSJim Ingham strm.Format("Unknown TID: {0}", tid); 474*1893065dSJim Ingham return false; 475*1893065dSJim Ingham } 476*1893065dSJim Ingham } 477*1893065dSJim Ingham 478*1893065dSJim Ingham if (thread_sp) 479*1893065dSJim Ingham index_id = thread_sp->GetIndexID(); 480*1893065dSJim Ingham ThreadPlanStack *stack = Find(tid); 481*1893065dSJim Ingham if (!stack) { 482*1893065dSJim Ingham strm.Format("Unknown TID: {0}\n", tid); 483*1893065dSJim Ingham return false; 484*1893065dSJim Ingham } 485*1893065dSJim Ingham 486*1893065dSJim Ingham if (condense_if_trivial) { 487*1893065dSJim Ingham if (!stack->AnyPlans() && !stack->AnyCompletedPlans() && 488*1893065dSJim Ingham !stack->AnyDiscardedPlans()) { 489*1893065dSJim Ingham strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid); 490*1893065dSJim Ingham strm.IndentMore(); 491*1893065dSJim Ingham strm.Indent(); 492*1893065dSJim Ingham strm.Printf("No active thread plans\n"); 493*1893065dSJim Ingham strm.IndentLess(); 494*1893065dSJim Ingham return true; 495*1893065dSJim Ingham } 496*1893065dSJim Ingham } 497*1893065dSJim Ingham 498*1893065dSJim Ingham strm.Indent(); 499*1893065dSJim Ingham strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid); 500*1893065dSJim Ingham 501*1893065dSJim Ingham stack->DumpThreadPlans(strm, desc_level, internal); 502*1893065dSJim Ingham return true; 503*1893065dSJim Ingham } 504*1893065dSJim Ingham 505*1893065dSJim Ingham bool ThreadPlanStackMap::PrunePlansForTID(lldb::tid_t tid) { 506*1893065dSJim Ingham // We only remove the plans for unreported TID's. 507*1893065dSJim Ingham ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); 508*1893065dSJim Ingham if (thread_sp) 509*1893065dSJim Ingham return false; 510*1893065dSJim Ingham 511*1893065dSJim Ingham return RemoveTID(tid); 512*1893065dSJim Ingham } 513