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