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 ThreadPlanStack::ThreadPlanStack(const Thread &thread, bool make_null) { 31 if (make_null) { 32 // The ThreadPlanNull doesn't do anything to the Thread, so this is actually 33 // still a const operation. 34 m_plans.push_back( 35 ThreadPlanSP(new ThreadPlanNull(const_cast<Thread &>(thread)))); 36 } 37 } 38 39 void ThreadPlanStack::DumpThreadPlans(Stream &s, 40 lldb::DescriptionLevel desc_level, 41 bool include_internal) const { 42 43 uint32_t stack_size; 44 45 s.IndentMore(); 46 PrintOneStack(s, "Active plan stack", m_plans, desc_level, include_internal); 47 PrintOneStack(s, "Completed plan stack", m_completed_plans, desc_level, 48 include_internal); 49 PrintOneStack(s, "Discarded plan stack", m_discarded_plans, desc_level, 50 include_internal); 51 s.IndentLess(); 52 } 53 54 void ThreadPlanStack::PrintOneStack(Stream &s, llvm::StringRef stack_name, 55 const PlanStack &stack, 56 lldb::DescriptionLevel desc_level, 57 bool include_internal) const { 58 // If the stack is empty, just exit: 59 if (stack.empty()) 60 return; 61 62 // Make sure there are public completed plans: 63 bool any_public = false; 64 if (!include_internal) { 65 for (auto plan : stack) { 66 if (!plan->GetPrivate()) { 67 any_public = true; 68 break; 69 } 70 } 71 } 72 73 if (include_internal || any_public) { 74 int print_idx = 0; 75 s.Indent(); 76 s.Printf("%s:\n", stack_name); 77 for (auto plan : stack) { 78 if (!include_internal && plan->GetPrivate()) 79 continue; 80 PrintPlanElement(s, plan, desc_level, print_idx++); 81 } 82 } 83 } 84 85 size_t ThreadPlanStack::CheckpointCompletedPlans() { 86 m_completed_plan_checkpoint++; 87 m_completed_plan_store.insert( 88 std::make_pair(m_completed_plan_checkpoint, m_completed_plans)); 89 return m_completed_plan_checkpoint; 90 } 91 92 void ThreadPlanStack::RestoreCompletedPlanCheckpoint(size_t checkpoint) { 93 auto result = m_completed_plan_store.find(checkpoint); 94 assert(result != m_completed_plan_store.end() && 95 "Asked for a checkpoint that didn't exist"); 96 m_completed_plans.swap((*result).second); 97 m_completed_plan_store.erase(result); 98 } 99 100 void ThreadPlanStack::DiscardCompletedPlanCheckpoint(size_t checkpoint) { 101 m_completed_plan_store.erase(checkpoint); 102 } 103 104 void ThreadPlanStack::ThreadDestroyed(Thread *thread) { 105 // Tell the plan stacks that this thread is going away: 106 for (ThreadPlanSP plan : m_plans) 107 plan->ThreadDestroyed(); 108 109 for (ThreadPlanSP plan : m_discarded_plans) 110 plan->ThreadDestroyed(); 111 112 for (ThreadPlanSP plan : m_completed_plans) 113 plan->ThreadDestroyed(); 114 115 // Now clear the current plan stacks: 116 m_plans.clear(); 117 m_discarded_plans.clear(); 118 m_completed_plans.clear(); 119 120 // Push a ThreadPlanNull on the plan stack. That way we can continue 121 // assuming that the plan stack is never empty, but if somebody errantly asks 122 // questions of a destroyed thread without checking first whether it is 123 // destroyed, they won't crash. 124 if (thread != nullptr) { 125 lldb::ThreadPlanSP null_plan_sp(new ThreadPlanNull(*thread)); 126 m_plans.push_back(null_plan_sp); 127 } 128 } 129 130 void ThreadPlanStack::EnableTracer(bool value, bool single_stepping) { 131 for (ThreadPlanSP plan : m_plans) { 132 if (plan->GetThreadPlanTracer()) { 133 plan->GetThreadPlanTracer()->EnableTracing(value); 134 plan->GetThreadPlanTracer()->EnableSingleStep(single_stepping); 135 } 136 } 137 } 138 139 void ThreadPlanStack::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) { 140 for (ThreadPlanSP plan : m_plans) 141 plan->SetThreadPlanTracer(tracer_sp); 142 } 143 144 void ThreadPlanStack::PushPlan(lldb::ThreadPlanSP new_plan_sp) { 145 // If the thread plan doesn't already have a tracer, give it its parent's 146 // tracer: 147 // The first plan has to be a base plan: 148 assert(m_plans.size() > 0 || 149 new_plan_sp->IsBasePlan() && "Zeroth plan must be a base plan"); 150 151 if (!new_plan_sp->GetThreadPlanTracer()) { 152 assert(!m_plans.empty()); 153 new_plan_sp->SetThreadPlanTracer(m_plans.back()->GetThreadPlanTracer()); 154 } 155 m_plans.push_back(new_plan_sp); 156 new_plan_sp->DidPush(); 157 } 158 159 lldb::ThreadPlanSP ThreadPlanStack::PopPlan() { 160 assert(m_plans.size() > 1 && "Can't pop the base thread plan"); 161 162 lldb::ThreadPlanSP &plan_sp = m_plans.back(); 163 m_completed_plans.push_back(plan_sp); 164 plan_sp->WillPop(); 165 m_plans.pop_back(); 166 return plan_sp; 167 } 168 169 lldb::ThreadPlanSP ThreadPlanStack::DiscardPlan() { 170 assert(m_plans.size() > 1 && "Can't discard the base thread plan"); 171 172 lldb::ThreadPlanSP &plan_sp = m_plans.back(); 173 m_discarded_plans.push_back(plan_sp); 174 plan_sp->WillPop(); 175 m_plans.pop_back(); 176 return plan_sp; 177 } 178 179 // If the input plan is nullptr, discard all plans. Otherwise make sure this 180 // plan is in the stack, and if so discard up to and including it. 181 void ThreadPlanStack::DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr) { 182 int stack_size = m_plans.size(); 183 184 if (up_to_plan_ptr == nullptr) { 185 for (int i = stack_size - 1; i > 0; i--) 186 DiscardPlan(); 187 return; 188 } 189 190 bool found_it = false; 191 for (int i = stack_size - 1; i > 0; i--) { 192 if (m_plans[i].get() == up_to_plan_ptr) { 193 found_it = true; 194 break; 195 } 196 } 197 198 if (found_it) { 199 bool last_one = false; 200 for (int i = stack_size - 1; i > 0 && !last_one; i--) { 201 if (GetCurrentPlan().get() == up_to_plan_ptr) 202 last_one = true; 203 DiscardPlan(); 204 } 205 } 206 } 207 208 void ThreadPlanStack::DiscardAllPlans() { 209 int stack_size = m_plans.size(); 210 for (int i = stack_size - 1; i > 0; i--) { 211 DiscardPlan(); 212 } 213 return; 214 } 215 216 void ThreadPlanStack::DiscardConsultingMasterPlans() { 217 while (true) { 218 int master_plan_idx; 219 bool discard = true; 220 221 // Find the first master plan, see if it wants discarding, and if yes 222 // discard up to it. 223 for (master_plan_idx = m_plans.size() - 1; master_plan_idx >= 0; 224 master_plan_idx--) { 225 if (m_plans[master_plan_idx]->IsMasterPlan()) { 226 discard = m_plans[master_plan_idx]->OkayToDiscard(); 227 break; 228 } 229 } 230 231 // If the master plan doesn't want to get discarded, then we're done. 232 if (!discard) 233 return; 234 235 // First pop all the dependent plans: 236 for (int i = m_plans.size() - 1; i > master_plan_idx; i--) { 237 DiscardPlan(); 238 } 239 240 // Now discard the master plan itself. 241 // The bottom-most plan never gets discarded. "OkayToDiscard" for it 242 // means discard it's dependent plans, but not it... 243 if (master_plan_idx > 0) { 244 DiscardPlan(); 245 } 246 } 247 } 248 249 lldb::ThreadPlanSP ThreadPlanStack::GetCurrentPlan() const { 250 assert(m_plans.size() != 0 && "There will always be a base plan."); 251 return m_plans.back(); 252 } 253 254 lldb::ThreadPlanSP ThreadPlanStack::GetCompletedPlan(bool skip_private) const { 255 if (m_completed_plans.empty()) 256 return {}; 257 258 if (!skip_private) 259 return m_completed_plans.back(); 260 261 for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 262 lldb::ThreadPlanSP completed_plan_sp; 263 completed_plan_sp = m_completed_plans[i]; 264 if (!completed_plan_sp->GetPrivate()) 265 return completed_plan_sp; 266 } 267 return {}; 268 } 269 270 lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx, 271 bool skip_private) const { 272 uint32_t idx = 0; 273 ThreadPlan *up_to_plan_ptr = nullptr; 274 275 for (lldb::ThreadPlanSP plan_sp : m_plans) { 276 if (skip_private && plan_sp->GetPrivate()) 277 continue; 278 if (idx == plan_idx) 279 return plan_sp; 280 idx++; 281 } 282 return {}; 283 } 284 285 lldb::ValueObjectSP ThreadPlanStack::GetReturnValueObject() const { 286 if (m_completed_plans.empty()) 287 return {}; 288 289 for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 290 lldb::ValueObjectSP return_valobj_sp; 291 return_valobj_sp = m_completed_plans[i]->GetReturnValueObject(); 292 if (return_valobj_sp) 293 return return_valobj_sp; 294 } 295 return {}; 296 } 297 298 lldb::ExpressionVariableSP ThreadPlanStack::GetExpressionVariable() const { 299 if (m_completed_plans.empty()) 300 return {}; 301 302 for (int i = m_completed_plans.size() - 1; i >= 0; i--) { 303 lldb::ExpressionVariableSP expression_variable_sp; 304 expression_variable_sp = m_completed_plans[i]->GetExpressionVariable(); 305 if (expression_variable_sp) 306 return expression_variable_sp; 307 } 308 return {}; 309 } 310 bool ThreadPlanStack::AnyPlans() const { 311 // There is always a base plan... 312 return m_plans.size() > 1; 313 } 314 315 bool ThreadPlanStack::AnyCompletedPlans() const { 316 return !m_completed_plans.empty(); 317 } 318 319 bool ThreadPlanStack::AnyDiscardedPlans() const { 320 return !m_discarded_plans.empty(); 321 } 322 323 bool ThreadPlanStack::IsPlanDone(ThreadPlan *in_plan) const { 324 for (auto plan : m_completed_plans) { 325 if (plan.get() == in_plan) 326 return true; 327 } 328 return false; 329 } 330 331 bool ThreadPlanStack::WasPlanDiscarded(ThreadPlan *in_plan) const { 332 for (auto plan : m_discarded_plans) { 333 if (plan.get() == in_plan) 334 return true; 335 } 336 return false; 337 } 338 339 ThreadPlan *ThreadPlanStack::GetPreviousPlan(ThreadPlan *current_plan) const { 340 if (current_plan == nullptr) 341 return nullptr; 342 343 // Look first in the completed plans, if the plan is here and there is 344 // a completed plan above it, return that. 345 int stack_size = m_completed_plans.size(); 346 for (int i = stack_size - 1; i > 0; i--) { 347 if (current_plan == m_completed_plans[i].get()) 348 return m_completed_plans[i - 1].get(); 349 } 350 351 // If this is the first completed plan, the previous one is the 352 // bottom of the regular plan stack. 353 if (stack_size > 0 && m_completed_plans[0].get() == current_plan) { 354 return GetCurrentPlan().get(); 355 } 356 357 // Otherwise look for it in the regular plans. 358 stack_size = m_plans.size(); 359 for (int i = stack_size - 1; i > 0; i--) { 360 if (current_plan == m_plans[i].get()) 361 return m_plans[i - 1].get(); 362 } 363 return nullptr; 364 } 365 366 ThreadPlan *ThreadPlanStack::GetInnermostExpression() const { 367 int stack_size = m_plans.size(); 368 369 for (int i = stack_size - 1; i > 0; i--) { 370 if (m_plans[i]->GetKind() == ThreadPlan::eKindCallFunction) 371 return m_plans[i].get(); 372 } 373 return nullptr; 374 } 375 376 void ThreadPlanStack::WillResume() { 377 m_completed_plans.clear(); 378 m_discarded_plans.clear(); 379 } 380 381 const ThreadPlanStack::PlanStack & 382 ThreadPlanStack::GetStackOfKind(ThreadPlanStack::StackKind kind) const { 383 switch (kind) { 384 case ePlans: 385 return m_plans; 386 case eCompletedPlans: 387 return m_completed_plans; 388 case eDiscardedPlans: 389 return m_discarded_plans; 390 } 391 llvm_unreachable("Invalid StackKind value"); 392 } 393 394 void ThreadPlanStackMap::Update(ThreadList ¤t_threads, 395 bool delete_missing, 396 bool check_for_new) { 397 398 // Now find all the new threads and add them to the map: 399 if (check_for_new) { 400 for (auto thread : current_threads.Threads()) { 401 lldb::tid_t cur_tid = thread->GetID(); 402 if (!Find(cur_tid)) { 403 AddThread(*thread.get()); 404 thread->QueueFundamentalPlan(true); 405 } 406 } 407 } 408 409 // If we aren't reaping missing threads at this point, 410 // we are done. 411 if (!delete_missing) 412 return; 413 // Otherwise scan for absent TID's. 414 std::vector<lldb::tid_t> missing_threads; 415 // If we are going to delete plans from the plan stack, 416 // then scan for absent TID's: 417 for (auto thread_plans : m_plans_list) { 418 lldb::tid_t cur_tid = thread_plans.first; 419 ThreadSP thread_sp = current_threads.FindThreadByID(cur_tid); 420 if (!thread_sp) 421 missing_threads.push_back(cur_tid); 422 } 423 for (lldb::tid_t tid : missing_threads) { 424 RemoveTID(tid); 425 } 426 } 427 428 void ThreadPlanStackMap::DumpPlans(Stream &strm, 429 lldb::DescriptionLevel desc_level, 430 bool internal, bool condense_if_trivial, 431 bool skip_unreported) { 432 for (auto elem : m_plans_list) { 433 lldb::tid_t tid = elem.first; 434 uint32_t index_id = 0; 435 ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); 436 437 if (skip_unreported) { 438 if (!thread_sp) 439 continue; 440 } 441 if (thread_sp) 442 index_id = thread_sp->GetIndexID(); 443 444 if (condense_if_trivial) { 445 if (!elem.second.AnyPlans() && !elem.second.AnyCompletedPlans() && 446 !elem.second.AnyDiscardedPlans()) { 447 strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid); 448 strm.IndentMore(); 449 strm.Indent(); 450 strm.Printf("No active thread plans\n"); 451 strm.IndentLess(); 452 return; 453 } 454 } 455 456 strm.Indent(); 457 strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid); 458 459 elem.second.DumpThreadPlans(strm, desc_level, internal); 460 } 461 } 462 463 bool ThreadPlanStackMap::DumpPlansForTID(Stream &strm, lldb::tid_t tid, 464 lldb::DescriptionLevel desc_level, 465 bool internal, 466 bool condense_if_trivial, 467 bool skip_unreported) { 468 uint32_t index_id = 0; 469 ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); 470 471 if (skip_unreported) { 472 if (!thread_sp) { 473 strm.Format("Unknown TID: {0}", tid); 474 return false; 475 } 476 } 477 478 if (thread_sp) 479 index_id = thread_sp->GetIndexID(); 480 ThreadPlanStack *stack = Find(tid); 481 if (!stack) { 482 strm.Format("Unknown TID: {0}\n", tid); 483 return false; 484 } 485 486 if (condense_if_trivial) { 487 if (!stack->AnyPlans() && !stack->AnyCompletedPlans() && 488 !stack->AnyDiscardedPlans()) { 489 strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid); 490 strm.IndentMore(); 491 strm.Indent(); 492 strm.Printf("No active thread plans\n"); 493 strm.IndentLess(); 494 return true; 495 } 496 } 497 498 strm.Indent(); 499 strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid); 500 501 stack->DumpThreadPlans(strm, desc_level, internal); 502 return true; 503 } 504 505 bool ThreadPlanStackMap::PrunePlansForTID(lldb::tid_t tid) { 506 // We only remove the plans for unreported TID's. 507 ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); 508 if (thread_sp) 509 return false; 510 511 return RemoveTID(tid); 512 } 513