blob: 6405c135a33e8baf0b580fd5d501552f0939c749 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- ThreadPlanStepInRange.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
Chris Lattner30fdc8d2010-06-08 16:52:24 +000010// C Includes
11// C++ Includes
12// Other libraries and framework includes
13// Project includes
Eugene Zelenkoe65b2cf2015-12-15 01:33:19 +000014#include "lldb/Target/ThreadPlanStepInRange.h"
Jim Ingham08581262018-03-12 21:17:04 +000015#include "lldb/Core/Architecture.h"
Jim Ingham4da62062014-01-23 21:52:47 +000016#include "lldb/Core/Module.h"
Jim Ingham7ce490c2010-09-16 00:58:09 +000017#include "lldb/Symbol/Function.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000018#include "lldb/Symbol/Symbol.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000019#include "lldb/Target/Process.h"
20#include "lldb/Target/RegisterContext.h"
Jim Ingham08581262018-03-12 21:17:04 +000021#include "lldb/Target/SectionLoadList.h"
Greg Clayton514487e2011-02-15 21:59:32 +000022#include "lldb/Target/Target.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000023#include "lldb/Target/Thread.h"
24#include "lldb/Target/ThreadPlanStepOut.h"
25#include "lldb/Target/ThreadPlanStepThrough.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000026#include "lldb/Utility/Log.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000027#include "lldb/Utility/RegularExpression.h"
28#include "lldb/Utility/Stream.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000029
30using namespace lldb;
31using namespace lldb_private;
32
Kate Stoneb9c1b512016-09-06 20:57:50 +000033uint32_t ThreadPlanStepInRange::s_default_flag_values =
34 ThreadPlanShouldStopHere::eStepInAvoidNoDebug;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000035
36//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000037// ThreadPlanStepInRange: Step through a stack range, either stepping over or
Adrian Prantl05097242018-04-30 16:49:04 +000038// into based on the value of \a type.
Chris Lattner30fdc8d2010-06-08 16:52:24 +000039//----------------------------------------------------------------------
40
Kate Stoneb9c1b512016-09-06 20:57:50 +000041ThreadPlanStepInRange::ThreadPlanStepInRange(
42 Thread &thread, const AddressRange &range,
43 const SymbolContext &addr_context, lldb::RunMode stop_others,
Jim Ingham4b4b2472014-03-13 02:47:14 +000044 LazyBool step_in_avoids_code_without_debug_info,
Kate Stoneb9c1b512016-09-06 20:57:50 +000045 LazyBool step_out_avoids_code_without_debug_info)
46 : ThreadPlanStepRange(ThreadPlan::eKindStepInRange,
47 "Step Range stepping in", thread, range, addr_context,
48 stop_others),
49 ThreadPlanShouldStopHere(this), m_step_past_prologue(true),
50 m_virtual_step(false) {
51 SetCallbacks();
52 SetFlagsToDefault();
53 SetupAvoidNoDebug(step_in_avoids_code_without_debug_info,
54 step_out_avoids_code_without_debug_info);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000055}
56
Kate Stoneb9c1b512016-09-06 20:57:50 +000057ThreadPlanStepInRange::ThreadPlanStepInRange(
58 Thread &thread, const AddressRange &range,
59 const SymbolContext &addr_context, const char *step_into_target,
60 lldb::RunMode stop_others, LazyBool step_in_avoids_code_without_debug_info,
61 LazyBool step_out_avoids_code_without_debug_info)
62 : ThreadPlanStepRange(ThreadPlan::eKindStepInRange,
63 "Step Range stepping in", thread, range, addr_context,
64 stop_others),
65 ThreadPlanShouldStopHere(this), m_step_past_prologue(true),
66 m_virtual_step(false), m_step_into_target(step_into_target) {
67 SetCallbacks();
68 SetFlagsToDefault();
69 SetupAvoidNoDebug(step_in_avoids_code_without_debug_info,
70 step_out_avoids_code_without_debug_info);
Jim Inghamc6276822012-12-12 19:58:40 +000071}
72
Eugene Zelenkoe65b2cf2015-12-15 01:33:19 +000073ThreadPlanStepInRange::~ThreadPlanStepInRange() = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000074
Kate Stoneb9c1b512016-09-06 20:57:50 +000075void ThreadPlanStepInRange::SetupAvoidNoDebug(
76 LazyBool step_in_avoids_code_without_debug_info,
77 LazyBool step_out_avoids_code_without_debug_info) {
78 bool avoid_nodebug = true;
79
80 switch (step_in_avoids_code_without_debug_info) {
81 case eLazyBoolYes:
82 avoid_nodebug = true;
83 break;
84 case eLazyBoolNo:
85 avoid_nodebug = false;
86 break;
87 case eLazyBoolCalculate:
88 avoid_nodebug = m_thread.GetStepInAvoidsNoDebug();
89 break;
90 }
91 if (avoid_nodebug)
92 GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
93 else
94 GetFlags().Clear(ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
95
96 switch (step_out_avoids_code_without_debug_info) {
97 case eLazyBoolYes:
98 avoid_nodebug = true;
99 break;
100 case eLazyBoolNo:
101 avoid_nodebug = false;
102 break;
103 case eLazyBoolCalculate:
104 avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug();
105 break;
106 }
107 if (avoid_nodebug)
108 GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
109 else
110 GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
Jim Ingham4b4b2472014-03-13 02:47:14 +0000111}
112
Kate Stoneb9c1b512016-09-06 20:57:50 +0000113void ThreadPlanStepInRange::GetDescription(Stream *s,
114 lldb::DescriptionLevel level) {
115 if (level == lldb::eDescriptionLevelBrief) {
116 s->Printf("step in");
117 return;
118 }
Jim Ingham2bdbfd52014-09-29 23:17:18 +0000119
Kate Stoneb9c1b512016-09-06 20:57:50 +0000120 s->Printf("Stepping in");
121 bool printed_line_info = false;
122 if (m_addr_context.line_entry.IsValid()) {
123 s->Printf(" through line ");
124 m_addr_context.line_entry.DumpStopContext(s, false);
125 printed_line_info = true;
126 }
Jim Ingham2bdbfd52014-09-29 23:17:18 +0000127
Kate Stoneb9c1b512016-09-06 20:57:50 +0000128 const char *step_into_target = m_step_into_target.AsCString();
129 if (step_into_target && step_into_target[0] != '\0')
130 s->Printf(" targeting %s", m_step_into_target.AsCString());
Jim Ingham2bdbfd52014-09-29 23:17:18 +0000131
Kate Stoneb9c1b512016-09-06 20:57:50 +0000132 if (!printed_line_info || level == eDescriptionLevelVerbose) {
133 s->Printf(" using ranges:");
134 DumpRanges(s);
135 }
Jim Ingham2bdbfd52014-09-29 23:17:18 +0000136
Kate Stoneb9c1b512016-09-06 20:57:50 +0000137 s->PutChar('.');
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000138}
139
Kate Stoneb9c1b512016-09-06 20:57:50 +0000140bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
141 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000142
Kate Stoneb9c1b512016-09-06 20:57:50 +0000143 if (log) {
144 StreamString s;
145 s.Address(
146 m_thread.GetRegisterContext()->GetPC(),
147 m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
148 log->Printf("ThreadPlanStepInRange reached %s.", s.GetData());
149 }
Jim Inghamf02a2e92012-09-07 01:11:44 +0000150
Kate Stoneb9c1b512016-09-06 20:57:50 +0000151 if (IsPlanComplete())
Jim Ingham221d51c2013-05-08 00:35:16 +0000152 return true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000153
154 m_no_more_plans = false;
155 if (m_sub_plan_sp && m_sub_plan_sp->IsPlanComplete()) {
156 if (!m_sub_plan_sp->PlanSucceeded()) {
157 SetPlanComplete();
158 m_no_more_plans = true;
159 return true;
160 } else
161 m_sub_plan_sp.reset();
162 }
163
164 if (m_virtual_step) {
165 // If we've just completed a virtual step, all we need to do is check for a
Adrian Prantl05097242018-04-30 16:49:04 +0000166 // ShouldStopHere plan, and otherwise we're done.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000167 // FIXME - This can be both a step in and a step out. Probably should
168 // record which in the m_virtual_step.
169 m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger);
170 } else {
171 // Stepping through should be done running other threads in general, since
Adrian Prantl05097242018-04-30 16:49:04 +0000172 // we're setting a breakpoint and continuing. So only stop others if we
173 // are explicitly told to do so.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000174
175 bool stop_others = (m_stop_others == lldb::eOnlyThisThread);
176
177 FrameComparison frame_order = CompareCurrentFrameToStartFrame();
178
179 if (frame_order == eFrameCompareOlder ||
180 frame_order == eFrameCompareSameParent) {
181 // If we're in an older frame then we should stop.
182 //
183 // A caveat to this is if we think the frame is older but we're actually
184 // in a trampoline.
185 // I'm going to make the assumption that you wouldn't RETURN to a
Adrian Prantl05097242018-04-30 16:49:04 +0000186 // trampoline. So if we are in a trampoline we think the frame is older
187 // because the trampoline confused the backtracer.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000188 m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false,
189 stop_others);
190 if (!m_sub_plan_sp) {
191 // Otherwise check the ShouldStopHere for step out:
192 m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order);
Jim Inghama4bb80b2017-08-23 19:40:21 +0000193 if (log) {
194 if (m_sub_plan_sp)
195 log->Printf("ShouldStopHere found plan to step out of this frame.");
196 else
197 log->Printf("ShouldStopHere no plan to step out of this frame.");
198 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000199 } else if (log) {
200 log->Printf(
201 "Thought I stepped out, but in fact arrived at a trampoline.");
202 }
203 } else if (frame_order == eFrameCompareEqual && InSymbol()) {
Adrian Prantl05097242018-04-30 16:49:04 +0000204 // If we are not in a place we should step through, we're done. One
205 // tricky bit here is that some stubs don't push a frame, so we have to
206 // check both the case of a frame that is younger, or the same as this
207 // frame. However, if the frame is the same, and we are still in the
208 // symbol we started in, the we don't need to do this. This first check
209 // isn't strictly necessary, but it is more efficient.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000210
211 // If we're still in the range, keep going, either by running to the next
Adrian Prantl05097242018-04-30 16:49:04 +0000212 // branch breakpoint, or by stepping.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000213 if (InRange()) {
214 SetNextBranchBreakpoint();
215 return false;
216 }
217
218 SetPlanComplete();
219 m_no_more_plans = true;
220 return true;
221 }
222
223 // If we get to this point, we're not going to use a previously set "next
224 // branch" breakpoint, so delete it:
225 ClearNextBranchBreakpoint();
226
227 // We may have set the plan up above in the FrameIsOlder section:
228
229 if (!m_sub_plan_sp)
230 m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false,
231 stop_others);
232
233 if (log) {
234 if (m_sub_plan_sp)
235 log->Printf("Found a step through plan: %s", m_sub_plan_sp->GetName());
236 else
237 log->Printf("No step through plan found.");
238 }
239
Adrian Prantl05097242018-04-30 16:49:04 +0000240 // If not, give the "should_stop" callback a chance to push a plan to get
241 // us out of here. But only do that if we actually have stepped in.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000242 if (!m_sub_plan_sp && frame_order == eFrameCompareYounger)
243 m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order);
244
245 // If we've stepped in and we are going to stop here, check to see if we
Adrian Prantl05097242018-04-30 16:49:04 +0000246 // were asked to run past the prologue, and if so do that.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000247
248 if (!m_sub_plan_sp && frame_order == eFrameCompareYounger &&
249 m_step_past_prologue) {
250 lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0);
251 if (curr_frame) {
252 size_t bytes_to_skip = 0;
253 lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC();
254 Address func_start_address;
255
256 SymbolContext sc = curr_frame->GetSymbolContext(eSymbolContextFunction |
257 eSymbolContextSymbol);
258
259 if (sc.function) {
260 func_start_address = sc.function->GetAddressRange().GetBaseAddress();
261 if (curr_addr ==
262 func_start_address.GetLoadAddress(
263 m_thread.CalculateTarget().get()))
264 bytes_to_skip = sc.function->GetPrologueByteSize();
265 } else if (sc.symbol) {
266 func_start_address = sc.symbol->GetAddress();
267 if (curr_addr ==
268 func_start_address.GetLoadAddress(
269 m_thread.CalculateTarget().get()))
270 bytes_to_skip = sc.symbol->GetPrologueByteSize();
271 }
272
Jim Ingham08581262018-03-12 21:17:04 +0000273 if (bytes_to_skip == 0 && sc.symbol) {
274 TargetSP target = m_thread.CalculateTarget();
Tatyana Krasnukha3da0f212018-06-27 07:01:07 +0000275 const Architecture *arch = target->GetArchitecturePlugin();
Jim Ingham08581262018-03-12 21:17:04 +0000276 if (arch) {
277 Address curr_sec_addr;
278 target->GetSectionLoadList().ResolveLoadAddress(curr_addr,
279 curr_sec_addr);
280 bytes_to_skip = arch->GetBytesToSkip(*sc.symbol, curr_sec_addr);
281 }
282 }
283
Kate Stoneb9c1b512016-09-06 20:57:50 +0000284 if (bytes_to_skip != 0) {
285 func_start_address.Slide(bytes_to_skip);
286 log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP);
287 if (log)
288 log->Printf("Pushing past prologue ");
289
290 m_sub_plan_sp = m_thread.QueueThreadPlanForRunToAddress(
291 false, func_start_address, true);
292 }
293 }
294 }
295 }
296
297 if (!m_sub_plan_sp) {
298 m_no_more_plans = true;
299 SetPlanComplete();
300 return true;
301 } else {
302 m_no_more_plans = false;
303 m_sub_plan_sp->SetPrivate(true);
304 return false;
305 }
Jim Ingham513c6bb2012-09-01 01:02:41 +0000306}
Daniel Malea246cb612013-05-14 15:20:12 +0000307
Kate Stoneb9c1b512016-09-06 20:57:50 +0000308void ThreadPlanStepInRange::SetAvoidRegexp(const char *name) {
Zachary Turner95eae422016-09-21 16:01:28 +0000309 auto name_ref = llvm::StringRef::withNullAsEmpty(name);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000310 if (!m_avoid_regexp_ap)
Zachary Turner95eae422016-09-21 16:01:28 +0000311 m_avoid_regexp_ap.reset(new RegularExpression(name_ref));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000312
Zachary Turner95eae422016-09-21 16:01:28 +0000313 m_avoid_regexp_ap->Compile(name_ref);
Daniel Malea246cb612013-05-14 15:20:12 +0000314}
Kate Stoneb9c1b512016-09-06 20:57:50 +0000315
316void ThreadPlanStepInRange::SetDefaultFlagValue(uint32_t new_value) {
317 // TODO: Should we test this for sanity?
318 ThreadPlanStepInRange::s_default_flag_values = new_value;
319}
320
321bool ThreadPlanStepInRange::FrameMatchesAvoidCriteria() {
322 StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
323
324 // Check the library list first, as that's cheapest:
325 bool libraries_say_avoid = false;
326
327 FileSpecList libraries_to_avoid(GetThread().GetLibrariesToAvoid());
328 size_t num_libraries = libraries_to_avoid.GetSize();
329 if (num_libraries > 0) {
330 SymbolContext sc(frame->GetSymbolContext(eSymbolContextModule));
331 FileSpec frame_library(sc.module_sp->GetFileSpec());
332
333 if (frame_library) {
334 for (size_t i = 0; i < num_libraries; i++) {
335 const FileSpec &file_spec(libraries_to_avoid.GetFileSpecAtIndex(i));
336 if (FileSpec::Equal(file_spec, frame_library, false)) {
337 libraries_say_avoid = true;
338 break;
339 }
340 }
341 }
342 }
343 if (libraries_say_avoid)
344 return true;
345
346 const RegularExpression *avoid_regexp_to_use = m_avoid_regexp_ap.get();
347 if (avoid_regexp_to_use == nullptr)
348 avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp();
349
350 if (avoid_regexp_to_use != nullptr) {
351 SymbolContext sc = frame->GetSymbolContext(
352 eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol);
353 if (sc.symbol != nullptr) {
354 const char *frame_function_name =
355 sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments)
356 .GetCString();
357 if (frame_function_name) {
358 size_t num_matches = 0;
359 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
360 if (log)
361 num_matches = 1;
362
363 RegularExpression::Match regex_match(num_matches);
364
365 bool return_value =
366 avoid_regexp_to_use->Execute(frame_function_name, &regex_match);
367 if (return_value) {
368 if (log) {
369 std::string match;
370 regex_match.GetMatchAtIndex(frame_function_name, 0, match);
371 log->Printf("Stepping out of function \"%s\" because it matches "
372 "the avoid regexp \"%s\" - match substring: \"%s\".",
Zachary Turner95eae422016-09-21 16:01:28 +0000373 frame_function_name,
374 avoid_regexp_to_use->GetText().str().c_str(),
Kate Stoneb9c1b512016-09-06 20:57:50 +0000375 match.c_str());
376 }
377 }
378 return return_value;
379 }
380 }
381 }
382 return false;
383}
384
385bool ThreadPlanStepInRange::DefaultShouldStopHereCallback(
386 ThreadPlan *current_plan, Flags &flags, FrameComparison operation,
387 void *baton) {
388 bool should_stop_here = true;
389 StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
390 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
391
392 // First see if the ThreadPlanShouldStopHere default implementation thinks we
393 // should get out of here:
394 should_stop_here = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback(
395 current_plan, flags, operation, baton);
396 if (!should_stop_here)
397 return should_stop_here;
398
399 if (should_stop_here && current_plan->GetKind() == eKindStepInRange &&
400 operation == eFrameCompareYounger) {
401 ThreadPlanStepInRange *step_in_range_plan =
402 static_cast<ThreadPlanStepInRange *>(current_plan);
403 if (step_in_range_plan->m_step_into_target) {
404 SymbolContext sc = frame->GetSymbolContext(
405 eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol);
406 if (sc.symbol != nullptr) {
Adrian Prantl05097242018-04-30 16:49:04 +0000407 // First try an exact match, since that's cheap with ConstStrings.
408 // Then do a strstr compare.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000409 if (step_in_range_plan->m_step_into_target == sc.GetFunctionName()) {
410 should_stop_here = true;
411 } else {
412 const char *target_name =
413 step_in_range_plan->m_step_into_target.AsCString();
414 const char *function_name = sc.GetFunctionName().AsCString();
415
416 if (function_name == nullptr)
417 should_stop_here = false;
418 else if (strstr(function_name, target_name) == nullptr)
419 should_stop_here = false;
420 }
421 if (log && !should_stop_here)
422 log->Printf("Stepping out of frame %s which did not match step into "
423 "target %s.",
424 sc.GetFunctionName().AsCString(),
425 step_in_range_plan->m_step_into_target.AsCString());
426 }
427 }
428
429 if (should_stop_here) {
430 ThreadPlanStepInRange *step_in_range_plan =
431 static_cast<ThreadPlanStepInRange *>(current_plan);
432 // Don't log the should_step_out here, it's easier to do it in
433 // FrameMatchesAvoidCriteria.
434 should_stop_here = !step_in_range_plan->FrameMatchesAvoidCriteria();
435 }
436 }
437
438 return should_stop_here;
439}
440
441bool ThreadPlanStepInRange::DoPlanExplainsStop(Event *event_ptr) {
442 // We always explain a stop. Either we've just done a single step, in which
Adrian Prantl05097242018-04-30 16:49:04 +0000443 // case we'll do our ordinary processing, or we stopped for some reason that
444 // isn't handled by our sub-plans, in which case we want to just stop right
445 // away. In general, we don't want to mark the plan as complete for
446 // unexplained stops. For instance, if you step in to some code with no debug
447 // info, so you step out and in the course of that hit a breakpoint, then you
448 // want to stop & show the user the breakpoint, but not unship the step in
449 // plan, since you still may want to complete that plan when you continue.
450 // This is particularly true when doing "step in to target function."
Kate Stoneb9c1b512016-09-06 20:57:50 +0000451 // stepping.
452 //
Adrian Prantl05097242018-04-30 16:49:04 +0000453 // The only variation is that if we are doing "step by running to next
454 // branch" in which case if we hit our branch breakpoint we don't set the
455 // plan to complete.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000456
457 bool return_value = false;
458
459 if (m_virtual_step) {
460 return_value = true;
461 } else {
462 StopInfoSP stop_info_sp = GetPrivateStopInfo();
463 if (stop_info_sp) {
464 StopReason reason = stop_info_sp->GetStopReason();
465
466 if (reason == eStopReasonBreakpoint) {
467 if (NextRangeBreakpointExplainsStop(stop_info_sp)) {
468 return_value = true;
469 }
470 } else if (IsUsuallyUnexplainedStopReason(reason)) {
471 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
472 if (log)
473 log->PutCString("ThreadPlanStepInRange got asked if it explains the "
474 "stop for some reason other than step.");
475 return_value = false;
476 } else {
477 return_value = true;
478 }
479 } else
480 return_value = true;
481 }
482
483 return return_value;
484}
485
486bool ThreadPlanStepInRange::DoWillResume(lldb::StateType resume_state,
487 bool current_plan) {
488 m_virtual_step = false;
489 if (resume_state == eStateStepping && current_plan) {
490 // See if we are about to step over a virtual inlined call.
491 bool step_without_resume = m_thread.DecrementCurrentInlinedDepth();
492 if (step_without_resume) {
493 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
494 if (log)
495 log->Printf("ThreadPlanStepInRange::DoWillResume: returning false, "
496 "inline_depth: %d",
497 m_thread.GetCurrentInlinedDepth());
498 SetStopInfo(StopInfo::CreateStopReasonToTrace(m_thread));
499
500 // FIXME: Maybe it would be better to create a InlineStep stop reason, but
501 // then
502 // the whole rest of the world would have to handle that stop reason.
503 m_virtual_step = true;
504 }
505 return !step_without_resume;
506 }
507 return true;
508}
509
510bool ThreadPlanStepInRange::IsVirtualStep() { return m_virtual_step; }