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