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 191893065dSJim Ingham static void PrintPlanElement(Stream &s, const ThreadPlanSP &plan, 2061e8e688SJim Ingham lldb::DescriptionLevel desc_level, 2161e8e688SJim Ingham int32_t elem_idx) { 221893065dSJim Ingham s.IndentMore(); 231893065dSJim Ingham s.Indent(); 241893065dSJim Ingham s.Printf("Element %d: ", elem_idx); 251893065dSJim Ingham plan->GetDescription(&s, desc_level); 261893065dSJim Ingham s.EOL(); 271893065dSJim Ingham s.IndentLess(); 2861e8e688SJim Ingham } 2961e8e688SJim Ingham 301893065dSJim Ingham ThreadPlanStack::ThreadPlanStack(const Thread &thread, bool make_null) { 311893065dSJim Ingham if (make_null) { 321893065dSJim Ingham // The ThreadPlanNull doesn't do anything to the Thread, so this is actually 331893065dSJim Ingham // still a const operation. 341893065dSJim Ingham m_plans.push_back( 351893065dSJim Ingham ThreadPlanSP(new ThreadPlanNull(const_cast<Thread &>(thread)))); 361893065dSJim Ingham } 371893065dSJim Ingham } 381893065dSJim Ingham 391893065dSJim Ingham void ThreadPlanStack::DumpThreadPlans(Stream &s, 4061e8e688SJim Ingham lldb::DescriptionLevel desc_level, 4161e8e688SJim Ingham bool include_internal) const { 421893065dSJim Ingham s.IndentMore(); 431893065dSJim Ingham PrintOneStack(s, "Active plan stack", m_plans, desc_level, include_internal); 441893065dSJim Ingham PrintOneStack(s, "Completed plan stack", m_completed_plans, desc_level, 451893065dSJim Ingham include_internal); 461893065dSJim Ingham PrintOneStack(s, "Discarded plan stack", m_discarded_plans, desc_level, 471893065dSJim Ingham include_internal); 481893065dSJim Ingham s.IndentLess(); 4961e8e688SJim Ingham } 5061e8e688SJim Ingham 511893065dSJim Ingham void ThreadPlanStack::PrintOneStack(Stream &s, llvm::StringRef stack_name, 521893065dSJim Ingham const PlanStack &stack, 531893065dSJim Ingham lldb::DescriptionLevel desc_level, 541893065dSJim Ingham bool include_internal) const { 551893065dSJim Ingham // If the stack is empty, just exit: 561893065dSJim Ingham if (stack.empty()) 571893065dSJim Ingham return; 581893065dSJim Ingham 591893065dSJim Ingham // Make sure there are public completed plans: 601893065dSJim Ingham bool any_public = false; 611893065dSJim Ingham if (!include_internal) { 621893065dSJim Ingham for (auto plan : stack) { 631893065dSJim Ingham if (!plan->GetPrivate()) { 641893065dSJim Ingham any_public = true; 651893065dSJim Ingham break; 661893065dSJim Ingham } 671893065dSJim Ingham } 6861e8e688SJim Ingham } 6961e8e688SJim Ingham 701893065dSJim Ingham if (include_internal || any_public) { 711893065dSJim Ingham int print_idx = 0; 721893065dSJim Ingham s.Indent(); 73*3ccd454cSEric Christopher s << stack_name << ":\n"; 741893065dSJim Ingham for (auto plan : stack) { 751893065dSJim Ingham if (!include_internal && plan->GetPrivate()) 761893065dSJim Ingham continue; 7761e8e688SJim Ingham PrintPlanElement(s, plan, desc_level, print_idx++); 7861e8e688SJim Ingham } 791893065dSJim Ingham } 8061e8e688SJim Ingham } 8161e8e688SJim Ingham 8261e8e688SJim Ingham size_t ThreadPlanStack::CheckpointCompletedPlans() { 8361e8e688SJim Ingham m_completed_plan_checkpoint++; 8461e8e688SJim Ingham m_completed_plan_store.insert( 8561e8e688SJim Ingham std::make_pair(m_completed_plan_checkpoint, m_completed_plans)); 8661e8e688SJim Ingham return m_completed_plan_checkpoint; 8761e8e688SJim Ingham } 8861e8e688SJim Ingham 8961e8e688SJim Ingham void ThreadPlanStack::RestoreCompletedPlanCheckpoint(size_t checkpoint) { 9061e8e688SJim Ingham auto result = m_completed_plan_store.find(checkpoint); 9161e8e688SJim Ingham assert(result != m_completed_plan_store.end() && 9261e8e688SJim Ingham "Asked for a checkpoint that didn't exist"); 9361e8e688SJim Ingham m_completed_plans.swap((*result).second); 9461e8e688SJim Ingham m_completed_plan_store.erase(result); 9561e8e688SJim Ingham } 9661e8e688SJim Ingham 9761e8e688SJim Ingham void ThreadPlanStack::DiscardCompletedPlanCheckpoint(size_t checkpoint) { 9861e8e688SJim Ingham m_completed_plan_store.erase(checkpoint); 9961e8e688SJim Ingham } 10061e8e688SJim Ingham 10161e8e688SJim Ingham void ThreadPlanStack::ThreadDestroyed(Thread *thread) { 10261e8e688SJim Ingham // Tell the plan stacks that this thread is going away: 10361e8e688SJim Ingham for (ThreadPlanSP plan : m_plans) 10461e8e688SJim Ingham plan->ThreadDestroyed(); 10561e8e688SJim Ingham 10661e8e688SJim Ingham for (ThreadPlanSP plan : m_discarded_plans) 10761e8e688SJim Ingham plan->ThreadDestroyed(); 10861e8e688SJim Ingham 10961e8e688SJim Ingham for (ThreadPlanSP plan : m_completed_plans) 11061e8e688SJim Ingham plan->ThreadDestroyed(); 11161e8e688SJim Ingham 11261e8e688SJim Ingham // Now clear the current plan stacks: 11361e8e688SJim Ingham m_plans.clear(); 11461e8e688SJim Ingham m_discarded_plans.clear(); 11561e8e688SJim Ingham m_completed_plans.clear(); 11661e8e688SJim Ingham 11761e8e688SJim Ingham // Push a ThreadPlanNull on the plan stack. That way we can continue 11861e8e688SJim Ingham // assuming that the plan stack is never empty, but if somebody errantly asks 11961e8e688SJim Ingham // questions of a destroyed thread without checking first whether it is 12061e8e688SJim Ingham // destroyed, they won't crash. 12161e8e688SJim Ingham if (thread != nullptr) { 12261e8e688SJim Ingham lldb::ThreadPlanSP null_plan_sp(new ThreadPlanNull(*thread)); 12361e8e688SJim Ingham m_plans.push_back(null_plan_sp); 12461e8e688SJim Ingham } 12561e8e688SJim Ingham } 12661e8e688SJim Ingham 12761e8e688SJim Ingham void ThreadPlanStack::EnableTracer(bool value, bool single_stepping) { 12861e8e688SJim Ingham for (ThreadPlanSP plan : m_plans) { 12961e8e688SJim Ingham if (plan->GetThreadPlanTracer()) { 13061e8e688SJim Ingham plan->GetThreadPlanTracer()->EnableTracing(value); 13161e8e688SJim Ingham plan->GetThreadPlanTracer()->EnableSingleStep(single_stepping); 13261e8e688SJim Ingham } 13361e8e688SJim Ingham } 13461e8e688SJim Ingham } 13561e8e688SJim Ingham 13661e8e688SJim Ingham void ThreadPlanStack::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) { 13761e8e688SJim Ingham for (ThreadPlanSP plan : m_plans) 13861e8e688SJim Ingham plan->SetThreadPlanTracer(tracer_sp); 13961e8e688SJim Ingham } 14061e8e688SJim Ingham 14161e8e688SJim Ingham void ThreadPlanStack::PushPlan(lldb::ThreadPlanSP new_plan_sp) { 14261e8e688SJim Ingham // If the thread plan doesn't already have a tracer, give it its parent's 14361e8e688SJim Ingham // tracer: 14461e8e688SJim Ingham // The first plan has to be a base plan: 14561e8e688SJim Ingham assert(m_plans.size() > 0 || 14661e8e688SJim Ingham new_plan_sp->IsBasePlan() && "Zeroth plan must be a base plan"); 14761e8e688SJim Ingham 14861e8e688SJim Ingham if (!new_plan_sp->GetThreadPlanTracer()) { 14961e8e688SJim Ingham assert(!m_plans.empty()); 15061e8e688SJim Ingham new_plan_sp->SetThreadPlanTracer(m_plans.back()->GetThreadPlanTracer()); 15161e8e688SJim Ingham } 15261e8e688SJim Ingham m_plans.push_back(new_plan_sp); 15361e8e688SJim Ingham new_plan_sp->DidPush(); 15461e8e688SJim Ingham } 15561e8e688SJim Ingham 15661e8e688SJim Ingham lldb::ThreadPlanSP ThreadPlanStack::PopPlan() { 15761e8e688SJim Ingham assert(m_plans.size() > 1 && "Can't pop the base thread plan"); 15861e8e688SJim Ingham 15961e8e688SJim Ingham lldb::ThreadPlanSP &plan_sp = m_plans.back(); 16061e8e688SJim Ingham m_completed_plans.push_back(plan_sp); 16161e8e688SJim Ingham plan_sp->WillPop(); 16261e8e688SJim Ingham m_plans.pop_back(); 16361e8e688SJim Ingham return plan_sp; 16461e8e688SJim Ingham } 16561e8e688SJim Ingham 16661e8e688SJim Ingham lldb::ThreadPlanSP ThreadPlanStack::DiscardPlan() { 16761e8e688SJim Ingham assert(m_plans.size() > 1 && "Can't discard the base thread plan"); 16861e8e688SJim Ingham 16961e8e688SJim Ingham lldb::ThreadPlanSP &plan_sp = m_plans.back(); 17061e8e688SJim Ingham m_discarded_plans.push_back(plan_sp); 17161e8e688SJim Ingham plan_sp->WillPop(); 17261e8e688SJim Ingham m_plans.pop_back(); 17361e8e688SJim Ingham return plan_sp; 17461e8e688SJim Ingham } 17561e8e688SJim Ingham 17661e8e688SJim Ingham // If the input plan is nullptr, discard all plans. Otherwise make sure this 17761e8e688SJim Ingham // plan is in the stack, and if so discard up to and including it. 17861e8e688SJim Ingham void ThreadPlanStack::DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr) { 17961e8e688SJim Ingham int stack_size = m_plans.size(); 18061e8e688SJim Ingham 18161e8e688SJim Ingham if (up_to_plan_ptr == nullptr) { 18261e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) 18361e8e688SJim Ingham DiscardPlan(); 18461e8e688SJim Ingham return; 18561e8e688SJim Ingham } 18661e8e688SJim Ingham 18761e8e688SJim Ingham bool found_it = false; 18861e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) { 18961e8e688SJim Ingham if (m_plans[i].get() == up_to_plan_ptr) { 19061e8e688SJim Ingham found_it = true; 19161e8e688SJim Ingham break; 19261e8e688SJim Ingham } 19361e8e688SJim Ingham } 19461e8e688SJim Ingham 19561e8e688SJim Ingham if (found_it) { 19661e8e688SJim Ingham bool last_one = false; 19761e8e688SJim Ingham for (int i = stack_size - 1; i > 0 && !last_one; i--) { 19861e8e688SJim Ingham if (GetCurrentPlan().get() == up_to_plan_ptr) 19961e8e688SJim Ingham last_one = true; 20061e8e688SJim Ingham DiscardPlan(); 20161e8e688SJim Ingham } 20261e8e688SJim Ingham } 20361e8e688SJim Ingham } 20461e8e688SJim Ingham 20561e8e688SJim Ingham void ThreadPlanStack::DiscardAllPlans() { 20661e8e688SJim Ingham int stack_size = m_plans.size(); 20761e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) { 20861e8e688SJim Ingham DiscardPlan(); 20961e8e688SJim Ingham } 21061e8e688SJim Ingham return; 21161e8e688SJim Ingham } 21261e8e688SJim Ingham 21361e8e688SJim Ingham void ThreadPlanStack::DiscardConsultingMasterPlans() { 21461e8e688SJim Ingham while (true) { 21561e8e688SJim Ingham int master_plan_idx; 21661e8e688SJim Ingham bool discard = true; 21761e8e688SJim Ingham 21861e8e688SJim Ingham // Find the first master plan, see if it wants discarding, and if yes 21961e8e688SJim Ingham // discard up to it. 22061e8e688SJim Ingham for (master_plan_idx = m_plans.size() - 1; master_plan_idx >= 0; 22161e8e688SJim Ingham master_plan_idx--) { 22261e8e688SJim Ingham if (m_plans[master_plan_idx]->IsMasterPlan()) { 22361e8e688SJim Ingham discard = m_plans[master_plan_idx]->OkayToDiscard(); 22461e8e688SJim Ingham break; 22561e8e688SJim Ingham } 22661e8e688SJim Ingham } 22761e8e688SJim Ingham 22861e8e688SJim Ingham // If the master plan doesn't want to get discarded, then we're done. 22961e8e688SJim Ingham if (!discard) 23061e8e688SJim Ingham return; 23161e8e688SJim Ingham 23261e8e688SJim Ingham // First pop all the dependent plans: 23361e8e688SJim Ingham for (int i = m_plans.size() - 1; i > master_plan_idx; i--) { 23461e8e688SJim Ingham DiscardPlan(); 23561e8e688SJim Ingham } 23661e8e688SJim Ingham 23761e8e688SJim Ingham // Now discard the master plan itself. 23861e8e688SJim Ingham // The bottom-most plan never gets discarded. "OkayToDiscard" for it 23961e8e688SJim Ingham // means discard it's dependent plans, but not it... 24061e8e688SJim Ingham if (master_plan_idx > 0) { 24161e8e688SJim Ingham DiscardPlan(); 24261e8e688SJim Ingham } 24361e8e688SJim Ingham } 24461e8e688SJim Ingham } 24561e8e688SJim Ingham 24661e8e688SJim Ingham lldb::ThreadPlanSP ThreadPlanStack::GetCurrentPlan() const { 24761e8e688SJim Ingham assert(m_plans.size() != 0 && "There will always be a base plan."); 24861e8e688SJim Ingham return m_plans.back(); 24961e8e688SJim Ingham } 25061e8e688SJim Ingham 25161e8e688SJim Ingham lldb::ThreadPlanSP ThreadPlanStack::GetCompletedPlan(bool skip_private) const { 25261e8e688SJim Ingham if (m_completed_plans.empty()) 25361e8e688SJim Ingham return {}; 25461e8e688SJim Ingham 25561e8e688SJim Ingham if (!skip_private) 25661e8e688SJim Ingham return m_completed_plans.back(); 25761e8e688SJim Ingham 25861e8e688SJim Ingham for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 25961e8e688SJim Ingham lldb::ThreadPlanSP completed_plan_sp; 26061e8e688SJim Ingham completed_plan_sp = m_completed_plans[i]; 26161e8e688SJim Ingham if (!completed_plan_sp->GetPrivate()) 26261e8e688SJim Ingham return completed_plan_sp; 26361e8e688SJim Ingham } 26461e8e688SJim Ingham return {}; 26561e8e688SJim Ingham } 26661e8e688SJim Ingham 26761e8e688SJim Ingham lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx, 26861e8e688SJim Ingham bool skip_private) const { 26961e8e688SJim Ingham uint32_t idx = 0; 27061e8e688SJim Ingham 27161e8e688SJim Ingham for (lldb::ThreadPlanSP plan_sp : m_plans) { 27261e8e688SJim Ingham if (skip_private && plan_sp->GetPrivate()) 27361e8e688SJim Ingham continue; 27461e8e688SJim Ingham if (idx == plan_idx) 27561e8e688SJim Ingham return plan_sp; 27661e8e688SJim Ingham idx++; 27761e8e688SJim Ingham } 27861e8e688SJim Ingham return {}; 27961e8e688SJim Ingham } 28061e8e688SJim Ingham 28161e8e688SJim Ingham lldb::ValueObjectSP ThreadPlanStack::GetReturnValueObject() const { 28261e8e688SJim Ingham if (m_completed_plans.empty()) 28361e8e688SJim Ingham return {}; 28461e8e688SJim Ingham 28561e8e688SJim Ingham for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 28661e8e688SJim Ingham lldb::ValueObjectSP return_valobj_sp; 28761e8e688SJim Ingham return_valobj_sp = m_completed_plans[i]->GetReturnValueObject(); 28861e8e688SJim Ingham if (return_valobj_sp) 28961e8e688SJim Ingham return return_valobj_sp; 29061e8e688SJim Ingham } 29161e8e688SJim Ingham return {}; 29261e8e688SJim Ingham } 29361e8e688SJim Ingham 29461e8e688SJim Ingham lldb::ExpressionVariableSP ThreadPlanStack::GetExpressionVariable() const { 29561e8e688SJim Ingham if (m_completed_plans.empty()) 29661e8e688SJim Ingham return {}; 29761e8e688SJim Ingham 29861e8e688SJim Ingham for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 29961e8e688SJim Ingham lldb::ExpressionVariableSP expression_variable_sp; 30061e8e688SJim Ingham expression_variable_sp = m_completed_plans[i]->GetExpressionVariable(); 30161e8e688SJim Ingham if (expression_variable_sp) 30261e8e688SJim Ingham return expression_variable_sp; 30361e8e688SJim Ingham } 30461e8e688SJim Ingham return {}; 30561e8e688SJim Ingham } 30661e8e688SJim Ingham bool ThreadPlanStack::AnyPlans() const { 30761e8e688SJim Ingham // There is always a base plan... 30861e8e688SJim Ingham return m_plans.size() > 1; 30961e8e688SJim Ingham } 31061e8e688SJim Ingham 31161e8e688SJim Ingham bool ThreadPlanStack::AnyCompletedPlans() const { 31261e8e688SJim Ingham return !m_completed_plans.empty(); 31361e8e688SJim Ingham } 31461e8e688SJim Ingham 31561e8e688SJim Ingham bool ThreadPlanStack::AnyDiscardedPlans() const { 31661e8e688SJim Ingham return !m_discarded_plans.empty(); 31761e8e688SJim Ingham } 31861e8e688SJim Ingham 31961e8e688SJim Ingham bool ThreadPlanStack::IsPlanDone(ThreadPlan *in_plan) const { 32061e8e688SJim Ingham for (auto plan : m_completed_plans) { 32161e8e688SJim Ingham if (plan.get() == in_plan) 32261e8e688SJim Ingham return true; 32361e8e688SJim Ingham } 32461e8e688SJim Ingham return false; 32561e8e688SJim Ingham } 32661e8e688SJim Ingham 32761e8e688SJim Ingham bool ThreadPlanStack::WasPlanDiscarded(ThreadPlan *in_plan) const { 32861e8e688SJim Ingham for (auto plan : m_discarded_plans) { 32961e8e688SJim Ingham if (plan.get() == in_plan) 33061e8e688SJim Ingham return true; 33161e8e688SJim Ingham } 33261e8e688SJim Ingham return false; 33361e8e688SJim Ingham } 33461e8e688SJim Ingham 33561e8e688SJim Ingham ThreadPlan *ThreadPlanStack::GetPreviousPlan(ThreadPlan *current_plan) const { 33661e8e688SJim Ingham if (current_plan == nullptr) 33761e8e688SJim Ingham return nullptr; 33861e8e688SJim Ingham 33961e8e688SJim Ingham // Look first in the completed plans, if the plan is here and there is 34061e8e688SJim Ingham // a completed plan above it, return that. 34161e8e688SJim Ingham int stack_size = m_completed_plans.size(); 34261e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) { 34361e8e688SJim Ingham if (current_plan == m_completed_plans[i].get()) 34461e8e688SJim Ingham return m_completed_plans[i - 1].get(); 34561e8e688SJim Ingham } 34661e8e688SJim Ingham 34761e8e688SJim Ingham // If this is the first completed plan, the previous one is the 34861e8e688SJim Ingham // bottom of the regular plan stack. 34961e8e688SJim Ingham if (stack_size > 0 && m_completed_plans[0].get() == current_plan) { 35061e8e688SJim Ingham return GetCurrentPlan().get(); 35161e8e688SJim Ingham } 35261e8e688SJim Ingham 35361e8e688SJim Ingham // Otherwise look for it in the regular plans. 35461e8e688SJim Ingham stack_size = m_plans.size(); 35561e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) { 35661e8e688SJim Ingham if (current_plan == m_plans[i].get()) 35761e8e688SJim Ingham return m_plans[i - 1].get(); 35861e8e688SJim Ingham } 35961e8e688SJim Ingham return nullptr; 36061e8e688SJim Ingham } 36161e8e688SJim Ingham 36261e8e688SJim Ingham ThreadPlan *ThreadPlanStack::GetInnermostExpression() const { 36361e8e688SJim Ingham int stack_size = m_plans.size(); 36461e8e688SJim Ingham 36561e8e688SJim Ingham for (int i = stack_size - 1; i > 0; i--) { 36661e8e688SJim Ingham if (m_plans[i]->GetKind() == ThreadPlan::eKindCallFunction) 36761e8e688SJim Ingham return m_plans[i].get(); 36861e8e688SJim Ingham } 36961e8e688SJim Ingham return nullptr; 37061e8e688SJim Ingham } 37161e8e688SJim Ingham 37261e8e688SJim Ingham void ThreadPlanStack::WillResume() { 37361e8e688SJim Ingham m_completed_plans.clear(); 37461e8e688SJim Ingham m_discarded_plans.clear(); 37561e8e688SJim Ingham } 37661e8e688SJim Ingham 37761e8e688SJim Ingham const ThreadPlanStack::PlanStack & 37861e8e688SJim Ingham ThreadPlanStack::GetStackOfKind(ThreadPlanStack::StackKind kind) const { 37961e8e688SJim Ingham switch (kind) { 38061e8e688SJim Ingham case ePlans: 38161e8e688SJim Ingham return m_plans; 38261e8e688SJim Ingham case eCompletedPlans: 38361e8e688SJim Ingham return m_completed_plans; 38461e8e688SJim Ingham case eDiscardedPlans: 38561e8e688SJim Ingham return m_discarded_plans; 38661e8e688SJim Ingham } 38761e8e688SJim Ingham llvm_unreachable("Invalid StackKind value"); 38861e8e688SJim Ingham } 3891893065dSJim Ingham 3901893065dSJim Ingham void ThreadPlanStackMap::Update(ThreadList ¤t_threads, 3911893065dSJim Ingham bool delete_missing, 3921893065dSJim Ingham bool check_for_new) { 3931893065dSJim Ingham 3941893065dSJim Ingham // Now find all the new threads and add them to the map: 3951893065dSJim Ingham if (check_for_new) { 3961893065dSJim Ingham for (auto thread : current_threads.Threads()) { 3971893065dSJim Ingham lldb::tid_t cur_tid = thread->GetID(); 3981893065dSJim Ingham if (!Find(cur_tid)) { 3991893065dSJim Ingham AddThread(*thread.get()); 4001893065dSJim Ingham thread->QueueFundamentalPlan(true); 4011893065dSJim Ingham } 4021893065dSJim Ingham } 4031893065dSJim Ingham } 4041893065dSJim Ingham 4051893065dSJim Ingham // If we aren't reaping missing threads at this point, 4061893065dSJim Ingham // we are done. 4071893065dSJim Ingham if (!delete_missing) 4081893065dSJim Ingham return; 4091893065dSJim Ingham // Otherwise scan for absent TID's. 4101893065dSJim Ingham std::vector<lldb::tid_t> missing_threads; 4111893065dSJim Ingham // If we are going to delete plans from the plan stack, 4121893065dSJim Ingham // then scan for absent TID's: 4131893065dSJim Ingham for (auto thread_plans : m_plans_list) { 4141893065dSJim Ingham lldb::tid_t cur_tid = thread_plans.first; 4151893065dSJim Ingham ThreadSP thread_sp = current_threads.FindThreadByID(cur_tid); 4161893065dSJim Ingham if (!thread_sp) 4171893065dSJim Ingham missing_threads.push_back(cur_tid); 4181893065dSJim Ingham } 4191893065dSJim Ingham for (lldb::tid_t tid : missing_threads) { 4201893065dSJim Ingham RemoveTID(tid); 4211893065dSJim Ingham } 4221893065dSJim Ingham } 4231893065dSJim Ingham 4241893065dSJim Ingham void ThreadPlanStackMap::DumpPlans(Stream &strm, 4251893065dSJim Ingham lldb::DescriptionLevel desc_level, 4261893065dSJim Ingham bool internal, bool condense_if_trivial, 4271893065dSJim Ingham bool skip_unreported) { 4281893065dSJim Ingham for (auto elem : m_plans_list) { 4291893065dSJim Ingham lldb::tid_t tid = elem.first; 4301893065dSJim Ingham uint32_t index_id = 0; 4311893065dSJim Ingham ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); 4321893065dSJim Ingham 4331893065dSJim Ingham if (skip_unreported) { 4341893065dSJim Ingham if (!thread_sp) 4351893065dSJim Ingham continue; 4361893065dSJim Ingham } 4371893065dSJim Ingham if (thread_sp) 4381893065dSJim Ingham index_id = thread_sp->GetIndexID(); 4391893065dSJim Ingham 4401893065dSJim Ingham if (condense_if_trivial) { 4411893065dSJim Ingham if (!elem.second.AnyPlans() && !elem.second.AnyCompletedPlans() && 4421893065dSJim Ingham !elem.second.AnyDiscardedPlans()) { 4431893065dSJim Ingham strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid); 4441893065dSJim Ingham strm.IndentMore(); 4451893065dSJim Ingham strm.Indent(); 4461893065dSJim Ingham strm.Printf("No active thread plans\n"); 4471893065dSJim Ingham strm.IndentLess(); 4481893065dSJim Ingham return; 4491893065dSJim Ingham } 4501893065dSJim Ingham } 4511893065dSJim Ingham 4521893065dSJim Ingham strm.Indent(); 4531893065dSJim Ingham strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid); 4541893065dSJim Ingham 4551893065dSJim Ingham elem.second.DumpThreadPlans(strm, desc_level, internal); 4561893065dSJim Ingham } 4571893065dSJim Ingham } 4581893065dSJim Ingham 4591893065dSJim Ingham bool ThreadPlanStackMap::DumpPlansForTID(Stream &strm, lldb::tid_t tid, 4601893065dSJim Ingham lldb::DescriptionLevel desc_level, 4611893065dSJim Ingham bool internal, 4621893065dSJim Ingham bool condense_if_trivial, 4631893065dSJim Ingham bool skip_unreported) { 4641893065dSJim Ingham uint32_t index_id = 0; 4651893065dSJim Ingham ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); 4661893065dSJim Ingham 4671893065dSJim Ingham if (skip_unreported) { 4681893065dSJim Ingham if (!thread_sp) { 4691893065dSJim Ingham strm.Format("Unknown TID: {0}", tid); 4701893065dSJim Ingham return false; 4711893065dSJim Ingham } 4721893065dSJim Ingham } 4731893065dSJim Ingham 4741893065dSJim Ingham if (thread_sp) 4751893065dSJim Ingham index_id = thread_sp->GetIndexID(); 4761893065dSJim Ingham ThreadPlanStack *stack = Find(tid); 4771893065dSJim Ingham if (!stack) { 4781893065dSJim Ingham strm.Format("Unknown TID: {0}\n", tid); 4791893065dSJim Ingham return false; 4801893065dSJim Ingham } 4811893065dSJim Ingham 4821893065dSJim Ingham if (condense_if_trivial) { 4831893065dSJim Ingham if (!stack->AnyPlans() && !stack->AnyCompletedPlans() && 4841893065dSJim Ingham !stack->AnyDiscardedPlans()) { 4851893065dSJim Ingham strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid); 4861893065dSJim Ingham strm.IndentMore(); 4871893065dSJim Ingham strm.Indent(); 4881893065dSJim Ingham strm.Printf("No active thread plans\n"); 4891893065dSJim Ingham strm.IndentLess(); 4901893065dSJim Ingham return true; 4911893065dSJim Ingham } 4921893065dSJim Ingham } 4931893065dSJim Ingham 4941893065dSJim Ingham strm.Indent(); 4951893065dSJim Ingham strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid); 4961893065dSJim Ingham 4971893065dSJim Ingham stack->DumpThreadPlans(strm, desc_level, internal); 4981893065dSJim Ingham return true; 4991893065dSJim Ingham } 5001893065dSJim Ingham 5011893065dSJim Ingham bool ThreadPlanStackMap::PrunePlansForTID(lldb::tid_t tid) { 5021893065dSJim Ingham // We only remove the plans for unreported TID's. 5031893065dSJim Ingham ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); 5041893065dSJim Ingham if (thread_sp) 5051893065dSJim Ingham return false; 5061893065dSJim Ingham 5071893065dSJim Ingham return RemoveTID(tid); 5081893065dSJim Ingham } 509