1 //===-- ThreadPlanStepRange.cpp -------------------------------------------===// 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/ThreadPlanStepRange.h" 10 #include "lldb/Breakpoint/BreakpointLocation.h" 11 #include "lldb/Breakpoint/BreakpointSite.h" 12 #include "lldb/Core/Disassembler.h" 13 #include "lldb/Symbol/Function.h" 14 #include "lldb/Symbol/Symbol.h" 15 #include "lldb/Target/ExecutionContext.h" 16 #include "lldb/Target/Process.h" 17 #include "lldb/Target/RegisterContext.h" 18 #include "lldb/Target/StopInfo.h" 19 #include "lldb/Target/Target.h" 20 #include "lldb/Target/Thread.h" 21 #include "lldb/Target/ThreadPlanRunToAddress.h" 22 #include "lldb/Utility/LLDBLog.h" 23 #include "lldb/Utility/Log.h" 24 #include "lldb/Utility/Stream.h" 25 26 using namespace lldb; 27 using namespace lldb_private; 28 29 // ThreadPlanStepRange: Step through a stack range, either stepping over or 30 // into based on the value of \a type. 31 32 ThreadPlanStepRange::ThreadPlanStepRange(ThreadPlanKind kind, const char *name, 33 Thread &thread, 34 const AddressRange &range, 35 const SymbolContext &addr_context, 36 lldb::RunMode stop_others, 37 bool given_ranges_only) 38 : ThreadPlan(kind, name, thread, eVoteNoOpinion, eVoteNoOpinion), 39 m_addr_context(addr_context), m_address_ranges(), 40 m_stop_others(stop_others), m_stack_id(), m_parent_stack_id(), 41 m_no_more_plans(false), m_first_run_event(true), m_use_fast_step(false), 42 m_given_ranges_only(given_ranges_only) { 43 m_use_fast_step = GetTarget().GetUseFastStepping(); 44 AddRange(range); 45 m_stack_id = thread.GetStackFrameAtIndex(0)->GetStackID(); 46 StackFrameSP parent_stack = thread.GetStackFrameAtIndex(1); 47 if (parent_stack) 48 m_parent_stack_id = parent_stack->GetStackID(); 49 } 50 51 ThreadPlanStepRange::~ThreadPlanStepRange() { ClearNextBranchBreakpoint(); } 52 53 void ThreadPlanStepRange::DidPush() { 54 // See if we can find a "next range" breakpoint: 55 SetNextBranchBreakpoint(); 56 } 57 58 bool ThreadPlanStepRange::ValidatePlan(Stream *error) { 59 if (m_could_not_resolve_hw_bp) { 60 if (error) 61 error->PutCString( 62 "Could not create hardware breakpoint for thread plan."); 63 return false; 64 } 65 return true; 66 } 67 68 Vote ThreadPlanStepRange::ShouldReportStop(Event *event_ptr) { 69 Log *log = GetLog(LLDBLog::Step); 70 71 const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo; 72 LLDB_LOGF(log, "ThreadPlanStepRange::ShouldReportStop() returning vote %i\n", 73 vote); 74 return vote; 75 } 76 77 void ThreadPlanStepRange::AddRange(const AddressRange &new_range) { 78 // For now I'm just adding the ranges. At some point we may want to condense 79 // the ranges if they overlap, though I don't think it is likely to be very 80 // important. 81 m_address_ranges.push_back(new_range); 82 83 // Fill the slot for this address range with an empty DisassemblerSP in the 84 // instruction ranges. I want the indices to match, but I don't want to do 85 // the work to disassemble this range if I don't step into it. 86 m_instruction_ranges.push_back(DisassemblerSP()); 87 } 88 89 void ThreadPlanStepRange::DumpRanges(Stream *s) { 90 size_t num_ranges = m_address_ranges.size(); 91 if (num_ranges == 1) { 92 m_address_ranges[0].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress); 93 } else { 94 for (size_t i = 0; i < num_ranges; i++) { 95 s->Printf(" %" PRIu64 ": ", uint64_t(i)); 96 m_address_ranges[i].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress); 97 } 98 } 99 } 100 101 bool ThreadPlanStepRange::InRange() { 102 Log *log = GetLog(LLDBLog::Step); 103 bool ret_value = false; 104 Thread &thread = GetThread(); 105 lldb::addr_t pc_load_addr = thread.GetRegisterContext()->GetPC(); 106 107 size_t num_ranges = m_address_ranges.size(); 108 for (size_t i = 0; i < num_ranges; i++) { 109 ret_value = 110 m_address_ranges[i].ContainsLoadAddress(pc_load_addr, &GetTarget()); 111 if (ret_value) 112 break; 113 } 114 115 if (!ret_value && !m_given_ranges_only) { 116 // See if we've just stepped to another part of the same line number... 117 StackFrame *frame = thread.GetStackFrameAtIndex(0).get(); 118 119 SymbolContext new_context( 120 frame->GetSymbolContext(eSymbolContextEverything)); 121 if (m_addr_context.line_entry.IsValid() && 122 new_context.line_entry.IsValid()) { 123 if (m_addr_context.line_entry.original_file_sp->Equal( 124 *new_context.line_entry.original_file_sp, 125 SupportFile::eEqualFileSpecAndChecksumIfSet)) { 126 if (m_addr_context.line_entry.line == new_context.line_entry.line) { 127 m_addr_context = new_context; 128 const bool include_inlined_functions = 129 GetKind() == eKindStepOverRange; 130 AddRange(m_addr_context.line_entry.GetSameLineContiguousAddressRange( 131 include_inlined_functions)); 132 ret_value = true; 133 if (log) { 134 StreamString s; 135 m_addr_context.line_entry.Dump(&s, &GetTarget(), true, 136 Address::DumpStyleLoadAddress, 137 Address::DumpStyleLoadAddress, true); 138 139 LLDB_LOGF( 140 log, 141 "Step range plan stepped to another range of same line: %s", 142 s.GetData()); 143 } 144 } else if (new_context.line_entry.line == 0) { 145 new_context.line_entry.line = m_addr_context.line_entry.line; 146 m_addr_context = new_context; 147 const bool include_inlined_functions = 148 GetKind() == eKindStepOverRange; 149 AddRange(m_addr_context.line_entry.GetSameLineContiguousAddressRange( 150 include_inlined_functions)); 151 ret_value = true; 152 if (log) { 153 StreamString s; 154 m_addr_context.line_entry.Dump(&s, &GetTarget(), true, 155 Address::DumpStyleLoadAddress, 156 Address::DumpStyleLoadAddress, true); 157 158 LLDB_LOGF(log, 159 "Step range plan stepped to a range at linenumber 0 " 160 "stepping through that range: %s", 161 s.GetData()); 162 } 163 } else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress( 164 &GetTarget()) != pc_load_addr) { 165 // Another thing that sometimes happens here is that we step out of 166 // one line into the MIDDLE of another line. So far I mostly see 167 // this due to bugs in the debug information. But we probably don't 168 // want to be in the middle of a line range, so in that case reset 169 // the stepping range to the line we've stepped into the middle of 170 // and continue. 171 m_addr_context = new_context; 172 m_address_ranges.clear(); 173 AddRange(m_addr_context.line_entry.range); 174 ret_value = true; 175 if (log) { 176 StreamString s; 177 m_addr_context.line_entry.Dump(&s, &GetTarget(), true, 178 Address::DumpStyleLoadAddress, 179 Address::DumpStyleLoadAddress, true); 180 181 LLDB_LOGF(log, 182 "Step range plan stepped to the middle of new " 183 "line(%d): %s, continuing to clear this line.", 184 new_context.line_entry.line, s.GetData()); 185 } 186 } 187 } 188 } 189 } 190 191 if (!ret_value && log) 192 LLDB_LOGF(log, "Step range plan out of range to 0x%" PRIx64, pc_load_addr); 193 194 return ret_value; 195 } 196 197 bool ThreadPlanStepRange::InSymbol() { 198 lldb::addr_t cur_pc = GetThread().GetRegisterContext()->GetPC(); 199 if (m_addr_context.function != nullptr) { 200 return m_addr_context.function->GetAddressRange().ContainsLoadAddress( 201 cur_pc, &GetTarget()); 202 } else if (m_addr_context.symbol && m_addr_context.symbol->ValueIsAddress()) { 203 AddressRange range(m_addr_context.symbol->GetAddressRef(), 204 m_addr_context.symbol->GetByteSize()); 205 return range.ContainsLoadAddress(cur_pc, &GetTarget()); 206 } 207 return false; 208 } 209 210 // FIXME: This should also handle inlining if we aren't going to do inlining in 211 // the 212 // main stack. 213 // 214 // Ideally we should remember the whole stack frame list, and then compare that 215 // to the current list. 216 217 lldb::FrameComparison ThreadPlanStepRange::CompareCurrentFrameToStartFrame() { 218 FrameComparison frame_order; 219 Thread &thread = GetThread(); 220 StackID cur_frame_id = thread.GetStackFrameAtIndex(0)->GetStackID(); 221 222 if (cur_frame_id == m_stack_id) { 223 frame_order = eFrameCompareEqual; 224 } else if (cur_frame_id < m_stack_id) { 225 frame_order = eFrameCompareYounger; 226 } else { 227 StackFrameSP cur_parent_frame = thread.GetStackFrameAtIndex(1); 228 StackID cur_parent_id; 229 if (cur_parent_frame) 230 cur_parent_id = cur_parent_frame->GetStackID(); 231 if (m_parent_stack_id.IsValid() && cur_parent_id.IsValid() && 232 m_parent_stack_id == cur_parent_id) 233 frame_order = eFrameCompareSameParent; 234 else 235 frame_order = eFrameCompareOlder; 236 } 237 return frame_order; 238 } 239 240 bool ThreadPlanStepRange::StopOthers() { 241 switch (m_stop_others) { 242 case lldb::eOnlyThisThread: 243 return true; 244 case lldb::eOnlyDuringStepping: 245 // If there is a call in the range of the next branch breakpoint, 246 // then we should always run all threads, since a call can execute 247 // arbitrary code which might for instance take a lock that's held 248 // by another thread. 249 return !m_found_calls; 250 case lldb::eAllThreads: 251 return false; 252 } 253 llvm_unreachable("Unhandled run mode!"); 254 } 255 256 InstructionList *ThreadPlanStepRange::GetInstructionsForAddress( 257 lldb::addr_t addr, size_t &range_index, size_t &insn_offset) { 258 size_t num_ranges = m_address_ranges.size(); 259 for (size_t i = 0; i < num_ranges; i++) { 260 if (m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget())) { 261 // Some joker added a zero size range to the stepping range... 262 if (m_address_ranges[i].GetByteSize() == 0) 263 return nullptr; 264 265 if (!m_instruction_ranges[i]) { 266 // Disassemble the address range given: 267 const char *plugin_name = nullptr; 268 const char *flavor = nullptr; 269 const char *cpu = nullptr; 270 const char *features = nullptr; 271 m_instruction_ranges[i] = Disassembler::DisassembleRange( 272 GetTarget().GetArchitecture(), plugin_name, flavor, cpu, features, 273 GetTarget(), m_address_ranges[i]); 274 } 275 if (!m_instruction_ranges[i]) 276 return nullptr; 277 else { 278 // Find where we are in the instruction list as well. If we aren't at 279 // an instruction, return nullptr. In this case, we're probably lost, 280 // and shouldn't try to do anything fancy. 281 282 insn_offset = 283 m_instruction_ranges[i] 284 ->GetInstructionList() 285 .GetIndexOfInstructionAtLoadAddress(addr, GetTarget()); 286 if (insn_offset == UINT32_MAX) 287 return nullptr; 288 else { 289 range_index = i; 290 return &m_instruction_ranges[i]->GetInstructionList(); 291 } 292 } 293 } 294 } 295 return nullptr; 296 } 297 298 bool ThreadPlanStepRange::IsNextBranchBreakpointStop(StopInfoSP stop_info_sp) { 299 if (!m_next_branch_bp_sp) 300 return false; 301 302 break_id_t bp_site_id = stop_info_sp->GetValue(); 303 BreakpointSiteSP bp_site_sp = 304 m_process.GetBreakpointSiteList().FindByID(bp_site_id); 305 if (!bp_site_sp) 306 return false; 307 else if (!bp_site_sp->IsBreakpointAtThisSite(m_next_branch_bp_sp->GetID())) 308 return false; 309 return true; 310 } 311 312 void ThreadPlanStepRange::ClearNextBranchBreakpoint() { 313 if (m_next_branch_bp_sp) { 314 Log *log = GetLog(LLDBLog::Step); 315 LLDB_LOGF(log, "Removing next branch breakpoint: %d.", 316 m_next_branch_bp_sp->GetID()); 317 GetTarget().RemoveBreakpointByID(m_next_branch_bp_sp->GetID()); 318 m_next_branch_bp_sp.reset(); 319 m_could_not_resolve_hw_bp = false; 320 m_found_calls = false; 321 } 322 } 323 324 void ThreadPlanStepRange::ClearNextBranchBreakpointExplainedStop() { 325 if (IsNextBranchBreakpointStop(GetPrivateStopInfo())) 326 ClearNextBranchBreakpoint(); 327 } 328 329 bool ThreadPlanStepRange::SetNextBranchBreakpoint() { 330 if (m_next_branch_bp_sp) 331 return true; 332 333 Log *log = GetLog(LLDBLog::Step); 334 // Stepping through ranges using breakpoints doesn't work yet, but with this 335 // off we fall back to instruction single stepping. 336 if (!m_use_fast_step) 337 return false; 338 339 // clear the m_found_calls, we'll rediscover it for this range. 340 m_found_calls = false; 341 342 lldb::addr_t cur_addr = GetThread().GetRegisterContext()->GetPC(); 343 // Find the current address in our address ranges, and fetch the disassembly 344 // if we haven't already: 345 size_t pc_index; 346 size_t range_index; 347 InstructionList *instructions = 348 GetInstructionsForAddress(cur_addr, range_index, pc_index); 349 if (instructions == nullptr) 350 return false; 351 else { 352 const bool ignore_calls = GetKind() == eKindStepOverRange; 353 uint32_t branch_index = instructions->GetIndexOfNextBranchInstruction( 354 pc_index, ignore_calls, &m_found_calls); 355 Address run_to_address; 356 357 // If we didn't find a branch, run to the end of the range. 358 if (branch_index == UINT32_MAX) { 359 uint32_t last_index = instructions->GetSize() - 1; 360 if (last_index - pc_index > 1) { 361 InstructionSP last_inst = 362 instructions->GetInstructionAtIndex(last_index); 363 size_t last_inst_size = last_inst->GetOpcode().GetByteSize(); 364 run_to_address = last_inst->GetAddress(); 365 run_to_address.Slide(last_inst_size); 366 } 367 } else if (branch_index - pc_index > 1) { 368 run_to_address = 369 instructions->GetInstructionAtIndex(branch_index)->GetAddress(); 370 } 371 if (branch_index == pc_index) 372 LLDB_LOGF(log, "ThreadPlanStepRange::SetNextBranchBreakpoint - skipping " 373 "because current is branch instruction"); 374 if (run_to_address.IsValid()) { 375 const bool is_internal = true; 376 m_next_branch_bp_sp = 377 GetTarget().CreateBreakpoint(run_to_address, is_internal, false); 378 if (m_next_branch_bp_sp) { 379 380 if (m_next_branch_bp_sp->IsHardware() && 381 !m_next_branch_bp_sp->HasResolvedLocations()) 382 m_could_not_resolve_hw_bp = true; 383 384 BreakpointLocationSP bp_loc = 385 m_next_branch_bp_sp->GetLocationAtIndex(0); 386 if (log) { 387 lldb::break_id_t bp_site_id = LLDB_INVALID_BREAK_ID; 388 if (bp_loc) { 389 BreakpointSiteSP bp_site = bp_loc->GetBreakpointSite(); 390 if (bp_site) { 391 bp_site_id = bp_site->GetID(); 392 } 393 } 394 LLDB_LOGF(log, 395 "ThreadPlanStepRange::SetNextBranchBreakpoint - Setting " 396 "breakpoint %d (site %d) to run to address 0x%" PRIx64, 397 m_next_branch_bp_sp->GetID(), bp_site_id, 398 run_to_address.GetLoadAddress(&m_process.GetTarget())); 399 } 400 // The "next branch breakpoint might land on a virtual inlined call 401 // stack. If that's true, we should always stop at the top of the 402 // inlined call stack. Only virtual steps should walk deeper into the 403 // inlined call stack. 404 Block *block = run_to_address.CalculateSymbolContextBlock(); 405 if (bp_loc && block) { 406 LineEntry top_most_line_entry; 407 lldb::addr_t run_to_addr = run_to_address.GetFileAddress(); 408 for (Block *inlined_parent = block->GetContainingInlinedBlock(); 409 inlined_parent; 410 inlined_parent = inlined_parent->GetInlinedParent()) { 411 AddressRange range; 412 if (!inlined_parent->GetRangeContainingAddress(run_to_address, 413 range)) 414 break; 415 Address range_start_address = range.GetBaseAddress(); 416 // Only compare addresses here, we may have different symbol 417 // contexts (for virtual inlined stacks), but we just want to know 418 // that they are all at the same address. 419 if (range_start_address.GetFileAddress() != run_to_addr) 420 break; 421 const InlineFunctionInfo *inline_info = 422 inlined_parent->GetInlinedFunctionInfo(); 423 if (!inline_info) 424 break; 425 const Declaration &call_site = inline_info->GetCallSite(); 426 top_most_line_entry.line = call_site.GetLine(); 427 top_most_line_entry.column = call_site.GetColumn(); 428 FileSpec call_site_file_spec = call_site.GetFile(); 429 top_most_line_entry.original_file_sp.reset( 430 new SupportFile(call_site_file_spec)); 431 top_most_line_entry.range = range; 432 top_most_line_entry.file_sp.reset(); 433 top_most_line_entry.ApplyFileMappings( 434 GetThread().CalculateTarget()); 435 if (!top_most_line_entry.file_sp) 436 top_most_line_entry.file_sp = 437 top_most_line_entry.original_file_sp; 438 } 439 if (top_most_line_entry.IsValid()) { 440 LLDB_LOG(log, "Setting preferred line entry: {0}:{1}", 441 top_most_line_entry.GetFile(), top_most_line_entry.line); 442 bp_loc->SetPreferredLineEntry(top_most_line_entry); 443 } 444 } 445 m_next_branch_bp_sp->SetThreadID(m_tid); 446 m_next_branch_bp_sp->SetBreakpointKind("next-branch-location"); 447 448 return true; 449 } else 450 return false; 451 } else 452 LLDB_LOGF(log, "ThreadPlanStepRange::SetNextBranchBreakpoint - skipping " 453 "invalid run_to_address"); 454 } 455 return false; 456 } 457 458 bool ThreadPlanStepRange::NextRangeBreakpointExplainsStop( 459 lldb::StopInfoSP stop_info_sp) { 460 if (!IsNextBranchBreakpointStop(stop_info_sp)) 461 return false; 462 463 break_id_t bp_site_id = stop_info_sp->GetValue(); 464 BreakpointSiteSP bp_site_sp = 465 m_process.GetBreakpointSiteList().FindByID(bp_site_id); 466 if (!bp_site_sp) 467 return false; 468 469 // If we've hit the next branch breakpoint, then clear it. 470 size_t num_constituents = bp_site_sp->GetNumberOfConstituents(); 471 bool explains_stop = true; 472 // If all the constituents are internal, then we are probably just stepping 473 // over this range from multiple threads, or multiple frames, so we want to 474 // continue. If one is not internal, then we should not explain the stop, 475 // and let the user breakpoint handle the stop. 476 for (size_t i = 0; i < num_constituents; i++) { 477 if (!bp_site_sp->GetConstituentAtIndex(i)->GetBreakpoint().IsInternal()) { 478 explains_stop = false; 479 break; 480 } 481 } 482 Log *log = GetLog(LLDBLog::Step); 483 LLDB_LOGF(log, 484 "ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit " 485 "next range breakpoint which has %" PRIu64 486 " constituents - explains stop: %u.", 487 (uint64_t)num_constituents, explains_stop); 488 return explains_stop; 489 } 490 491 bool ThreadPlanStepRange::WillStop() { return true; } 492 493 StateType ThreadPlanStepRange::GetPlanRunState() { 494 if (m_next_branch_bp_sp) 495 return eStateRunning; 496 else 497 return eStateStepping; 498 } 499 500 bool ThreadPlanStepRange::MischiefManaged() { 501 // If we have pushed some plans between ShouldStop & MischiefManaged, then 502 // we're not done... 503 // I do this check first because we might have stepped somewhere that will 504 // fool InRange into 505 // thinking it needs to step past the end of that line. This happens, for 506 // instance, when stepping over inlined code that is in the middle of the 507 // current line. 508 509 if (!m_no_more_plans) 510 return false; 511 512 bool done = true; 513 if (!IsPlanComplete()) { 514 if (InRange()) { 515 done = false; 516 } else { 517 FrameComparison frame_order = CompareCurrentFrameToStartFrame(); 518 done = (frame_order != eFrameCompareOlder) ? m_no_more_plans : true; 519 } 520 } 521 522 if (done) { 523 Log *log = GetLog(LLDBLog::Step); 524 LLDB_LOGF(log, "Completed step through range plan."); 525 ClearNextBranchBreakpoint(); 526 ThreadPlan::MischiefManaged(); 527 return true; 528 } else { 529 return false; 530 } 531 } 532 533 bool ThreadPlanStepRange::IsPlanStale() { 534 Log *log = GetLog(LLDBLog::Step); 535 FrameComparison frame_order = CompareCurrentFrameToStartFrame(); 536 537 if (frame_order == eFrameCompareOlder) { 538 if (log) { 539 LLDB_LOGF(log, "ThreadPlanStepRange::IsPlanStale returning true, we've " 540 "stepped out."); 541 } 542 return true; 543 } else if (frame_order == eFrameCompareEqual && InSymbol()) { 544 // If we are not in a place we should step through, we've gotten stale. One 545 // tricky bit here is that some stubs don't push a frame, so we should. 546 // check that we are in the same symbol. 547 if (!InRange()) { 548 // Set plan Complete when we reach next instruction just after the range 549 lldb::addr_t addr = GetThread().GetRegisterContext()->GetPC() - 1; 550 size_t num_ranges = m_address_ranges.size(); 551 for (size_t i = 0; i < num_ranges; i++) { 552 bool in_range = 553 m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget()); 554 if (in_range) { 555 SetPlanComplete(); 556 } 557 } 558 return true; 559 } 560 } 561 return false; 562 } 563