1 //===-- ThreadPlanStepInRange.cpp -----------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
27 using namespace lldb_private
;
29 uint32_t ThreadPlanStepInRange::s_default_flag_values
=
30 ThreadPlanShouldStopHere::eStepInAvoidNoDebug
;
32 // ThreadPlanStepInRange: Step through a stack range, either stepping over or
33 // into based on the value of \a type.
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
,
43 ThreadPlanShouldStopHere(this), m_step_past_prologue(true),
44 m_virtual_step(false), m_step_into_target(step_into_target
) {
47 SetupAvoidNoDebug(step_in_avoids_code_without_debug_info
,
48 step_out_avoids_code_without_debug_info
);
51 ThreadPlanStepInRange::~ThreadPlanStepInRange() = default;
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
) {
63 avoid_nodebug
= false;
65 case eLazyBoolCalculate
:
66 avoid_nodebug
= thread
.GetStepInAvoidsNoDebug();
70 GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug
);
72 GetFlags().Clear(ThreadPlanShouldStopHere::eStepInAvoidNoDebug
);
74 switch (step_out_avoids_code_without_debug_info
) {
79 avoid_nodebug
= false;
81 case eLazyBoolCalculate
:
82 avoid_nodebug
= thread
.GetStepOutAvoidsNoDebug();
86 GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug
);
88 GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug
);
91 void ThreadPlanStepInRange::GetDescription(Stream
*s
,
92 lldb::DescriptionLevel level
) {
94 auto PrintFailureIfAny
= [&]() {
95 if (m_status
.Success())
97 s
->Printf(" failed (%s)", m_status
.AsCString());
100 if (level
== lldb::eDescriptionLevelBrief
) {
101 s
->Printf("step in");
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;
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());
118 if (!printed_line_info
|| level
== eDescriptionLevelVerbose
) {
119 s
->Printf(" using ranges:");
128 bool ThreadPlanStepInRange::ShouldStop(Event
*event_ptr
) {
129 Log
*log
= GetLog(LLDBLog::Step
);
133 DumpAddress(s
.AsRawOstream(), GetThread().GetRegisterContext()->GetPC(),
134 GetTarget().GetArchitecture().GetAddressByteSize());
135 LLDB_LOGF(log
, "ThreadPlanStepInRange reached %s.", s
.GetData());
138 if (IsPlanComplete())
141 m_no_more_plans
= false;
142 if (m_sub_plan_sp
&& m_sub_plan_sp
->IsPlanComplete()) {
143 if (!m_sub_plan_sp
->PlanSucceeded()) {
145 m_no_more_plans
= true;
148 m_sub_plan_sp
.reset();
151 if (m_virtual_step
) {
152 // If we've just completed a virtual step, all we need to do is check for a
153 // ShouldStopHere plan, and otherwise we're done.
154 // FIXME - This can be both a step in and a step out. Probably should
155 // record which in the m_virtual_step.
157 CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger
, m_status
);
159 // Stepping through should be done running other threads in general, since
160 // we're setting a breakpoint and continuing. So only stop others if we
161 // are explicitly told to do so.
163 bool stop_others
= (m_stop_others
== lldb::eOnlyThisThread
);
165 FrameComparison frame_order
= CompareCurrentFrameToStartFrame();
167 Thread
&thread
= GetThread();
168 if (frame_order
== eFrameCompareOlder
||
169 frame_order
== eFrameCompareSameParent
) {
170 // If we're in an older frame then we should stop.
172 // A caveat to this is if we think the frame is older but we're actually
174 // I'm going to make the assumption that you wouldn't RETURN to a
175 // trampoline. So if we are in a trampoline we think the frame is older
176 // because the trampoline confused the backtracer.
177 m_sub_plan_sp
= thread
.QueueThreadPlanForStepThrough(
178 m_stack_id
, false, stop_others
, m_status
);
179 if (!m_sub_plan_sp
) {
180 // Otherwise check the ShouldStopHere for step out:
182 CheckShouldStopHereAndQueueStepOut(frame_order
, m_status
);
186 "ShouldStopHere found plan to step out of this frame.");
188 LLDB_LOGF(log
, "ShouldStopHere no plan to step out of this frame.");
192 log
, "Thought I stepped out, but in fact arrived at a trampoline.");
194 } else if (frame_order
== eFrameCompareEqual
&& InSymbol()) {
195 // If we are not in a place we should step through, we're done. One
196 // tricky bit here is that some stubs don't push a frame, so we have to
197 // check both the case of a frame that is younger, or the same as this
198 // frame. However, if the frame is the same, and we are still in the
199 // symbol we started in, the we don't need to do this. This first check
200 // isn't strictly necessary, but it is more efficient.
202 // If we're still in the range, keep going, either by running to the next
203 // branch breakpoint, or by stepping.
205 SetNextBranchBreakpoint();
210 m_no_more_plans
= true;
214 // If we get to this point, we're not going to use a previously set "next
215 // branch" breakpoint, so delete it:
216 ClearNextBranchBreakpoint();
218 // We may have set the plan up above in the FrameIsOlder section:
221 m_sub_plan_sp
= thread
.QueueThreadPlanForStepThrough(
222 m_stack_id
, false, stop_others
, m_status
);
226 LLDB_LOGF(log
, "Found a step through plan: %s",
227 m_sub_plan_sp
->GetName());
229 LLDB_LOGF(log
, "No step through plan found.");
232 // If not, give the "should_stop" callback a chance to push a plan to get
233 // us out of here. But only do that if we actually have stepped in.
234 if (!m_sub_plan_sp
&& frame_order
== eFrameCompareYounger
)
235 m_sub_plan_sp
= CheckShouldStopHereAndQueueStepOut(frame_order
, m_status
);
237 // If we've stepped in and we are going to stop here, check to see if we
238 // were asked to run past the prologue, and if so do that.
240 if (!m_sub_plan_sp
&& frame_order
== eFrameCompareYounger
&&
241 m_step_past_prologue
) {
242 lldb::StackFrameSP curr_frame
= thread
.GetStackFrameAtIndex(0);
244 size_t bytes_to_skip
= 0;
245 lldb::addr_t curr_addr
= thread
.GetRegisterContext()->GetPC();
246 Address func_start_address
;
248 SymbolContext sc
= curr_frame
->GetSymbolContext(eSymbolContextFunction
|
249 eSymbolContextSymbol
);
252 func_start_address
= sc
.function
->GetAddressRange().GetBaseAddress();
253 if (curr_addr
== func_start_address
.GetLoadAddress(&GetTarget()))
254 bytes_to_skip
= sc
.function
->GetPrologueByteSize();
255 } else if (sc
.symbol
) {
256 func_start_address
= sc
.symbol
->GetAddress();
257 if (curr_addr
== func_start_address
.GetLoadAddress(&GetTarget()))
258 bytes_to_skip
= sc
.symbol
->GetPrologueByteSize();
261 if (bytes_to_skip
== 0 && sc
.symbol
) {
262 const Architecture
*arch
= GetTarget().GetArchitecturePlugin();
264 Address curr_sec_addr
;
265 GetTarget().GetSectionLoadList().ResolveLoadAddress(curr_addr
,
267 bytes_to_skip
= arch
->GetBytesToSkip(*sc
.symbol
, curr_sec_addr
);
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 ");
276 m_sub_plan_sp
= thread
.QueueThreadPlanForRunToAddress(
277 false, func_start_address
, true, m_status
);
283 if (!m_sub_plan_sp
) {
284 m_no_more_plans
= true;
288 m_no_more_plans
= false;
289 m_sub_plan_sp
->SetPrivate(true);
294 void ThreadPlanStepInRange::SetAvoidRegexp(const char *name
) {
295 if (m_avoid_regexp_up
)
296 *m_avoid_regexp_up
= RegularExpression(name
);
298 m_avoid_regexp_up
= std::make_unique
<RegularExpression
>(name
);
301 void ThreadPlanStepInRange::SetDefaultFlagValue(uint32_t new_value
) {
302 // TODO: Should we test this for sanity?
303 ThreadPlanStepInRange::s_default_flag_values
= new_value
;
306 bool ThreadPlanStepInRange::FrameMatchesAvoidCriteria() {
307 StackFrame
*frame
= GetThread().GetStackFrameAtIndex(0).get();
309 // Check the library list first, as that's cheapest:
310 bool libraries_say_avoid
= false;
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());
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;
328 if (libraries_say_avoid
)
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();
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
)
342 if (frame_function_name
) {
343 bool return_value
= avoid_regexp_to_use
->Execute(frame_function_name
);
345 LLDB_LOGF(GetLog(LLDBLog::Step
),
346 "Stepping out of function \"%s\" because it matches the "
347 "avoid regexp \"%s\".",
349 avoid_regexp_to_use
->GetText().str().c_str());
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
);
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
)
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;
385 const char *target_name
=
386 step_in_range_plan
->m_step_into_target
.AsCString();
387 const char *function_name
= sc
.GetFunctionName().AsCString();
389 if (function_name
== nullptr)
390 should_stop_here
= false;
391 else if (strstr(function_name
, target_name
) == nullptr)
392 should_stop_here
= false;
394 if (log
&& !should_stop_here
)
396 "Stepping out of frame %s which did not match step into "
398 sc
.GetFunctionName().AsCString(),
399 step_in_range_plan
->m_step_into_target
.AsCString());
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();
412 return should_stop_here
;
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."
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
431 bool return_value
= false;
433 if (m_virtual_step
) {
436 StopInfoSP stop_info_sp
= GetPrivateStopInfo();
438 StopReason reason
= stop_info_sp
->GetStopReason();
440 if (reason
== eStopReasonBreakpoint
) {
441 if (NextRangeBreakpointExplainsStop(stop_info_sp
)) {
444 } else if (IsUsuallyUnexplainedStopReason(reason
)) {
445 Log
*log
= GetLog(LLDBLog::Step
);
447 log
->PutCString("ThreadPlanStepInRange got asked if it explains the "
448 "stop for some reason other than step.");
449 return_value
= false;
460 bool ThreadPlanStepInRange::DoWillResume(lldb::StateType resume_state
,
462 m_virtual_step
= false;
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 bool step_without_resume
= thread
.DecrementCurrentInlinedDepth();
467 if (step_without_resume
) {
468 Log
*log
= GetLog(LLDBLog::Step
);
470 "ThreadPlanStepInRange::DoWillResume: returning false, "
472 thread
.GetCurrentInlinedDepth());
473 SetStopInfo(StopInfo::CreateStopReasonToTrace(thread
));
475 // FIXME: Maybe it would be better to create a InlineStep stop reason, but
477 // the whole rest of the world would have to handle that stop reason.
478 m_virtual_step
= true;
480 return !step_without_resume
;
485 bool ThreadPlanStepInRange::IsVirtualStep() { return m_virtual_step
; }