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"
194da6206dSJim Ingham #include "lldb/Core/Module.h"
2030fdc8d8SChris Lattner #include "lldb/Core/Stream.h"
21a56c8006SJim Ingham #include "lldb/Symbol/Symbol.h"
227ce490c6SJim Ingham #include "lldb/Symbol/Function.h"
2330fdc8d8SChris Lattner #include "lldb/Target/Process.h"
2430fdc8d8SChris Lattner #include "lldb/Target/RegisterContext.h"
25514487e8SGreg Clayton #include "lldb/Target/Target.h"
2630fdc8d8SChris Lattner #include "lldb/Target/Thread.h"
2730fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepOut.h"
2830fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepThrough.h"
29a56c8006SJim Ingham #include "lldb/Core/RegularExpression.h"
3030fdc8d8SChris Lattner 
3130fdc8d8SChris Lattner using namespace lldb;
3230fdc8d8SChris Lattner using namespace lldb_private;
3330fdc8d8SChris Lattner 
3430fdc8d8SChris Lattner uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eAvoidNoDebug;
3530fdc8d8SChris Lattner 
3630fdc8d8SChris Lattner //----------------------------------------------------------------------
3730fdc8d8SChris Lattner // ThreadPlanStepInRange: Step through a stack range, either stepping over or into
3830fdc8d8SChris Lattner // based on the value of \a type.
3930fdc8d8SChris Lattner //----------------------------------------------------------------------
4030fdc8d8SChris Lattner 
4130fdc8d8SChris Lattner ThreadPlanStepInRange::ThreadPlanStepInRange
4230fdc8d8SChris Lattner (
4330fdc8d8SChris Lattner     Thread &thread,
4430fdc8d8SChris Lattner     const AddressRange &range,
4530fdc8d8SChris Lattner     const SymbolContext &addr_context,
4630fdc8d8SChris Lattner     lldb::RunMode stop_others
4730fdc8d8SChris Lattner ) :
48b01e742aSJim Ingham     ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
497ce490c6SJim Ingham     ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
50f02a2e96SJim Ingham     m_step_past_prologue (true),
51f02a2e96SJim Ingham     m_virtual_step (false)
5230fdc8d8SChris Lattner {
5330fdc8d8SChris Lattner     SetFlagsToDefault ();
5430fdc8d8SChris Lattner }
5530fdc8d8SChris Lattner 
56c627682eSJim Ingham ThreadPlanStepInRange::ThreadPlanStepInRange
57c627682eSJim Ingham (
58c627682eSJim Ingham     Thread &thread,
59c627682eSJim Ingham     const AddressRange &range,
60c627682eSJim Ingham     const SymbolContext &addr_context,
61c627682eSJim Ingham     const char *step_into_target,
62c627682eSJim Ingham     lldb::RunMode stop_others
63c627682eSJim Ingham ) :
64c627682eSJim Ingham     ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
65c627682eSJim Ingham     ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
66c627682eSJim Ingham     m_step_past_prologue (true),
67c627682eSJim Ingham     m_virtual_step (false),
68c627682eSJim Ingham     m_step_into_target (step_into_target)
69c627682eSJim Ingham {
70c627682eSJim Ingham     SetFlagsToDefault ();
71c627682eSJim Ingham }
72c627682eSJim Ingham 
7330fdc8d8SChris Lattner ThreadPlanStepInRange::~ThreadPlanStepInRange ()
7430fdc8d8SChris Lattner {
7530fdc8d8SChris Lattner }
7630fdc8d8SChris Lattner 
7730fdc8d8SChris Lattner void
7830fdc8d8SChris Lattner ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
7930fdc8d8SChris Lattner {
8030fdc8d8SChris Lattner     if (level == lldb::eDescriptionLevelBrief)
8130fdc8d8SChris Lattner         s->Printf("step in");
8230fdc8d8SChris Lattner     else
8330fdc8d8SChris Lattner     {
8430fdc8d8SChris Lattner         s->Printf ("Stepping through range (stepping into functions): ");
85c4c9fedcSJim Ingham         DumpRanges(s);
864d56e9c1SJim Ingham         const char *step_into_target = m_step_into_target.AsCString();
874d56e9c1SJim Ingham         if (step_into_target && step_into_target[0] != '\0')
88c627682eSJim Ingham             s->Printf (" targeting %s.", m_step_into_target.AsCString());
894d56e9c1SJim Ingham         else
904d56e9c1SJim Ingham             s->PutChar('.');
9130fdc8d8SChris Lattner     }
9230fdc8d8SChris Lattner }
9330fdc8d8SChris Lattner 
9430fdc8d8SChris Lattner bool
9530fdc8d8SChris Lattner ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
9630fdc8d8SChris Lattner {
975160ce5cSGreg Clayton     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
9830fdc8d8SChris Lattner 
9930fdc8d8SChris Lattner     if (log)
10030fdc8d8SChris Lattner     {
10130fdc8d8SChris Lattner         StreamString s;
102514487e8SGreg Clayton         s.Address (m_thread.GetRegisterContext()->GetPC(),
1031ac04c30SGreg Clayton                    m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
10430fdc8d8SChris Lattner         log->Printf("ThreadPlanStepInRange reached %s.", s.GetData());
10530fdc8d8SChris Lattner     }
10630fdc8d8SChris Lattner 
10725f66700SJim Ingham     if (IsPlanComplete())
10825f66700SJim Ingham         return true;
10925f66700SJim Ingham 
1104d56e9c1SJim Ingham     m_no_more_plans = false;
1114d56e9c1SJim Ingham     if (m_sub_plan_sp && m_sub_plan_sp->IsPlanComplete())
1124d56e9c1SJim Ingham     {
1134d56e9c1SJim Ingham         if (!m_sub_plan_sp->PlanSucceeded())
1144d56e9c1SJim Ingham         {
1154d56e9c1SJim Ingham             SetPlanComplete();
1164d56e9c1SJim Ingham             m_no_more_plans = true;
1174d56e9c1SJim Ingham             return true;
1184d56e9c1SJim Ingham         }
1194d56e9c1SJim Ingham         else
1204d56e9c1SJim Ingham             m_sub_plan_sp.reset();
1214d56e9c1SJim Ingham     }
12230fdc8d8SChris Lattner 
123f02a2e96SJim Ingham     if (m_virtual_step)
124f02a2e96SJim Ingham     {
125f02a2e96SJim Ingham         // If we've just completed a virtual step, all we need to do is check for a ShouldStopHere plan, and otherwise
126f02a2e96SJim Ingham         // we're done.
1274d56e9c1SJim Ingham         m_sub_plan_sp = InvokeShouldStopHereCallback();
128f02a2e96SJim Ingham     }
129f02a2e96SJim Ingham     else
130f02a2e96SJim Ingham     {
1314a58e968SJim Ingham         // Stepping through should be done running other threads in general, since we're setting a breakpoint and
1324a58e968SJim Ingham         // continuing.  So only stop others if we are explicitly told to do so.
1339d790c5dSJim Ingham 
13430fdc8d8SChris Lattner         bool stop_others;
1354a58e968SJim Ingham         if (m_stop_others == lldb::eOnlyThisThread)
1364a58e968SJim Ingham             stop_others = true;
1376cf5b8f1SEd Maste         else
1386cf5b8f1SEd Maste             stop_others = false;
13930fdc8d8SChris Lattner 
140b5c0d1ccSJim Ingham         FrameComparison frame_order = CompareCurrentFrameToStartFrame();
141b5c0d1ccSJim Ingham 
142b5c0d1ccSJim Ingham         if (frame_order == eFrameCompareOlder)
1435822173bSJim Ingham         {
1445822173bSJim Ingham             // If we're in an older frame then we should stop.
1455822173bSJim Ingham             //
1465822173bSJim Ingham             // A caveat to this is if we think the frame is older but we're actually in a trampoline.
1475822173bSJim Ingham             // I'm going to make the assumption that you wouldn't RETURN to a trampoline.  So if we are
1485822173bSJim Ingham             // in a trampoline we think the frame is older because the trampoline confused the backtracer.
1494d56e9c1SJim Ingham             m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
1504d56e9c1SJim Ingham             if (!m_sub_plan_sp)
1515822173bSJim Ingham                 return true;
1525822173bSJim Ingham             else if (log)
1535822173bSJim Ingham             {
1545822173bSJim Ingham                 log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
1555822173bSJim Ingham             }
1565822173bSJim Ingham 
1575822173bSJim Ingham         }
158564d8bc2SJim Ingham         else if (frame_order == eFrameCompareEqual && InSymbol())
1595822173bSJim Ingham         {
1605822173bSJim Ingham             // If we are not in a place we should step through, we're done.
1615822173bSJim Ingham             // One tricky bit here is that some stubs don't push a frame, so we have to check
1625822173bSJim Ingham             // both the case of a frame that is younger, or the same as this frame.
1635822173bSJim Ingham             // However, if the frame is the same, and we are still in the symbol we started
1645822173bSJim Ingham             // in, the we don't need to do this.  This first check isn't strictly necessary,
1655822173bSJim Ingham             // but it is more efficient.
1665822173bSJim Ingham 
167564d8bc2SJim Ingham             // If we're still in the range, keep going, either by running to the next branch breakpoint, or by
168564d8bc2SJim Ingham             // stepping.
169564d8bc2SJim Ingham             if (InRange())
170564d8bc2SJim Ingham             {
171564d8bc2SJim Ingham                 SetNextBranchBreakpoint();
172564d8bc2SJim Ingham                 return false;
173564d8bc2SJim Ingham             }
174564d8bc2SJim Ingham 
1755822173bSJim Ingham             SetPlanComplete();
176c627682eSJim Ingham             m_no_more_plans = true;
1775822173bSJim Ingham             return true;
1785822173bSJim Ingham         }
1795822173bSJim Ingham 
180564d8bc2SJim Ingham         // If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it:
181564d8bc2SJim Ingham         ClearNextBranchBreakpoint();
182564d8bc2SJim Ingham 
1835822173bSJim Ingham         // We may have set the plan up above in the FrameIsOlder section:
1845822173bSJim Ingham 
1854d56e9c1SJim Ingham         if (!m_sub_plan_sp)
1864d56e9c1SJim Ingham             m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
18708b87e0dSJim Ingham 
18808b87e0dSJim Ingham         if (log)
18908b87e0dSJim Ingham         {
1904d56e9c1SJim Ingham             if (m_sub_plan_sp)
1914d56e9c1SJim Ingham                 log->Printf ("Found a step through plan: %s", m_sub_plan_sp->GetName());
19208b87e0dSJim Ingham             else
19308b87e0dSJim Ingham                 log->Printf ("No step through plan found.");
19408b87e0dSJim Ingham         }
19508b87e0dSJim Ingham 
19630fdc8d8SChris Lattner         // If not, give the "should_stop" callback a chance to push a plan to get us out of here.
19730fdc8d8SChris Lattner         // But only do that if we actually have stepped in.
1984d56e9c1SJim Ingham         if (!m_sub_plan_sp && frame_order == eFrameCompareYounger)
1994d56e9c1SJim Ingham             m_sub_plan_sp = InvokeShouldStopHereCallback();
20030fdc8d8SChris Lattner 
2017ce490c6SJim Ingham         // If we've stepped in and we are going to stop here, check to see if we were asked to
2027ce490c6SJim Ingham         // run past the prologue, and if so do that.
2037ce490c6SJim Ingham 
2044d56e9c1SJim Ingham         if (!m_sub_plan_sp && frame_order == eFrameCompareYounger && m_step_past_prologue)
2057ce490c6SJim Ingham         {
206b57e4a1bSJason Molenda             lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0);
2077ce490c6SJim Ingham             if (curr_frame)
2087ce490c6SJim Ingham             {
2097ce490c6SJim Ingham                 size_t bytes_to_skip = 0;
2107ce490c6SJim Ingham                 lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC();
2117ce490c6SJim Ingham                 Address func_start_address;
2127ce490c6SJim Ingham 
2137ce490c6SJim Ingham                 SymbolContext sc = curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol);
2147ce490c6SJim Ingham 
2157ce490c6SJim Ingham                 if (sc.function)
2167ce490c6SJim Ingham                 {
2177ce490c6SJim Ingham                     func_start_address = sc.function->GetAddressRange().GetBaseAddress();
218d9e416c0SGreg Clayton                     if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
2197ce490c6SJim Ingham                         bytes_to_skip = sc.function->GetPrologueByteSize();
2207ce490c6SJim Ingham                 }
2217ce490c6SJim Ingham                 else if (sc.symbol)
2227ce490c6SJim Ingham                 {
223e7612134SGreg Clayton                     func_start_address = sc.symbol->GetAddress();
224d9e416c0SGreg Clayton                     if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
2257ce490c6SJim Ingham                         bytes_to_skip = sc.symbol->GetPrologueByteSize();
2267ce490c6SJim Ingham                 }
2277ce490c6SJim Ingham 
2287ce490c6SJim Ingham                 if (bytes_to_skip != 0)
2297ce490c6SJim Ingham                 {
2307ce490c6SJim Ingham                     func_start_address.Slide (bytes_to_skip);
23120ad3c40SCaroline Tice                     log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
2327ce490c6SJim Ingham                     if (log)
2337ce490c6SJim Ingham                         log->Printf ("Pushing past prologue ");
2347ce490c6SJim Ingham 
2354d56e9c1SJim Ingham                     m_sub_plan_sp = m_thread.QueueThreadPlanForRunToAddress(false, func_start_address,true);
2367ce490c6SJim Ingham                 }
2377ce490c6SJim Ingham             }
2387ce490c6SJim Ingham         }
239f02a2e96SJim Ingham      }
2407ce490c6SJim Ingham 
2414d56e9c1SJim Ingham      if (!m_sub_plan_sp)
24230fdc8d8SChris Lattner      {
24330fdc8d8SChris Lattner         m_no_more_plans = true;
24430fdc8d8SChris Lattner         SetPlanComplete();
24530fdc8d8SChris Lattner         return true;
24630fdc8d8SChris Lattner     }
24730fdc8d8SChris Lattner     else
24830fdc8d8SChris Lattner     {
24930fdc8d8SChris Lattner         m_no_more_plans = false;
25030fdc8d8SChris Lattner         return false;
25130fdc8d8SChris Lattner     }
25230fdc8d8SChris Lattner }
25330fdc8d8SChris Lattner 
25430fdc8d8SChris Lattner void
25530fdc8d8SChris Lattner ThreadPlanStepInRange::SetFlagsToDefault ()
25630fdc8d8SChris Lattner {
25730fdc8d8SChris Lattner     GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
25830fdc8d8SChris Lattner }
25930fdc8d8SChris Lattner 
26030fdc8d8SChris Lattner void
261a56c8006SJim Ingham ThreadPlanStepInRange::SetAvoidRegexp(const char *name)
262a56c8006SJim Ingham {
263a56c8006SJim Ingham     if (m_avoid_regexp_ap.get() == NULL)
264a56c8006SJim Ingham         m_avoid_regexp_ap.reset (new RegularExpression(name));
265a56c8006SJim Ingham 
266a56c8006SJim Ingham     m_avoid_regexp_ap->Compile (name);
267a56c8006SJim Ingham }
268a56c8006SJim Ingham 
269a56c8006SJim Ingham void
27030fdc8d8SChris Lattner ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value)
27130fdc8d8SChris Lattner {
27230fdc8d8SChris Lattner     // TODO: Should we test this for sanity?
27330fdc8d8SChris Lattner     ThreadPlanStepInRange::s_default_flag_values = new_value;
27430fdc8d8SChris Lattner }
27530fdc8d8SChris Lattner 
276a56c8006SJim Ingham bool
2774da6206dSJim Ingham ThreadPlanStepInRange::FrameMatchesAvoidCriteria ()
278a56c8006SJim Ingham {
279b57e4a1bSJason Molenda     StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
280a56c8006SJim Ingham 
2814da6206dSJim Ingham     // Check the library list first, as that's cheapest:
282*a786e539SJim Ingham     bool libraries_say_avoid = false;
283*a786e539SJim Ingham 
2844da6206dSJim Ingham     FileSpecList libraries_to_avoid (GetThread().GetLibrariesToAvoid());
2854da6206dSJim Ingham     size_t num_libraries = libraries_to_avoid.GetSize();
286*a786e539SJim Ingham     if (num_libraries > 0)
287*a786e539SJim Ingham     {
2884da6206dSJim Ingham         SymbolContext sc(frame->GetSymbolContext(eSymbolContextModule));
2894da6206dSJim Ingham         FileSpec frame_library(sc.module_sp->GetFileSpec());
2904da6206dSJim Ingham 
2914da6206dSJim Ingham         if (frame_library)
2924da6206dSJim Ingham         {
2934da6206dSJim Ingham             for (size_t i = 0; i < num_libraries; i++)
2944da6206dSJim Ingham             {
2954da6206dSJim Ingham                 const FileSpec &file_spec(libraries_to_avoid.GetFileSpecAtIndex(i));
2964da6206dSJim Ingham                 if (FileSpec::Equal (file_spec, frame_library, false))
2974da6206dSJim Ingham                 {
2984da6206dSJim Ingham                     libraries_say_avoid = true;
2994da6206dSJim Ingham                     break;
3004da6206dSJim Ingham                 }
3014da6206dSJim Ingham             }
3024da6206dSJim Ingham         }
303*a786e539SJim Ingham     }
3044da6206dSJim Ingham     if (libraries_say_avoid)
3054da6206dSJim Ingham         return true;
3064da6206dSJim Ingham 
30767cc0636SGreg Clayton     const RegularExpression *avoid_regexp_to_use = m_avoid_regexp_ap.get();
308ee8aea10SJim Ingham     if (avoid_regexp_to_use == NULL)
309ee8aea10SJim Ingham         avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp();
310ee8aea10SJim Ingham 
311ee8aea10SJim Ingham     if (avoid_regexp_to_use != NULL)
312a56c8006SJim Ingham     {
3134592cbc4SGreg Clayton         SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol);
314a56c8006SJim Ingham         if (sc.symbol != NULL)
315a56c8006SJim Ingham         {
3164592cbc4SGreg Clayton             const char *frame_function_name = sc.GetFunctionName().GetCString();
3174592cbc4SGreg Clayton             if (frame_function_name)
3183101ba33SJim Ingham             {
319cf2667c4SJim Ingham                 size_t num_matches = 0;
3205160ce5cSGreg Clayton                 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
3213101ba33SJim Ingham                 if (log)
322cf2667c4SJim Ingham                     num_matches = 1;
323bc43cab5SGreg Clayton 
324bc43cab5SGreg Clayton                 RegularExpression::Match regex_match(num_matches);
325bc43cab5SGreg Clayton 
326bc43cab5SGreg Clayton                 bool return_value = avoid_regexp_to_use->Execute(frame_function_name, &regex_match);
327cf2667c4SJim Ingham                 if (return_value)
328cf2667c4SJim Ingham                 {
329cf2667c4SJim Ingham                     if (log)
330cf2667c4SJim Ingham                     {
331cf2667c4SJim Ingham                         std::string match;
332bc43cab5SGreg Clayton                         regex_match.GetMatchAtIndex(frame_function_name,0, match);
333cf2667c4SJim Ingham                         log->Printf ("Stepping out of function \"%s\" because it matches the avoid regexp \"%s\" - match substring: \"%s\".",
3343101ba33SJim Ingham                                      frame_function_name,
335cf2667c4SJim Ingham                                      avoid_regexp_to_use->GetText(),
336cf2667c4SJim Ingham                                      match.c_str());
337cf2667c4SJim Ingham                     }
3383101ba33SJim Ingham 
3393101ba33SJim Ingham                 }
3403101ba33SJim Ingham                 return return_value;
3413101ba33SJim Ingham             }
342a56c8006SJim Ingham         }
343a56c8006SJim Ingham     }
344a56c8006SJim Ingham     return false;
345a56c8006SJim Ingham }
346a56c8006SJim Ingham 
3474d56e9c1SJim Ingham ThreadPlanSP
34830fdc8d8SChris Lattner ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
34930fdc8d8SChris Lattner {
350a56c8006SJim Ingham     bool should_step_out = false;
351b57e4a1bSJason Molenda     StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
3525160ce5cSGreg Clayton     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
35330fdc8d8SChris Lattner 
35473b472d4SGreg Clayton     if (flags.Test(eAvoidNoDebug))
355a56c8006SJim Ingham     {
35630fdc8d8SChris Lattner         if (!frame->HasDebugInformation())
357af0f1759SJim Ingham         {
358af0f1759SJim Ingham             if (log)
359af0f1759SJim Ingham                 log->Printf ("Stepping out of frame with no debug info");
360af0f1759SJim Ingham 
361a56c8006SJim Ingham             should_step_out = true;
362a56c8006SJim Ingham         }
363af0f1759SJim Ingham     }
364a56c8006SJim Ingham 
365a56c8006SJim Ingham     if (current_plan->GetKind() == eKindStepInRange)
366a56c8006SJim Ingham     {
367a56c8006SJim Ingham         ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
368c627682eSJim Ingham         if (step_in_range_plan->m_step_into_target)
369c627682eSJim Ingham         {
370c627682eSJim Ingham             SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol);
371c627682eSJim Ingham             if (sc.symbol != NULL)
372c627682eSJim Ingham             {
373c627682eSJim Ingham                 // First try an exact match, since that's cheap with ConstStrings.  Then do a strstr compare.
374c627682eSJim Ingham                 if (step_in_range_plan->m_step_into_target == sc.GetFunctionName())
375c627682eSJim Ingham                 {
376c627682eSJim Ingham                     should_step_out = false;
377c627682eSJim Ingham                 }
378c627682eSJim Ingham                 else
379c627682eSJim Ingham                 {
380c627682eSJim Ingham                     const char *target_name = step_in_range_plan->m_step_into_target.AsCString();
381c627682eSJim Ingham                     const char *function_name = sc.GetFunctionName().AsCString();
382c627682eSJim Ingham 
383c627682eSJim Ingham                     if (function_name == NULL)
384c627682eSJim Ingham                         should_step_out = true;
385c627682eSJim Ingham                     else if (strstr (function_name, target_name) == NULL)
386c627682eSJim Ingham                         should_step_out = true;
387c627682eSJim Ingham                 }
3883101ba33SJim Ingham                 if (log && should_step_out)
3893101ba33SJim Ingham                     log->Printf("Stepping out of frame %s which did not match step into target %s.",
3903101ba33SJim Ingham                                 sc.GetFunctionName().AsCString(),
3913101ba33SJim Ingham                                 step_in_range_plan->m_step_into_target.AsCString());
392c627682eSJim Ingham             }
393c627682eSJim Ingham         }
394c627682eSJim Ingham 
395c627682eSJim Ingham         if (!should_step_out)
396c627682eSJim Ingham         {
397c627682eSJim Ingham             ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
3984da6206dSJim Ingham             // Don't log the should_step_out here, it's easier to do it in FrameMatchesAvoidCriteria.
3994da6206dSJim Ingham             should_step_out = step_in_range_plan->FrameMatchesAvoidCriteria ();
400a56c8006SJim Ingham         }
401a56c8006SJim Ingham     }
402a56c8006SJim Ingham 
403c627682eSJim Ingham 
404a56c8006SJim Ingham     if (should_step_out)
40530fdc8d8SChris Lattner     {
40630fdc8d8SChris Lattner         // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
4074a58e968SJim Ingham         // We really should have all plans take the tri-state for "stop others" so we can do the right
4084a58e968SJim Ingham         // thing.  For now let's be safe and always run others when we are likely to run arbitrary code.
4094a58e968SJim Ingham         const bool stop_others = false;
410481cef25SGreg Clayton         return current_plan->GetThread().QueueThreadPlanForStepOut (false,
411481cef25SGreg Clayton                                                                     NULL,
412481cef25SGreg Clayton                                                                     true,
4134a58e968SJim Ingham                                                                     stop_others,
414481cef25SGreg Clayton                                                                     eVoteNo,
415481cef25SGreg Clayton                                                                     eVoteNoOpinion,
416481cef25SGreg Clayton                                                                     0); // Frame index
41730fdc8d8SChris Lattner     }
41830fdc8d8SChris Lattner 
4194d56e9c1SJim Ingham     return ThreadPlanSP();
42030fdc8d8SChris Lattner }
421fbbfe6ecSJim Ingham 
422fbbfe6ecSJim Ingham bool
423221d51cfSJim Ingham ThreadPlanStepInRange::DoPlanExplainsStop (Event *event_ptr)
424fbbfe6ecSJim Ingham {
425fbbfe6ecSJim Ingham     // We always explain a stop.  Either we've just done a single step, in which
426fbbfe6ecSJim Ingham     // case we'll do our ordinary processing, or we stopped for some
427fbbfe6ecSJim Ingham     // reason that isn't handled by our sub-plans, in which case we want to just stop right
428fbbfe6ecSJim Ingham     // away.
429c627682eSJim Ingham     // In general, we don't want to mark the plan as complete for unexplained stops.
430c627682eSJim Ingham     // For instance, if you step in to some code with no debug info, so you step out
431c627682eSJim Ingham     // and in the course of that hit a breakpoint, then you want to stop & show the user
432c627682eSJim Ingham     // the breakpoint, but not unship the step in plan, since you still may want to complete that
433c627682eSJim Ingham     // plan when you continue.  This is particularly true when doing "step in to target function."
434c627682eSJim Ingham     // stepping.
435fbbfe6ecSJim Ingham     //
436fbbfe6ecSJim Ingham     // The only variation is that if we are doing "step by running to next branch" in which case
437fbbfe6ecSJim Ingham     // if we hit our branch breakpoint we don't set the plan to complete.
438fbbfe6ecSJim Ingham 
439221d51cfSJim Ingham     bool return_value;
440f02a2e96SJim Ingham 
441221d51cfSJim Ingham     if (m_virtual_step)
442221d51cfSJim Ingham     {
443221d51cfSJim Ingham         return_value = true;
444221d51cfSJim Ingham     }
445221d51cfSJim Ingham     else
446221d51cfSJim Ingham     {
44760c4118cSJim Ingham         StopInfoSP stop_info_sp = GetPrivateStopInfo ();
448fbbfe6ecSJim Ingham         if (stop_info_sp)
449fbbfe6ecSJim Ingham         {
450fbbfe6ecSJim Ingham             StopReason reason = stop_info_sp->GetStopReason();
451fbbfe6ecSJim Ingham 
452fbbfe6ecSJim Ingham             switch (reason)
453fbbfe6ecSJim Ingham             {
454fbbfe6ecSJim Ingham             case eStopReasonBreakpoint:
455fbbfe6ecSJim Ingham                 if (NextRangeBreakpointExplainsStop(stop_info_sp))
456221d51cfSJim Ingham                 {
457221d51cfSJim Ingham                     return_value = true;
458221d51cfSJim Ingham                     break;
459221d51cfSJim Ingham                 }
460fbbfe6ecSJim Ingham             case eStopReasonWatchpoint:
461fbbfe6ecSJim Ingham             case eStopReasonSignal:
462fbbfe6ecSJim Ingham             case eStopReasonException:
46390ba8115SGreg Clayton             case eStopReasonExec:
464f85defaeSAndrew Kaylor             case eStopReasonThreadExiting:
465513c6bb8SJim Ingham                 {
4665160ce5cSGreg Clayton                     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
467fbbfe6ecSJim Ingham                     if (log)
468fbbfe6ecSJim Ingham                         log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step.");
469513c6bb8SJim Ingham                 }
470221d51cfSJim Ingham                 return_value = false;
471fbbfe6ecSJim Ingham                 break;
472fbbfe6ecSJim Ingham             default:
473221d51cfSJim Ingham                 return_value = true;
474fbbfe6ecSJim Ingham                 break;
475fbbfe6ecSJim Ingham             }
476fbbfe6ecSJim Ingham         }
477221d51cfSJim Ingham         else
478221d51cfSJim Ingham             return_value = true;
479221d51cfSJim Ingham     }
480221d51cfSJim Ingham 
481221d51cfSJim Ingham     return return_value;
482fbbfe6ecSJim Ingham }
483513c6bb8SJim Ingham 
484513c6bb8SJim Ingham bool
485221d51cfSJim Ingham ThreadPlanStepInRange::DoWillResume (lldb::StateType resume_state, bool current_plan)
486513c6bb8SJim Ingham {
487513c6bb8SJim Ingham     if (resume_state == eStateStepping && current_plan)
488513c6bb8SJim Ingham     {
489513c6bb8SJim Ingham         // See if we are about to step over a virtual inlined call.
490513c6bb8SJim Ingham         bool step_without_resume = m_thread.DecrementCurrentInlinedDepth();
491513c6bb8SJim Ingham         if (step_without_resume)
492513c6bb8SJim Ingham         {
4935160ce5cSGreg Clayton             Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
494513c6bb8SJim Ingham             if (log)
495221d51cfSJim Ingham                 log->Printf ("ThreadPlanStepInRange::DoWillResume: returning false, inline_depth: %d",
496513c6bb8SJim Ingham                              m_thread.GetCurrentInlinedDepth());
497513c6bb8SJim Ingham             SetStopInfo(StopInfo::CreateStopReasonToTrace(m_thread));
498f02a2e96SJim Ingham 
499f02a2e96SJim Ingham             // FIXME: Maybe it would be better to create a InlineStep stop reason, but then
500f02a2e96SJim Ingham             // the whole rest of the world would have to handle that stop reason.
501f02a2e96SJim Ingham             m_virtual_step = true;
502513c6bb8SJim Ingham         }
503513c6bb8SJim Ingham         return !step_without_resume;
504513c6bb8SJim Ingham     }
505221d51cfSJim Ingham     return true;
506513c6bb8SJim Ingham }
507246cb611SDaniel Malea 
508246cb611SDaniel Malea bool
509246cb611SDaniel Malea ThreadPlanStepInRange::IsVirtualStep()
510246cb611SDaniel Malea {
511246cb611SDaniel Malea   return m_virtual_step;
512246cb611SDaniel Malea }
513