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