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