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