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