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