1 //===-- ThreadPlanStepInRange.cpp -----------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Target/ThreadPlanStepInRange.h" 10 #include "lldb/Core/Architecture.h" 11 #include "lldb/Core/Module.h" 12 #include "lldb/Symbol/Function.h" 13 #include "lldb/Symbol/Symbol.h" 14 #include "lldb/Target/Process.h" 15 #include "lldb/Target/RegisterContext.h" 16 #include "lldb/Target/SectionLoadList.h" 17 #include "lldb/Target/Target.h" 18 #include "lldb/Target/Thread.h" 19 #include "lldb/Target/ThreadPlanStepOut.h" 20 #include "lldb/Target/ThreadPlanStepThrough.h" 21 #include "lldb/Utility/LLDBLog.h" 22 #include "lldb/Utility/Log.h" 23 #include "lldb/Utility/RegularExpression.h" 24 #include "lldb/Utility/Stream.h" 25 26 using namespace lldb; 27 using namespace lldb_private; 28 29 uint32_t ThreadPlanStepInRange::s_default_flag_values = 30 ThreadPlanShouldStopHere::eStepInAvoidNoDebug; 31 32 // ThreadPlanStepInRange: Step through a stack range, either stepping over or 33 // into based on the value of \a type. 34 35 ThreadPlanStepInRange::ThreadPlanStepInRange( 36 Thread &thread, const AddressRange &range, 37 const SymbolContext &addr_context, const char *step_into_target, 38 lldb::RunMode stop_others, LazyBool step_in_avoids_code_without_debug_info, 39 LazyBool step_out_avoids_code_without_debug_info) 40 : ThreadPlanStepRange(ThreadPlan::eKindStepInRange, 41 "Step Range stepping in", thread, range, addr_context, 42 stop_others), 43 ThreadPlanShouldStopHere(this), m_step_past_prologue(true), 44 m_virtual_step(eLazyBoolCalculate), m_step_into_target(step_into_target) { 45 SetCallbacks(); 46 SetFlagsToDefault(); 47 SetupAvoidNoDebug(step_in_avoids_code_without_debug_info, 48 step_out_avoids_code_without_debug_info); 49 } 50 51 ThreadPlanStepInRange::~ThreadPlanStepInRange() = default; 52 53 void ThreadPlanStepInRange::SetupAvoidNoDebug( 54 LazyBool step_in_avoids_code_without_debug_info, 55 LazyBool step_out_avoids_code_without_debug_info) { 56 bool avoid_nodebug = true; 57 Thread &thread = GetThread(); 58 switch (step_in_avoids_code_without_debug_info) { 59 case eLazyBoolYes: 60 avoid_nodebug = true; 61 break; 62 case eLazyBoolNo: 63 avoid_nodebug = false; 64 break; 65 case eLazyBoolCalculate: 66 avoid_nodebug = thread.GetStepInAvoidsNoDebug(); 67 break; 68 } 69 if (avoid_nodebug) 70 GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug); 71 else 72 GetFlags().Clear(ThreadPlanShouldStopHere::eStepInAvoidNoDebug); 73 74 switch (step_out_avoids_code_without_debug_info) { 75 case eLazyBoolYes: 76 avoid_nodebug = true; 77 break; 78 case eLazyBoolNo: 79 avoid_nodebug = false; 80 break; 81 case eLazyBoolCalculate: 82 avoid_nodebug = thread.GetStepOutAvoidsNoDebug(); 83 break; 84 } 85 if (avoid_nodebug) 86 GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); 87 else 88 GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); 89 } 90 91 void ThreadPlanStepInRange::GetDescription(Stream *s, 92 lldb::DescriptionLevel level) { 93 94 auto PrintFailureIfAny = [&]() { 95 if (m_status.Success()) 96 return; 97 s->Printf(" failed (%s)", m_status.AsCString()); 98 }; 99 100 if (level == lldb::eDescriptionLevelBrief) { 101 s->Printf("step in"); 102 PrintFailureIfAny(); 103 return; 104 } 105 106 s->Printf("Stepping in"); 107 bool printed_line_info = false; 108 if (m_addr_context.line_entry.IsValid()) { 109 s->Printf(" through line "); 110 m_addr_context.line_entry.DumpStopContext(s, false); 111 printed_line_info = true; 112 } 113 114 const char *step_into_target = m_step_into_target.AsCString(); 115 if (step_into_target && step_into_target[0] != '\0') 116 s->Printf(" targeting %s", m_step_into_target.AsCString()); 117 118 if (!printed_line_info || level == eDescriptionLevelVerbose) { 119 s->Printf(" using ranges:"); 120 DumpRanges(s); 121 } 122 123 PrintFailureIfAny(); 124 125 s->PutChar('.'); 126 } 127 128 bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { 129 Log *log = GetLog(LLDBLog::Step); 130 131 if (log) { 132 StreamString s; 133 DumpAddress(s.AsRawOstream(), GetThread().GetRegisterContext()->GetPC(), 134 GetTarget().GetArchitecture().GetAddressByteSize()); 135 LLDB_LOGF(log, "ThreadPlanStepInRange reached %s.", s.GetData()); 136 } 137 ClearNextBranchBreakpointExplainedStop(); 138 139 if (IsPlanComplete()) 140 return true; 141 142 m_no_more_plans = false; 143 if (m_sub_plan_sp && m_sub_plan_sp->IsPlanComplete()) { 144 if (!m_sub_plan_sp->PlanSucceeded()) { 145 SetPlanComplete(); 146 m_no_more_plans = true; 147 return true; 148 } else 149 m_sub_plan_sp.reset(); 150 } 151 152 if (m_virtual_step == eLazyBoolYes) { 153 // If we've just completed a virtual step, all we need to do is check for a 154 // ShouldStopHere plan, and otherwise we're done. 155 // FIXME - This can be both a step in and a step out. Probably should 156 // record which in the m_virtual_step. 157 m_sub_plan_sp = 158 CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger, m_status); 159 } else { 160 // Stepping through should be done running other threads in general, since 161 // we're setting a breakpoint and continuing. So only stop others if we 162 // are explicitly told to do so. 163 164 bool stop_others = (m_stop_others == lldb::eOnlyThisThread); 165 166 FrameComparison frame_order = CompareCurrentFrameToStartFrame(); 167 168 Thread &thread = GetThread(); 169 if (frame_order == eFrameCompareOlder || 170 frame_order == eFrameCompareSameParent) { 171 // If we're in an older frame then we should stop. 172 // 173 // A caveat to this is if we think the frame is older but we're actually 174 // in a trampoline. 175 // I'm going to make the assumption that you wouldn't RETURN to a 176 // trampoline. So if we are in a trampoline we think the frame is older 177 // because the trampoline confused the backtracer. 178 m_sub_plan_sp = thread.QueueThreadPlanForStepThrough( 179 m_stack_id, false, stop_others, m_status); 180 if (!m_sub_plan_sp) { 181 // Otherwise check the ShouldStopHere for step out: 182 m_sub_plan_sp = 183 CheckShouldStopHereAndQueueStepOut(frame_order, m_status); 184 if (log) { 185 if (m_sub_plan_sp) 186 LLDB_LOGF(log, 187 "ShouldStopHere found plan to step out of this frame."); 188 else 189 LLDB_LOGF(log, "ShouldStopHere no plan to step out of this frame."); 190 } 191 } else if (log) { 192 LLDB_LOGF( 193 log, "Thought I stepped out, but in fact arrived at a trampoline."); 194 } 195 } else if (frame_order == eFrameCompareEqual && InSymbol()) { 196 // If we are not in a place we should step through, we're done. One 197 // tricky bit here is that some stubs don't push a frame, so we have to 198 // check both the case of a frame that is younger, or the same as this 199 // frame. However, if the frame is the same, and we are still in the 200 // symbol we started in, the we don't need to do this. This first check 201 // isn't strictly necessary, but it is more efficient. 202 203 // If we're still in the range, keep going, either by running to the next 204 // branch breakpoint, or by stepping. 205 if (InRange()) { 206 SetNextBranchBreakpoint(); 207 return false; 208 } 209 210 SetPlanComplete(); 211 m_no_more_plans = true; 212 return true; 213 } 214 215 // If we get to this point, we're not going to use a previously set "next 216 // branch" breakpoint, so delete it: 217 ClearNextBranchBreakpoint(); 218 219 // We may have set the plan up above in the FrameIsOlder section: 220 221 if (!m_sub_plan_sp) 222 m_sub_plan_sp = thread.QueueThreadPlanForStepThrough( 223 m_stack_id, false, stop_others, m_status); 224 225 if (log) { 226 if (m_sub_plan_sp) 227 LLDB_LOGF(log, "Found a step through plan: %s", 228 m_sub_plan_sp->GetName()); 229 else 230 LLDB_LOGF(log, "No step through plan found."); 231 } 232 233 // If not, give the "should_stop" callback a chance to push a plan to get 234 // us out of here. But only do that if we actually have stepped in. 235 if (!m_sub_plan_sp && frame_order == eFrameCompareYounger) 236 m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order, m_status); 237 238 // If we've stepped in and we are going to stop here, check to see if we 239 // were asked to run past the prologue, and if so do that. 240 241 if (!m_sub_plan_sp && frame_order == eFrameCompareYounger && 242 m_step_past_prologue) { 243 lldb::StackFrameSP curr_frame = thread.GetStackFrameAtIndex(0); 244 if (curr_frame) { 245 size_t bytes_to_skip = 0; 246 lldb::addr_t curr_addr = thread.GetRegisterContext()->GetPC(); 247 Address func_start_address; 248 249 SymbolContext sc = curr_frame->GetSymbolContext(eSymbolContextFunction | 250 eSymbolContextSymbol); 251 252 if (sc.function) { 253 func_start_address = sc.function->GetAddress(); 254 if (curr_addr == func_start_address.GetLoadAddress(&GetTarget())) 255 bytes_to_skip = sc.function->GetPrologueByteSize(); 256 } else if (sc.symbol) { 257 func_start_address = sc.symbol->GetAddress(); 258 if (curr_addr == func_start_address.GetLoadAddress(&GetTarget())) 259 bytes_to_skip = sc.symbol->GetPrologueByteSize(); 260 } 261 262 if (bytes_to_skip == 0 && sc.symbol) { 263 const Architecture *arch = GetTarget().GetArchitecturePlugin(); 264 if (arch) { 265 Address curr_sec_addr; 266 GetTarget().ResolveLoadAddress(curr_addr, curr_sec_addr); 267 bytes_to_skip = arch->GetBytesToSkip(*sc.symbol, curr_sec_addr); 268 } 269 } 270 271 if (bytes_to_skip != 0) { 272 func_start_address.Slide(bytes_to_skip); 273 log = GetLog(LLDBLog::Step); 274 LLDB_LOGF(log, "Pushing past prologue "); 275 276 m_sub_plan_sp = thread.QueueThreadPlanForRunToAddress( 277 false, func_start_address, true, m_status); 278 } 279 } 280 } 281 } 282 283 if (!m_sub_plan_sp) { 284 m_no_more_plans = true; 285 SetPlanComplete(); 286 return true; 287 } else { 288 m_no_more_plans = false; 289 m_sub_plan_sp->SetPrivate(true); 290 return false; 291 } 292 } 293 294 void ThreadPlanStepInRange::SetAvoidRegexp(const char *name) { 295 if (m_avoid_regexp_up) 296 *m_avoid_regexp_up = RegularExpression(name); 297 else 298 m_avoid_regexp_up = std::make_unique<RegularExpression>(name); 299 } 300 301 void ThreadPlanStepInRange::SetDefaultFlagValue(uint32_t new_value) { 302 // TODO: Should we test this for sanity? 303 ThreadPlanStepInRange::s_default_flag_values = new_value; 304 } 305 306 bool ThreadPlanStepInRange::FrameMatchesAvoidCriteria() { 307 StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get(); 308 309 // Check the library list first, as that's cheapest: 310 bool libraries_say_avoid = false; 311 312 FileSpecList libraries_to_avoid(GetThread().GetLibrariesToAvoid()); 313 size_t num_libraries = libraries_to_avoid.GetSize(); 314 if (num_libraries > 0) { 315 SymbolContext sc(frame->GetSymbolContext(eSymbolContextModule)); 316 FileSpec frame_library(sc.module_sp->GetFileSpec()); 317 318 if (frame_library) { 319 for (size_t i = 0; i < num_libraries; i++) { 320 const FileSpec &file_spec(libraries_to_avoid.GetFileSpecAtIndex(i)); 321 if (FileSpec::Match(file_spec, frame_library)) { 322 libraries_say_avoid = true; 323 break; 324 } 325 } 326 } 327 } 328 if (libraries_say_avoid) 329 return true; 330 331 const RegularExpression *avoid_regexp_to_use = m_avoid_regexp_up.get(); 332 if (avoid_regexp_to_use == nullptr) 333 avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp(); 334 335 if (avoid_regexp_to_use != nullptr) { 336 SymbolContext sc = frame->GetSymbolContext( 337 eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol); 338 if (sc.symbol != nullptr) { 339 const char *frame_function_name = 340 sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments) 341 .GetCString(); 342 if (frame_function_name) { 343 bool return_value = avoid_regexp_to_use->Execute(frame_function_name); 344 if (return_value) { 345 LLDB_LOGF(GetLog(LLDBLog::Step), 346 "Stepping out of function \"%s\" because it matches the " 347 "avoid regexp \"%s\".", 348 frame_function_name, 349 avoid_regexp_to_use->GetText().str().c_str()); 350 } 351 return return_value; 352 } 353 } 354 } 355 return false; 356 } 357 358 bool ThreadPlanStepInRange::DefaultShouldStopHereCallback( 359 ThreadPlan *current_plan, Flags &flags, FrameComparison operation, 360 Status &status, void *baton) { 361 bool should_stop_here = true; 362 StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); 363 Log *log = GetLog(LLDBLog::Step); 364 365 // First see if the ThreadPlanShouldStopHere default implementation thinks we 366 // should get out of here: 367 should_stop_here = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback( 368 current_plan, flags, operation, status, baton); 369 if (!should_stop_here) 370 return false; 371 372 if (should_stop_here && current_plan->GetKind() == eKindStepInRange && 373 operation == eFrameCompareYounger) { 374 ThreadPlanStepInRange *step_in_range_plan = 375 static_cast<ThreadPlanStepInRange *>(current_plan); 376 if (step_in_range_plan->m_step_into_target) { 377 SymbolContext sc = frame->GetSymbolContext( 378 eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol); 379 if (sc.symbol != nullptr) { 380 // First try an exact match, since that's cheap with ConstStrings. 381 // Then do a strstr compare. 382 if (step_in_range_plan->m_step_into_target == sc.GetFunctionName()) { 383 should_stop_here = true; 384 } else { 385 const char *target_name = 386 step_in_range_plan->m_step_into_target.AsCString(); 387 const char *function_name = sc.GetFunctionName().AsCString(); 388 389 if (function_name == nullptr) 390 should_stop_here = false; 391 else if (strstr(function_name, target_name) == nullptr) 392 should_stop_here = false; 393 } 394 if (log && !should_stop_here) 395 LLDB_LOGF(log, 396 "Stepping out of frame %s which did not match step into " 397 "target %s.", 398 sc.GetFunctionName().AsCString(), 399 step_in_range_plan->m_step_into_target.AsCString()); 400 } 401 } 402 403 if (should_stop_here) { 404 ThreadPlanStepInRange *step_in_range_plan = 405 static_cast<ThreadPlanStepInRange *>(current_plan); 406 // Don't log the should_step_out here, it's easier to do it in 407 // FrameMatchesAvoidCriteria. 408 should_stop_here = !step_in_range_plan->FrameMatchesAvoidCriteria(); 409 } 410 } 411 412 return should_stop_here; 413 } 414 415 bool ThreadPlanStepInRange::DoPlanExplainsStop(Event *event_ptr) { 416 // We always explain a stop. Either we've just done a single step, in which 417 // case we'll do our ordinary processing, or we stopped for some reason that 418 // isn't handled by our sub-plans, in which case we want to just stop right 419 // away. In general, we don't want to mark the plan as complete for 420 // unexplained stops. For instance, if you step in to some code with no debug 421 // info, so you step out and in the course of that hit a breakpoint, then you 422 // want to stop & show the user the breakpoint, but not unship the step in 423 // plan, since you still may want to complete that plan when you continue. 424 // This is particularly true when doing "step in to target function." 425 // stepping. 426 // 427 // The only variation is that if we are doing "step by running to next 428 // branch" in which case if we hit our branch breakpoint we don't set the 429 // plan to complete. 430 431 bool return_value = false; 432 433 if (m_virtual_step == eLazyBoolYes) { 434 return_value = true; 435 } else { 436 StopInfoSP stop_info_sp = GetPrivateStopInfo(); 437 if (stop_info_sp) { 438 StopReason reason = stop_info_sp->GetStopReason(); 439 440 if (reason == eStopReasonBreakpoint) { 441 if (NextRangeBreakpointExplainsStop(stop_info_sp)) { 442 return_value = true; 443 } 444 } else if (IsUsuallyUnexplainedStopReason(reason)) { 445 Log *log = GetLog(LLDBLog::Step); 446 if (log) 447 log->PutCString("ThreadPlanStepInRange got asked if it explains the " 448 "stop for some reason other than step."); 449 return_value = false; 450 } else { 451 return_value = true; 452 } 453 } else 454 return_value = true; 455 } 456 457 return return_value; 458 } 459 460 bool ThreadPlanStepInRange::DoWillResume(lldb::StateType resume_state, 461 bool current_plan) { 462 m_virtual_step = eLazyBoolCalculate; 463 if (resume_state == eStateStepping && current_plan) { 464 Thread &thread = GetThread(); 465 // See if we are about to step over a virtual inlined call. 466 // But if we already know we're virtual stepping, don't decrement the 467 // inlined depth again... 468 469 bool step_without_resume = thread.DecrementCurrentInlinedDepth(); 470 if (step_without_resume) { 471 Log *log = GetLog(LLDBLog::Step); 472 LLDB_LOGF(log, 473 "ThreadPlanStepInRange::DoWillResume: returning false, " 474 "inline_depth: %d", 475 thread.GetCurrentInlinedDepth()); 476 SetStopInfo(StopInfo::CreateStopReasonToTrace(thread)); 477 478 // FIXME: Maybe it would be better to create a InlineStep stop reason, but 479 // then 480 // the whole rest of the world would have to handle that stop reason. 481 m_virtual_step = eLazyBoolYes; 482 } 483 return !step_without_resume; 484 } 485 return true; 486 } 487 488 bool ThreadPlanStepInRange::IsVirtualStep() { 489 if (m_virtual_step == eLazyBoolCalculate) { 490 Thread &thread = GetThread(); 491 uint32_t cur_inline_depth = thread.GetCurrentInlinedDepth(); 492 if (cur_inline_depth == UINT32_MAX || cur_inline_depth == 0) 493 m_virtual_step = eLazyBoolNo; 494 else 495 m_virtual_step = eLazyBoolYes; 496 } 497 return m_virtual_step == eLazyBoolYes; 498 } 499