130fdc8d8SChris Lattner //===-- ThreadPlanStepInRange.cpp -------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner 
1030fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepInRange.h"
1130fdc8d8SChris Lattner 
1230fdc8d8SChris Lattner // C Includes
1330fdc8d8SChris Lattner // C++ Includes
1430fdc8d8SChris Lattner // Other libraries and framework includes
1530fdc8d8SChris Lattner // Project includes
1630fdc8d8SChris Lattner 
1730fdc8d8SChris Lattner #include "lldb/lldb-private-log.h"
1830fdc8d8SChris Lattner #include "lldb/Core/Log.h"
1930fdc8d8SChris Lattner #include "lldb/Core/Stream.h"
20a56c8006SJim Ingham #include "lldb/Symbol/Symbol.h"
217ce490c6SJim Ingham #include "lldb/Symbol/Function.h"
2230fdc8d8SChris Lattner #include "lldb/Target/Process.h"
2330fdc8d8SChris Lattner #include "lldb/Target/RegisterContext.h"
24514487e8SGreg Clayton #include "lldb/Target/Target.h"
2530fdc8d8SChris Lattner #include "lldb/Target/Thread.h"
2630fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepOut.h"
2730fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepThrough.h"
28a56c8006SJim Ingham #include "lldb/Core/RegularExpression.h"
2930fdc8d8SChris Lattner 
3030fdc8d8SChris Lattner using namespace lldb;
3130fdc8d8SChris Lattner using namespace lldb_private;
3230fdc8d8SChris Lattner 
3330fdc8d8SChris Lattner uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eAvoidNoDebug;
3430fdc8d8SChris Lattner 
3530fdc8d8SChris Lattner //----------------------------------------------------------------------
3630fdc8d8SChris Lattner // ThreadPlanStepInRange: Step through a stack range, either stepping over or into
3730fdc8d8SChris Lattner // based on the value of \a type.
3830fdc8d8SChris Lattner //----------------------------------------------------------------------
3930fdc8d8SChris Lattner 
4030fdc8d8SChris Lattner ThreadPlanStepInRange::ThreadPlanStepInRange
4130fdc8d8SChris Lattner (
4230fdc8d8SChris Lattner     Thread &thread,
4330fdc8d8SChris Lattner     const AddressRange &range,
4430fdc8d8SChris Lattner     const SymbolContext &addr_context,
4530fdc8d8SChris Lattner     lldb::RunMode stop_others
4630fdc8d8SChris Lattner ) :
47b01e742aSJim Ingham     ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
487ce490c6SJim Ingham     ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
49f02a2e96SJim Ingham     m_step_past_prologue (true),
50f02a2e96SJim Ingham     m_virtual_step (false)
5130fdc8d8SChris Lattner {
5230fdc8d8SChris Lattner     SetFlagsToDefault ();
5330fdc8d8SChris Lattner }
5430fdc8d8SChris Lattner 
55c627682eSJim Ingham ThreadPlanStepInRange::ThreadPlanStepInRange
56c627682eSJim Ingham (
57c627682eSJim Ingham     Thread &thread,
58c627682eSJim Ingham     const AddressRange &range,
59c627682eSJim Ingham     const SymbolContext &addr_context,
60c627682eSJim Ingham     const char *step_into_target,
61c627682eSJim Ingham     lldb::RunMode stop_others
62c627682eSJim Ingham ) :
63c627682eSJim Ingham     ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
64c627682eSJim Ingham     ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
65c627682eSJim Ingham     m_step_past_prologue (true),
66c627682eSJim Ingham     m_virtual_step (false),
67c627682eSJim Ingham     m_step_into_target (step_into_target)
68c627682eSJim Ingham {
69c627682eSJim Ingham     SetFlagsToDefault ();
70c627682eSJim Ingham }
71c627682eSJim Ingham 
7230fdc8d8SChris Lattner ThreadPlanStepInRange::~ThreadPlanStepInRange ()
7330fdc8d8SChris Lattner {
7430fdc8d8SChris Lattner }
7530fdc8d8SChris Lattner 
7630fdc8d8SChris Lattner void
7730fdc8d8SChris Lattner ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
7830fdc8d8SChris Lattner {
7930fdc8d8SChris Lattner     if (level == lldb::eDescriptionLevelBrief)
8030fdc8d8SChris Lattner         s->Printf("step in");
8130fdc8d8SChris Lattner     else
8230fdc8d8SChris Lattner     {
8330fdc8d8SChris Lattner         s->Printf ("Stepping through range (stepping into functions): ");
84c4c9fedcSJim Ingham         DumpRanges(s);
85c627682eSJim Ingham         s->Printf ("targeting %s.", m_step_into_target.AsCString());
8630fdc8d8SChris Lattner     }
8730fdc8d8SChris Lattner }
8830fdc8d8SChris Lattner 
8930fdc8d8SChris Lattner bool
9030fdc8d8SChris Lattner ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
9130fdc8d8SChris Lattner {
922d4edfbcSGreg Clayton     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
9330fdc8d8SChris Lattner     m_no_more_plans = false;
9430fdc8d8SChris Lattner 
9530fdc8d8SChris Lattner     if (log)
9630fdc8d8SChris Lattner     {
9730fdc8d8SChris Lattner         StreamString s;
98514487e8SGreg Clayton         s.Address (m_thread.GetRegisterContext()->GetPC(),
991ac04c30SGreg Clayton                    m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
10030fdc8d8SChris Lattner         log->Printf("ThreadPlanStepInRange reached %s.", s.GetData());
10130fdc8d8SChris Lattner     }
10230fdc8d8SChris Lattner 
10325f66700SJim Ingham     if (IsPlanComplete())
10425f66700SJim Ingham         return true;
10525f66700SJim Ingham 
10630fdc8d8SChris Lattner     ThreadPlan* new_plan = NULL;
10730fdc8d8SChris Lattner 
108f02a2e96SJim Ingham     if (m_virtual_step)
109f02a2e96SJim Ingham     {
110f02a2e96SJim Ingham         // If we've just completed a virtual step, all we need to do is check for a ShouldStopHere plan, and otherwise
111f02a2e96SJim Ingham         // we're done.
112f02a2e96SJim Ingham         new_plan = InvokeShouldStopHereCallback();
113f02a2e96SJim Ingham     }
114f02a2e96SJim Ingham     else
115f02a2e96SJim Ingham     {
1164a58e968SJim Ingham         // Stepping through should be done running other threads in general, since we're setting a breakpoint and
1174a58e968SJim Ingham         // continuing.  So only stop others if we are explicitly told to do so.
1189d790c5dSJim Ingham 
11930fdc8d8SChris Lattner         bool stop_others;
1204a58e968SJim Ingham         if (m_stop_others == lldb::eOnlyThisThread)
12130fdc8d8SChris Lattner             stop_others = false;
1224a58e968SJim Ingham         else
1234a58e968SJim Ingham             stop_others = true;
12430fdc8d8SChris Lattner 
125b5c0d1ccSJim Ingham         FrameComparison frame_order = CompareCurrentFrameToStartFrame();
126b5c0d1ccSJim Ingham 
127b5c0d1ccSJim Ingham         if (frame_order == eFrameCompareOlder)
1285822173bSJim Ingham         {
1295822173bSJim Ingham             // If we're in an older frame then we should stop.
1305822173bSJim Ingham             //
1315822173bSJim Ingham             // A caveat to this is if we think the frame is older but we're actually in a trampoline.
1325822173bSJim Ingham             // I'm going to make the assumption that you wouldn't RETURN to a trampoline.  So if we are
1335822173bSJim Ingham             // in a trampoline we think the frame is older because the trampoline confused the backtracer.
13418de2fdcSJim Ingham             new_plan = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
1355822173bSJim Ingham             if (new_plan == NULL)
1365822173bSJim Ingham                 return true;
1375822173bSJim Ingham             else if (log)
1385822173bSJim Ingham             {
1395822173bSJim Ingham                 log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
1405822173bSJim Ingham             }
1415822173bSJim Ingham 
1425822173bSJim Ingham         }
143564d8bc2SJim Ingham         else if (frame_order == eFrameCompareEqual && InSymbol())
1445822173bSJim Ingham         {
1455822173bSJim Ingham             // If we are not in a place we should step through, we're done.
1465822173bSJim Ingham             // One tricky bit here is that some stubs don't push a frame, so we have to check
1475822173bSJim Ingham             // both the case of a frame that is younger, or the same as this frame.
1485822173bSJim Ingham             // However, if the frame is the same, and we are still in the symbol we started
1495822173bSJim Ingham             // in, the we don't need to do this.  This first check isn't strictly necessary,
1505822173bSJim Ingham             // but it is more efficient.
1515822173bSJim Ingham 
152564d8bc2SJim Ingham             // If we're still in the range, keep going, either by running to the next branch breakpoint, or by
153564d8bc2SJim Ingham             // stepping.
154564d8bc2SJim Ingham             if (InRange())
155564d8bc2SJim Ingham             {
156564d8bc2SJim Ingham                 SetNextBranchBreakpoint();
157564d8bc2SJim Ingham                 return false;
158564d8bc2SJim Ingham             }
159564d8bc2SJim Ingham 
1605822173bSJim Ingham             SetPlanComplete();
161c627682eSJim Ingham             m_no_more_plans = true;
1625822173bSJim Ingham             return true;
1635822173bSJim Ingham         }
1645822173bSJim Ingham 
165564d8bc2SJim Ingham         // If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it:
166564d8bc2SJim Ingham         ClearNextBranchBreakpoint();
167564d8bc2SJim Ingham 
1685822173bSJim Ingham         // We may have set the plan up above in the FrameIsOlder section:
1695822173bSJim Ingham 
1705822173bSJim Ingham         if (new_plan == NULL)
17118de2fdcSJim Ingham             new_plan = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
17208b87e0dSJim Ingham 
17308b87e0dSJim Ingham         if (log)
17408b87e0dSJim Ingham         {
17508b87e0dSJim Ingham             if (new_plan != NULL)
17608b87e0dSJim Ingham                 log->Printf ("Found a step through plan: %s", new_plan->GetName());
17708b87e0dSJim Ingham             else
17808b87e0dSJim Ingham                 log->Printf ("No step through plan found.");
17908b87e0dSJim Ingham         }
18008b87e0dSJim Ingham 
18130fdc8d8SChris Lattner         // If not, give the "should_stop" callback a chance to push a plan to get us out of here.
18230fdc8d8SChris Lattner         // But only do that if we actually have stepped in.
183b5c0d1ccSJim Ingham         if (!new_plan && frame_order == eFrameCompareYounger)
18430fdc8d8SChris Lattner             new_plan = InvokeShouldStopHereCallback();
18530fdc8d8SChris Lattner 
1867ce490c6SJim Ingham         // If we've stepped in and we are going to stop here, check to see if we were asked to
1877ce490c6SJim Ingham         // run past the prologue, and if so do that.
1887ce490c6SJim Ingham 
189b5c0d1ccSJim Ingham         if (new_plan == NULL && frame_order == eFrameCompareYounger && m_step_past_prologue)
1907ce490c6SJim Ingham         {
1917ce490c6SJim Ingham             lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0);
1927ce490c6SJim Ingham             if (curr_frame)
1937ce490c6SJim Ingham             {
1947ce490c6SJim Ingham                 size_t bytes_to_skip = 0;
1957ce490c6SJim Ingham                 lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC();
1967ce490c6SJim Ingham                 Address func_start_address;
1977ce490c6SJim Ingham 
1987ce490c6SJim Ingham                 SymbolContext sc = curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol);
1997ce490c6SJim Ingham 
2007ce490c6SJim Ingham                 if (sc.function)
2017ce490c6SJim Ingham                 {
2027ce490c6SJim Ingham                     func_start_address = sc.function->GetAddressRange().GetBaseAddress();
203d9e416c0SGreg Clayton                     if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
2047ce490c6SJim Ingham                         bytes_to_skip = sc.function->GetPrologueByteSize();
2057ce490c6SJim Ingham                 }
2067ce490c6SJim Ingham                 else if (sc.symbol)
2077ce490c6SJim Ingham                 {
208e7612134SGreg Clayton                     func_start_address = sc.symbol->GetAddress();
209d9e416c0SGreg Clayton                     if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
2107ce490c6SJim Ingham                         bytes_to_skip = sc.symbol->GetPrologueByteSize();
2117ce490c6SJim Ingham                 }
2127ce490c6SJim Ingham 
2137ce490c6SJim Ingham                 if (bytes_to_skip != 0)
2147ce490c6SJim Ingham                 {
2157ce490c6SJim Ingham                     func_start_address.Slide (bytes_to_skip);
21620ad3c40SCaroline Tice                     log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
2177ce490c6SJim Ingham                     if (log)
2187ce490c6SJim Ingham                         log->Printf ("Pushing past prologue ");
2197ce490c6SJim Ingham 
2207ce490c6SJim Ingham                     new_plan = m_thread.QueueThreadPlanForRunToAddress(false, func_start_address,true);
2217ce490c6SJim Ingham                 }
2227ce490c6SJim Ingham             }
2237ce490c6SJim Ingham         }
224f02a2e96SJim Ingham      }
2257ce490c6SJim Ingham 
22630fdc8d8SChris Lattner      if (new_plan == NULL)
22730fdc8d8SChris Lattner      {
22830fdc8d8SChris Lattner         m_no_more_plans = true;
22930fdc8d8SChris Lattner         SetPlanComplete();
23030fdc8d8SChris Lattner         return true;
23130fdc8d8SChris Lattner     }
23230fdc8d8SChris Lattner     else
23330fdc8d8SChris Lattner     {
23430fdc8d8SChris Lattner         m_no_more_plans = false;
23530fdc8d8SChris Lattner         return false;
23630fdc8d8SChris Lattner     }
23730fdc8d8SChris Lattner }
23830fdc8d8SChris Lattner 
23930fdc8d8SChris Lattner void
24030fdc8d8SChris Lattner ThreadPlanStepInRange::SetFlagsToDefault ()
24130fdc8d8SChris Lattner {
24230fdc8d8SChris Lattner     GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
24330fdc8d8SChris Lattner }
24430fdc8d8SChris Lattner 
24530fdc8d8SChris Lattner void
246a56c8006SJim Ingham ThreadPlanStepInRange::SetAvoidRegexp(const char *name)
247a56c8006SJim Ingham {
248a56c8006SJim Ingham     if (m_avoid_regexp_ap.get() == NULL)
249a56c8006SJim Ingham         m_avoid_regexp_ap.reset (new RegularExpression(name));
250a56c8006SJim Ingham 
251a56c8006SJim Ingham     m_avoid_regexp_ap->Compile (name);
252a56c8006SJim Ingham }
253a56c8006SJim Ingham 
254a56c8006SJim Ingham void
25530fdc8d8SChris Lattner ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value)
25630fdc8d8SChris Lattner {
25730fdc8d8SChris Lattner     // TODO: Should we test this for sanity?
25830fdc8d8SChris Lattner     ThreadPlanStepInRange::s_default_flag_values = new_value;
25930fdc8d8SChris Lattner }
26030fdc8d8SChris Lattner 
261a56c8006SJim Ingham bool
262a56c8006SJim Ingham ThreadPlanStepInRange::FrameMatchesAvoidRegexp ()
263a56c8006SJim Ingham {
264a56c8006SJim Ingham     StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
265a56c8006SJim Ingham 
26667cc0636SGreg Clayton     const RegularExpression *avoid_regexp_to_use = m_avoid_regexp_ap.get();
267ee8aea10SJim Ingham     if (avoid_regexp_to_use == NULL)
268ee8aea10SJim Ingham         avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp();
269ee8aea10SJim Ingham 
270ee8aea10SJim Ingham     if (avoid_regexp_to_use != NULL)
271a56c8006SJim Ingham     {
2724592cbc4SGreg Clayton         SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol);
273a56c8006SJim Ingham         if (sc.symbol != NULL)
274a56c8006SJim Ingham         {
2754592cbc4SGreg Clayton             const char *frame_function_name = sc.GetFunctionName().GetCString();
2764592cbc4SGreg Clayton             if (frame_function_name)
2774592cbc4SGreg Clayton                return avoid_regexp_to_use->Execute(frame_function_name);
278a56c8006SJim Ingham         }
279a56c8006SJim Ingham     }
280a56c8006SJim Ingham     return false;
281a56c8006SJim Ingham }
282a56c8006SJim Ingham 
28330fdc8d8SChris Lattner ThreadPlan *
28430fdc8d8SChris Lattner ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
28530fdc8d8SChris Lattner {
286a56c8006SJim Ingham     bool should_step_out = false;
28730fdc8d8SChris Lattner     StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
28830fdc8d8SChris Lattner 
28973b472d4SGreg Clayton     if (flags.Test(eAvoidNoDebug))
290a56c8006SJim Ingham     {
29130fdc8d8SChris Lattner         if (!frame->HasDebugInformation())
292af0f1759SJim Ingham         {
293513c6bb8SJim Ingham             LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
294af0f1759SJim Ingham             if (log)
295af0f1759SJim Ingham                 log->Printf ("Stepping out of frame with no debug info");
296af0f1759SJim Ingham 
297a56c8006SJim Ingham             should_step_out = true;
298a56c8006SJim Ingham         }
299af0f1759SJim Ingham     }
300a56c8006SJim Ingham 
301a56c8006SJim Ingham     if (current_plan->GetKind() == eKindStepInRange)
302a56c8006SJim Ingham     {
303a56c8006SJim Ingham         ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
304c627682eSJim Ingham         if (step_in_range_plan->m_step_into_target)
305c627682eSJim Ingham         {
306c627682eSJim Ingham             SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol);
307c627682eSJim Ingham             if (sc.symbol != NULL)
308c627682eSJim Ingham             {
309c627682eSJim Ingham                 // First try an exact match, since that's cheap with ConstStrings.  Then do a strstr compare.
310c627682eSJim Ingham                 if (step_in_range_plan->m_step_into_target == sc.GetFunctionName())
311c627682eSJim Ingham                 {
312c627682eSJim Ingham                     should_step_out = false;
313c627682eSJim Ingham                 }
314c627682eSJim Ingham                 else
315c627682eSJim Ingham                 {
316c627682eSJim Ingham                     const char *target_name = step_in_range_plan->m_step_into_target.AsCString();
317c627682eSJim Ingham                     const char *function_name = sc.GetFunctionName().AsCString();
318c627682eSJim Ingham 
319c627682eSJim Ingham                     if (function_name == NULL)
320c627682eSJim Ingham                         should_step_out = true;
321c627682eSJim Ingham                     else if (strstr (function_name, target_name) == NULL)
322c627682eSJim Ingham                         should_step_out = true;
323c627682eSJim Ingham                 }
324c627682eSJim Ingham             }
325c627682eSJim Ingham         }
326c627682eSJim Ingham 
327c627682eSJim Ingham         if (!should_step_out)
328c627682eSJim Ingham         {
329c627682eSJim Ingham                 ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
330a56c8006SJim Ingham                 should_step_out = step_in_range_plan->FrameMatchesAvoidRegexp ();
331a56c8006SJim Ingham         }
332a56c8006SJim Ingham     }
333a56c8006SJim Ingham 
334c627682eSJim Ingham 
335a56c8006SJim Ingham     if (should_step_out)
33630fdc8d8SChris Lattner     {
33730fdc8d8SChris Lattner         // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
3384a58e968SJim Ingham         // We really should have all plans take the tri-state for "stop others" so we can do the right
3394a58e968SJim Ingham         // thing.  For now let's be safe and always run others when we are likely to run arbitrary code.
3404a58e968SJim Ingham         const bool stop_others = false;
341481cef25SGreg Clayton         return current_plan->GetThread().QueueThreadPlanForStepOut (false,
342481cef25SGreg Clayton                                                                     NULL,
343481cef25SGreg Clayton                                                                     true,
3444a58e968SJim Ingham                                                                     stop_others,
345481cef25SGreg Clayton                                                                     eVoteNo,
346481cef25SGreg Clayton                                                                     eVoteNoOpinion,
347481cef25SGreg Clayton                                                                     0); // Frame index
34830fdc8d8SChris Lattner     }
34930fdc8d8SChris Lattner 
35030fdc8d8SChris Lattner     return NULL;
35130fdc8d8SChris Lattner }
352fbbfe6ecSJim Ingham 
353fbbfe6ecSJim Ingham bool
354fbbfe6ecSJim Ingham ThreadPlanStepInRange::PlanExplainsStop ()
355fbbfe6ecSJim Ingham {
356fbbfe6ecSJim Ingham     // We always explain a stop.  Either we've just done a single step, in which
357fbbfe6ecSJim Ingham     // case we'll do our ordinary processing, or we stopped for some
358fbbfe6ecSJim Ingham     // reason that isn't handled by our sub-plans, in which case we want to just stop right
359fbbfe6ecSJim Ingham     // away.
360c627682eSJim Ingham     // In general, we don't want to mark the plan as complete for unexplained stops.
361c627682eSJim Ingham     // For instance, if you step in to some code with no debug info, so you step out
362c627682eSJim Ingham     // and in the course of that hit a breakpoint, then you want to stop & show the user
363c627682eSJim Ingham     // the breakpoint, but not unship the step in plan, since you still may want to complete that
364c627682eSJim Ingham     // plan when you continue.  This is particularly true when doing "step in to target function."
365c627682eSJim Ingham     // stepping.
366fbbfe6ecSJim Ingham     //
367fbbfe6ecSJim Ingham     // The only variation is that if we are doing "step by running to next branch" in which case
368fbbfe6ecSJim Ingham     // if we hit our branch breakpoint we don't set the plan to complete.
369fbbfe6ecSJim Ingham 
370f02a2e96SJim Ingham     if (m_virtual_step)
371f02a2e96SJim Ingham         return true;
372f02a2e96SJim Ingham 
373fbbfe6ecSJim Ingham     StopInfoSP stop_info_sp = GetPrivateStopReason();
374fbbfe6ecSJim Ingham     if (stop_info_sp)
375fbbfe6ecSJim Ingham     {
376fbbfe6ecSJim Ingham         StopReason reason = stop_info_sp->GetStopReason();
377fbbfe6ecSJim Ingham 
378fbbfe6ecSJim Ingham         switch (reason)
379fbbfe6ecSJim Ingham         {
380fbbfe6ecSJim Ingham         case eStopReasonBreakpoint:
381fbbfe6ecSJim Ingham             if (NextRangeBreakpointExplainsStop(stop_info_sp))
382fbbfe6ecSJim Ingham                 return true;
383fbbfe6ecSJim Ingham         case eStopReasonWatchpoint:
384fbbfe6ecSJim Ingham         case eStopReasonSignal:
385fbbfe6ecSJim Ingham         case eStopReasonException:
38690ba8115SGreg Clayton         case eStopReasonExec:
387*f85defaeSAndrew Kaylor         case eStopReasonThreadExiting:
388513c6bb8SJim Ingham             {
389513c6bb8SJim Ingham                 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
390fbbfe6ecSJim Ingham                 if (log)
391fbbfe6ecSJim Ingham                     log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step.");
392513c6bb8SJim Ingham             }
393c627682eSJim Ingham             return false;
394fbbfe6ecSJim Ingham             break;
395fbbfe6ecSJim Ingham         default:
396fbbfe6ecSJim Ingham             break;
397fbbfe6ecSJim Ingham         }
398fbbfe6ecSJim Ingham     }
399fbbfe6ecSJim Ingham     return true;
400fbbfe6ecSJim Ingham }
401513c6bb8SJim Ingham 
402513c6bb8SJim Ingham bool
403513c6bb8SJim Ingham ThreadPlanStepInRange::WillResume (lldb::StateType resume_state, bool current_plan)
404513c6bb8SJim Ingham {
405513c6bb8SJim Ingham     if (resume_state == eStateStepping && current_plan)
406513c6bb8SJim Ingham     {
407513c6bb8SJim Ingham         // See if we are about to step over a virtual inlined call.
408513c6bb8SJim Ingham         bool step_without_resume = m_thread.DecrementCurrentInlinedDepth();
409513c6bb8SJim Ingham         if (step_without_resume)
410513c6bb8SJim Ingham         {
411513c6bb8SJim Ingham             LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
412513c6bb8SJim Ingham             if (log)
413513c6bb8SJim Ingham                 log->Printf ("ThreadPlanStepInRange::WillResume: returning false, inline_depth: %d",
414513c6bb8SJim Ingham                              m_thread.GetCurrentInlinedDepth());
415513c6bb8SJim Ingham             SetStopInfo(StopInfo::CreateStopReasonToTrace(m_thread));
416f02a2e96SJim Ingham 
417f02a2e96SJim Ingham             // FIXME: Maybe it would be better to create a InlineStep stop reason, but then
418f02a2e96SJim Ingham             // the whole rest of the world would have to handle that stop reason.
419f02a2e96SJim Ingham             m_virtual_step = true;
420513c6bb8SJim Ingham         }
421513c6bb8SJim Ingham         return !step_without_resume;
422513c6bb8SJim Ingham     }
423513c6bb8SJim Ingham     else
424513c6bb8SJim Ingham         return ThreadPlan::WillResume(resume_state, current_plan);
425513c6bb8SJim Ingham 
426513c6bb8SJim Ingham }
427