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