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