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