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 
10e65b2cf2SEugene Zelenko #include "lldb/Target/ThreadPlanStepInRange.h"
1108581263SJim Ingham #include "lldb/Core/Architecture.h"
124da6206dSJim Ingham #include "lldb/Core/Module.h"
137ce490c6SJim Ingham #include "lldb/Symbol/Function.h"
14b9c1b51eSKate Stone #include "lldb/Symbol/Symbol.h"
1530fdc8d8SChris Lattner #include "lldb/Target/Process.h"
1630fdc8d8SChris Lattner #include "lldb/Target/RegisterContext.h"
1708581263SJim Ingham #include "lldb/Target/SectionLoadList.h"
18514487e8SGreg Clayton #include "lldb/Target/Target.h"
1930fdc8d8SChris Lattner #include "lldb/Target/Thread.h"
2030fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepOut.h"
2130fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepThrough.h"
226f9e6901SZachary Turner #include "lldb/Utility/Log.h"
23bf9a7730SZachary Turner #include "lldb/Utility/RegularExpression.h"
24bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
2530fdc8d8SChris Lattner 
2630fdc8d8SChris Lattner using namespace lldb;
2730fdc8d8SChris Lattner using namespace lldb_private;
2830fdc8d8SChris Lattner 
29b9c1b51eSKate Stone uint32_t ThreadPlanStepInRange::s_default_flag_values =
30b9c1b51eSKate Stone     ThreadPlanShouldStopHere::eStepInAvoidNoDebug;
3130fdc8d8SChris Lattner 
3230fdc8d8SChris Lattner //----------------------------------------------------------------------
33b9c1b51eSKate Stone // ThreadPlanStepInRange: Step through a stack range, either stepping over or
3405097246SAdrian Prantl // into based on the value of \a type.
3530fdc8d8SChris Lattner //----------------------------------------------------------------------
3630fdc8d8SChris Lattner 
37b9c1b51eSKate Stone ThreadPlanStepInRange::ThreadPlanStepInRange(
38b9c1b51eSKate Stone     Thread &thread, const AddressRange &range,
39b9c1b51eSKate Stone     const SymbolContext &addr_context, lldb::RunMode stop_others,
404b4b2478SJim Ingham     LazyBool step_in_avoids_code_without_debug_info,
41b9c1b51eSKate Stone     LazyBool step_out_avoids_code_without_debug_info)
42b9c1b51eSKate Stone     : ThreadPlanStepRange(ThreadPlan::eKindStepInRange,
43b9c1b51eSKate Stone                           "Step Range stepping in", thread, range, addr_context,
44b9c1b51eSKate Stone                           stop_others),
45b9c1b51eSKate Stone       ThreadPlanShouldStopHere(this), m_step_past_prologue(true),
46b9c1b51eSKate Stone       m_virtual_step(false) {
474b4b2478SJim Ingham   SetCallbacks();
4830fdc8d8SChris Lattner   SetFlagsToDefault();
49b9c1b51eSKate Stone   SetupAvoidNoDebug(step_in_avoids_code_without_debug_info,
50b9c1b51eSKate Stone                     step_out_avoids_code_without_debug_info);
5130fdc8d8SChris Lattner }
5230fdc8d8SChris Lattner 
53b9c1b51eSKate Stone ThreadPlanStepInRange::ThreadPlanStepInRange(
54b9c1b51eSKate Stone     Thread &thread, const AddressRange &range,
55b9c1b51eSKate Stone     const SymbolContext &addr_context, const char *step_into_target,
56b9c1b51eSKate Stone     lldb::RunMode stop_others, LazyBool step_in_avoids_code_without_debug_info,
57b9c1b51eSKate Stone     LazyBool step_out_avoids_code_without_debug_info)
58b9c1b51eSKate Stone     : ThreadPlanStepRange(ThreadPlan::eKindStepInRange,
59b9c1b51eSKate Stone                           "Step Range stepping in", thread, range, addr_context,
60b9c1b51eSKate Stone                           stop_others),
61b9c1b51eSKate Stone       ThreadPlanShouldStopHere(this), m_step_past_prologue(true),
62b9c1b51eSKate Stone       m_virtual_step(false), m_step_into_target(step_into_target) {
634b4b2478SJim Ingham   SetCallbacks();
64c627682eSJim Ingham   SetFlagsToDefault();
65b9c1b51eSKate Stone   SetupAvoidNoDebug(step_in_avoids_code_without_debug_info,
66b9c1b51eSKate Stone                     step_out_avoids_code_without_debug_info);
67c627682eSJim Ingham }
68c627682eSJim Ingham 
69e65b2cf2SEugene Zelenko ThreadPlanStepInRange::~ThreadPlanStepInRange() = default;
7030fdc8d8SChris Lattner 
71b9c1b51eSKate Stone void ThreadPlanStepInRange::SetupAvoidNoDebug(
72b9c1b51eSKate Stone     LazyBool step_in_avoids_code_without_debug_info,
73b9c1b51eSKate Stone     LazyBool step_out_avoids_code_without_debug_info) {
744b4b2478SJim Ingham   bool avoid_nodebug = true;
754b4b2478SJim Ingham 
76b9c1b51eSKate Stone   switch (step_in_avoids_code_without_debug_info) {
774b4b2478SJim Ingham   case eLazyBoolYes:
784b4b2478SJim Ingham     avoid_nodebug = true;
794b4b2478SJim Ingham     break;
804b4b2478SJim Ingham   case eLazyBoolNo:
814b4b2478SJim Ingham     avoid_nodebug = false;
824b4b2478SJim Ingham     break;
834b4b2478SJim Ingham   case eLazyBoolCalculate:
844b4b2478SJim Ingham     avoid_nodebug = m_thread.GetStepInAvoidsNoDebug();
854b4b2478SJim Ingham     break;
864b4b2478SJim Ingham   }
874b4b2478SJim Ingham   if (avoid_nodebug)
884b4b2478SJim Ingham     GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
894b4b2478SJim Ingham   else
904b4b2478SJim Ingham     GetFlags().Clear(ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
914b4b2478SJim Ingham 
92b9c1b51eSKate Stone   switch (step_out_avoids_code_without_debug_info) {
934b4b2478SJim Ingham   case eLazyBoolYes:
944b4b2478SJim Ingham     avoid_nodebug = true;
954b4b2478SJim Ingham     break;
964b4b2478SJim Ingham   case eLazyBoolNo:
974b4b2478SJim Ingham     avoid_nodebug = false;
984b4b2478SJim Ingham     break;
994b4b2478SJim Ingham   case eLazyBoolCalculate:
1004b4b2478SJim Ingham     avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug();
1014b4b2478SJim Ingham     break;
1024b4b2478SJim Ingham   }
1034b4b2478SJim Ingham   if (avoid_nodebug)
1044b4b2478SJim Ingham     GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
1054b4b2478SJim Ingham   else
1064b4b2478SJim Ingham     GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
1074b4b2478SJim Ingham }
1084b4b2478SJim Ingham 
109b9c1b51eSKate Stone void ThreadPlanStepInRange::GetDescription(Stream *s,
110b9c1b51eSKate Stone                                            lldb::DescriptionLevel level) {
111*e103ae92SJonas Devlieghere 
112*e103ae92SJonas Devlieghere   auto PrintFailureIfAny = [&]() {
113*e103ae92SJonas Devlieghere     if (m_status.Success())
114*e103ae92SJonas Devlieghere       return;
115*e103ae92SJonas Devlieghere     s->Printf(" failed (%s)", m_status.AsCString());
116*e103ae92SJonas Devlieghere   };
117*e103ae92SJonas Devlieghere 
118b9c1b51eSKate Stone   if (level == lldb::eDescriptionLevelBrief) {
1192bdbfd50SJim Ingham     s->Printf("step in");
120*e103ae92SJonas Devlieghere     PrintFailureIfAny();
1212bdbfd50SJim Ingham     return;
1222bdbfd50SJim Ingham   }
1232bdbfd50SJim Ingham 
1242bdbfd50SJim Ingham   s->Printf("Stepping in");
1252bdbfd50SJim Ingham   bool printed_line_info = false;
126b9c1b51eSKate Stone   if (m_addr_context.line_entry.IsValid()) {
1272bdbfd50SJim Ingham     s->Printf(" through line ");
1282bdbfd50SJim Ingham     m_addr_context.line_entry.DumpStopContext(s, false);
1292bdbfd50SJim Ingham     printed_line_info = true;
1302bdbfd50SJim Ingham   }
1312bdbfd50SJim Ingham 
1324d56e9c1SJim Ingham   const char *step_into_target = m_step_into_target.AsCString();
1334d56e9c1SJim Ingham   if (step_into_target && step_into_target[0] != '\0')
1342bdbfd50SJim Ingham     s->Printf(" targeting %s", m_step_into_target.AsCString());
1352bdbfd50SJim Ingham 
136b9c1b51eSKate Stone   if (!printed_line_info || level == eDescriptionLevelVerbose) {
1372bdbfd50SJim Ingham     s->Printf(" using ranges:");
1382bdbfd50SJim Ingham     DumpRanges(s);
13930fdc8d8SChris Lattner   }
1402bdbfd50SJim Ingham 
141*e103ae92SJonas Devlieghere   PrintFailureIfAny();
142*e103ae92SJonas Devlieghere 
1432bdbfd50SJim Ingham   s->PutChar('.');
14430fdc8d8SChris Lattner }
14530fdc8d8SChris Lattner 
146b9c1b51eSKate Stone bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
1475160ce5cSGreg Clayton   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
14830fdc8d8SChris Lattner 
149b9c1b51eSKate Stone   if (log) {
15030fdc8d8SChris Lattner     StreamString s;
151b9c1b51eSKate Stone     s.Address(
152b9c1b51eSKate Stone         m_thread.GetRegisterContext()->GetPC(),
1531ac04c30SGreg Clayton         m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
15430fdc8d8SChris Lattner     log->Printf("ThreadPlanStepInRange reached %s.", s.GetData());
15530fdc8d8SChris Lattner   }
15630fdc8d8SChris Lattner 
15725f66700SJim Ingham   if (IsPlanComplete())
15825f66700SJim Ingham     return true;
15925f66700SJim Ingham 
1604d56e9c1SJim Ingham   m_no_more_plans = false;
161b9c1b51eSKate Stone   if (m_sub_plan_sp && m_sub_plan_sp->IsPlanComplete()) {
162b9c1b51eSKate Stone     if (!m_sub_plan_sp->PlanSucceeded()) {
1634d56e9c1SJim Ingham       SetPlanComplete();
1644d56e9c1SJim Ingham       m_no_more_plans = true;
1654d56e9c1SJim Ingham       return true;
166b9c1b51eSKate Stone     } else
1674d56e9c1SJim Ingham       m_sub_plan_sp.reset();
1684d56e9c1SJim Ingham   }
16930fdc8d8SChris Lattner 
170b9c1b51eSKate Stone   if (m_virtual_step) {
171b9c1b51eSKate Stone     // If we've just completed a virtual step, all we need to do is check for a
17205097246SAdrian Prantl     // ShouldStopHere plan, and otherwise we're done.
173b9c1b51eSKate Stone     // FIXME - This can be both a step in and a step out.  Probably should
174b9c1b51eSKate Stone     // record which in the m_virtual_step.
175*e103ae92SJonas Devlieghere     m_sub_plan_sp =
176*e103ae92SJonas Devlieghere         CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger, m_status);
177b9c1b51eSKate Stone   } else {
178b9c1b51eSKate Stone     // Stepping through should be done running other threads in general, since
17905097246SAdrian Prantl     // we're setting a breakpoint and continuing.  So only stop others if we
18005097246SAdrian Prantl     // are explicitly told to do so.
1819d790c5dSJim Ingham 
182e65b2cf2SEugene Zelenko     bool stop_others = (m_stop_others == lldb::eOnlyThisThread);
18330fdc8d8SChris Lattner 
184b5c0d1ccSJim Ingham     FrameComparison frame_order = CompareCurrentFrameToStartFrame();
185b5c0d1ccSJim Ingham 
186b9c1b51eSKate Stone     if (frame_order == eFrameCompareOlder ||
187b9c1b51eSKate Stone         frame_order == eFrameCompareSameParent) {
1885822173bSJim Ingham       // If we're in an older frame then we should stop.
1895822173bSJim Ingham       //
190b9c1b51eSKate Stone       // A caveat to this is if we think the frame is older but we're actually
191b9c1b51eSKate Stone       // in a trampoline.
192b9c1b51eSKate Stone       // I'm going to make the assumption that you wouldn't RETURN to a
19305097246SAdrian Prantl       // trampoline.  So if we are in a trampoline we think the frame is older
19405097246SAdrian Prantl       // because the trampoline confused the backtracer.
195*e103ae92SJonas Devlieghere       m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough(
196*e103ae92SJonas Devlieghere           m_stack_id, false, stop_others, m_status);
197b9c1b51eSKate Stone       if (!m_sub_plan_sp) {
1984b4b2478SJim Ingham         // Otherwise check the ShouldStopHere for step out:
199*e103ae92SJonas Devlieghere         m_sub_plan_sp =
200*e103ae92SJonas Devlieghere             CheckShouldStopHereAndQueueStepOut(frame_order, m_status);
201a4bb80b2SJim Ingham         if (log) {
202a4bb80b2SJim Ingham           if (m_sub_plan_sp)
203a4bb80b2SJim Ingham             log->Printf("ShouldStopHere found plan to step out of this frame.");
204a4bb80b2SJim Ingham           else
205a4bb80b2SJim Ingham             log->Printf("ShouldStopHere no plan to step out of this frame.");
206a4bb80b2SJim Ingham         }
207b9c1b51eSKate Stone       } else if (log) {
208b9c1b51eSKate Stone         log->Printf(
209b9c1b51eSKate Stone             "Thought I stepped out, but in fact arrived at a trampoline.");
2104b4b2478SJim Ingham       }
211b9c1b51eSKate Stone     } else if (frame_order == eFrameCompareEqual && InSymbol()) {
21205097246SAdrian Prantl       // If we are not in a place we should step through, we're done. One
21305097246SAdrian Prantl       // tricky bit here is that some stubs don't push a frame, so we have to
21405097246SAdrian Prantl       // check both the case of a frame that is younger, or the same as this
21505097246SAdrian Prantl       // frame. However, if the frame is the same, and we are still in the
21605097246SAdrian Prantl       // symbol we started in, the we don't need to do this.  This first check
21705097246SAdrian Prantl       // isn't strictly necessary, but it is more efficient.
2185822173bSJim Ingham 
219b9c1b51eSKate Stone       // If we're still in the range, keep going, either by running to the next
22005097246SAdrian Prantl       // branch breakpoint, or by stepping.
221b9c1b51eSKate Stone       if (InRange()) {
222564d8bc2SJim Ingham         SetNextBranchBreakpoint();
223564d8bc2SJim Ingham         return false;
224564d8bc2SJim Ingham       }
225564d8bc2SJim Ingham 
2265822173bSJim Ingham       SetPlanComplete();
227c627682eSJim Ingham       m_no_more_plans = true;
2285822173bSJim Ingham       return true;
2295822173bSJim Ingham     }
2305822173bSJim Ingham 
231b9c1b51eSKate Stone     // If we get to this point, we're not going to use a previously set "next
232b9c1b51eSKate Stone     // branch" breakpoint, so delete it:
233564d8bc2SJim Ingham     ClearNextBranchBreakpoint();
234564d8bc2SJim Ingham 
2355822173bSJim Ingham     // We may have set the plan up above in the FrameIsOlder section:
2365822173bSJim Ingham 
2374d56e9c1SJim Ingham     if (!m_sub_plan_sp)
238*e103ae92SJonas Devlieghere       m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough(
239*e103ae92SJonas Devlieghere           m_stack_id, false, stop_others, m_status);
24008b87e0dSJim Ingham 
241b9c1b51eSKate Stone     if (log) {
2424d56e9c1SJim Ingham       if (m_sub_plan_sp)
2434d56e9c1SJim Ingham         log->Printf("Found a step through plan: %s", m_sub_plan_sp->GetName());
24408b87e0dSJim Ingham       else
24508b87e0dSJim Ingham         log->Printf("No step through plan found.");
24608b87e0dSJim Ingham     }
24708b87e0dSJim Ingham 
24805097246SAdrian Prantl     // If not, give the "should_stop" callback a chance to push a plan to get
24905097246SAdrian Prantl     // us out of here. But only do that if we actually have stepped in.
2504d56e9c1SJim Ingham     if (!m_sub_plan_sp && frame_order == eFrameCompareYounger)
251*e103ae92SJonas Devlieghere       m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order, m_status);
25230fdc8d8SChris Lattner 
253b9c1b51eSKate Stone     // If we've stepped in and we are going to stop here, check to see if we
25405097246SAdrian Prantl     // were asked to run past the prologue, and if so do that.
2557ce490c6SJim Ingham 
256b9c1b51eSKate Stone     if (!m_sub_plan_sp && frame_order == eFrameCompareYounger &&
257b9c1b51eSKate Stone         m_step_past_prologue) {
258b57e4a1bSJason Molenda       lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0);
259b9c1b51eSKate Stone       if (curr_frame) {
2607ce490c6SJim Ingham         size_t bytes_to_skip = 0;
2617ce490c6SJim Ingham         lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC();
2627ce490c6SJim Ingham         Address func_start_address;
2637ce490c6SJim Ingham 
264b9c1b51eSKate Stone         SymbolContext sc = curr_frame->GetSymbolContext(eSymbolContextFunction |
265b9c1b51eSKate Stone                                                         eSymbolContextSymbol);
2667ce490c6SJim Ingham 
267b9c1b51eSKate Stone         if (sc.function) {
2687ce490c6SJim Ingham           func_start_address = sc.function->GetAddressRange().GetBaseAddress();
269b9c1b51eSKate Stone           if (curr_addr ==
270b9c1b51eSKate Stone               func_start_address.GetLoadAddress(
271b9c1b51eSKate Stone                   m_thread.CalculateTarget().get()))
2727ce490c6SJim Ingham             bytes_to_skip = sc.function->GetPrologueByteSize();
273b9c1b51eSKate Stone         } else if (sc.symbol) {
274e7612134SGreg Clayton           func_start_address = sc.symbol->GetAddress();
275b9c1b51eSKate Stone           if (curr_addr ==
276b9c1b51eSKate Stone               func_start_address.GetLoadAddress(
277b9c1b51eSKate Stone                   m_thread.CalculateTarget().get()))
2787ce490c6SJim Ingham             bytes_to_skip = sc.symbol->GetPrologueByteSize();
2797ce490c6SJim Ingham         }
2807ce490c6SJim Ingham 
28108581263SJim Ingham         if (bytes_to_skip == 0 && sc.symbol) {
28208581263SJim Ingham           TargetSP target = m_thread.CalculateTarget();
2833da0f218STatyana Krasnukha           const Architecture *arch = target->GetArchitecturePlugin();
28408581263SJim Ingham           if (arch) {
28508581263SJim Ingham             Address curr_sec_addr;
28608581263SJim Ingham             target->GetSectionLoadList().ResolveLoadAddress(curr_addr,
28708581263SJim Ingham                                                             curr_sec_addr);
28808581263SJim Ingham             bytes_to_skip = arch->GetBytesToSkip(*sc.symbol, curr_sec_addr);
28908581263SJim Ingham           }
29008581263SJim Ingham         }
29108581263SJim Ingham 
292b9c1b51eSKate Stone         if (bytes_to_skip != 0) {
2937ce490c6SJim Ingham           func_start_address.Slide(bytes_to_skip);
29420ad3c40SCaroline Tice           log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP);
2957ce490c6SJim Ingham           if (log)
2967ce490c6SJim Ingham             log->Printf("Pushing past prologue ");
2977ce490c6SJim Ingham 
298b9c1b51eSKate Stone           m_sub_plan_sp = m_thread.QueueThreadPlanForRunToAddress(
299*e103ae92SJonas Devlieghere               false, func_start_address, true, m_status);
3007ce490c6SJim Ingham         }
3017ce490c6SJim Ingham       }
3027ce490c6SJim Ingham     }
303f02a2e96SJim Ingham   }
3047ce490c6SJim Ingham 
305b9c1b51eSKate Stone   if (!m_sub_plan_sp) {
30630fdc8d8SChris Lattner     m_no_more_plans = true;
30730fdc8d8SChris Lattner     SetPlanComplete();
30830fdc8d8SChris Lattner     return true;
309b9c1b51eSKate Stone   } else {
31030fdc8d8SChris Lattner     m_no_more_plans = false;
3112bdbfd50SJim Ingham     m_sub_plan_sp->SetPrivate(true);
31230fdc8d8SChris Lattner     return false;
31330fdc8d8SChris Lattner   }
31430fdc8d8SChris Lattner }
31530fdc8d8SChris Lattner 
316b9c1b51eSKate Stone void ThreadPlanStepInRange::SetAvoidRegexp(const char *name) {
31795eae423SZachary Turner   auto name_ref = llvm::StringRef::withNullAsEmpty(name);
318e65b2cf2SEugene Zelenko   if (!m_avoid_regexp_ap)
31995eae423SZachary Turner     m_avoid_regexp_ap.reset(new RegularExpression(name_ref));
320a56c8006SJim Ingham 
32195eae423SZachary Turner   m_avoid_regexp_ap->Compile(name_ref);
322a56c8006SJim Ingham }
323a56c8006SJim Ingham 
324b9c1b51eSKate Stone void ThreadPlanStepInRange::SetDefaultFlagValue(uint32_t new_value) {
32530fdc8d8SChris Lattner   // TODO: Should we test this for sanity?
32630fdc8d8SChris Lattner   ThreadPlanStepInRange::s_default_flag_values = new_value;
32730fdc8d8SChris Lattner }
32830fdc8d8SChris Lattner 
329b9c1b51eSKate Stone bool ThreadPlanStepInRange::FrameMatchesAvoidCriteria() {
330b57e4a1bSJason Molenda   StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
331a56c8006SJim Ingham 
3324da6206dSJim Ingham   // Check the library list first, as that's cheapest:
333a786e539SJim Ingham   bool libraries_say_avoid = false;
334a786e539SJim Ingham 
3354da6206dSJim Ingham   FileSpecList libraries_to_avoid(GetThread().GetLibrariesToAvoid());
3364da6206dSJim Ingham   size_t num_libraries = libraries_to_avoid.GetSize();
337b9c1b51eSKate Stone   if (num_libraries > 0) {
3384da6206dSJim Ingham     SymbolContext sc(frame->GetSymbolContext(eSymbolContextModule));
3394da6206dSJim Ingham     FileSpec frame_library(sc.module_sp->GetFileSpec());
3404da6206dSJim Ingham 
341b9c1b51eSKate Stone     if (frame_library) {
342b9c1b51eSKate Stone       for (size_t i = 0; i < num_libraries; i++) {
3434da6206dSJim Ingham         const FileSpec &file_spec(libraries_to_avoid.GetFileSpecAtIndex(i));
344b9c1b51eSKate Stone         if (FileSpec::Equal(file_spec, frame_library, false)) {
3454da6206dSJim Ingham           libraries_say_avoid = true;
3464da6206dSJim Ingham           break;
3474da6206dSJim Ingham         }
3484da6206dSJim Ingham       }
3494da6206dSJim Ingham     }
350a786e539SJim Ingham   }
3514da6206dSJim Ingham   if (libraries_say_avoid)
3524da6206dSJim Ingham     return true;
3534da6206dSJim Ingham 
35467cc0636SGreg Clayton   const RegularExpression *avoid_regexp_to_use = m_avoid_regexp_ap.get();
355e65b2cf2SEugene Zelenko   if (avoid_regexp_to_use == nullptr)
356ee8aea10SJim Ingham     avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp();
357ee8aea10SJim Ingham 
358b9c1b51eSKate Stone   if (avoid_regexp_to_use != nullptr) {
359b9c1b51eSKate Stone     SymbolContext sc = frame->GetSymbolContext(
360b9c1b51eSKate Stone         eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol);
361b9c1b51eSKate Stone     if (sc.symbol != nullptr) {
362b9c1b51eSKate Stone       const char *frame_function_name =
363b9c1b51eSKate Stone           sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments)
364b9c1b51eSKate Stone               .GetCString();
365b9c1b51eSKate Stone       if (frame_function_name) {
366cf2667c4SJim Ingham         size_t num_matches = 0;
3675160ce5cSGreg Clayton         Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
3683101ba33SJim Ingham         if (log)
369cf2667c4SJim Ingham           num_matches = 1;
370bc43cab5SGreg Clayton 
371bc43cab5SGreg Clayton         RegularExpression::Match regex_match(num_matches);
372bc43cab5SGreg Clayton 
373b9c1b51eSKate Stone         bool return_value =
374b9c1b51eSKate Stone             avoid_regexp_to_use->Execute(frame_function_name, &regex_match);
375b9c1b51eSKate Stone         if (return_value) {
376b9c1b51eSKate Stone           if (log) {
377cf2667c4SJim Ingham             std::string match;
378bc43cab5SGreg Clayton             regex_match.GetMatchAtIndex(frame_function_name, 0, match);
379b9c1b51eSKate Stone             log->Printf("Stepping out of function \"%s\" because it matches "
380b9c1b51eSKate Stone                         "the avoid regexp \"%s\" - match substring: \"%s\".",
38195eae423SZachary Turner                         frame_function_name,
38295eae423SZachary Turner                         avoid_regexp_to_use->GetText().str().c_str(),
383cf2667c4SJim Ingham                         match.c_str());
384cf2667c4SJim Ingham           }
3853101ba33SJim Ingham         }
3863101ba33SJim Ingham         return return_value;
3873101ba33SJim Ingham       }
388a56c8006SJim Ingham     }
389a56c8006SJim Ingham   }
390a56c8006SJim Ingham   return false;
391a56c8006SJim Ingham }
392a56c8006SJim Ingham 
393b9c1b51eSKate Stone bool ThreadPlanStepInRange::DefaultShouldStopHereCallback(
394b9c1b51eSKate Stone     ThreadPlan *current_plan, Flags &flags, FrameComparison operation,
395*e103ae92SJonas Devlieghere     Status &status, void *baton) {
3964b4b2478SJim Ingham   bool should_stop_here = true;
397b57e4a1bSJason Molenda   StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
3985160ce5cSGreg Clayton   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
39930fdc8d8SChris Lattner 
400b9c1b51eSKate Stone   // First see if the ThreadPlanShouldStopHere default implementation thinks we
401b9c1b51eSKate Stone   // should get out of here:
402b9c1b51eSKate Stone   should_stop_here = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback(
403*e103ae92SJonas Devlieghere       current_plan, flags, operation, status, baton);
4040c2b9d2aSJim Ingham   if (!should_stop_here)
4050c2b9d2aSJim Ingham     return should_stop_here;
406a56c8006SJim Ingham 
407b9c1b51eSKate Stone   if (should_stop_here && current_plan->GetKind() == eKindStepInRange &&
408b9c1b51eSKate Stone       operation == eFrameCompareYounger) {
409b9c1b51eSKate Stone     ThreadPlanStepInRange *step_in_range_plan =
410b9c1b51eSKate Stone         static_cast<ThreadPlanStepInRange *>(current_plan);
411b9c1b51eSKate Stone     if (step_in_range_plan->m_step_into_target) {
412b9c1b51eSKate Stone       SymbolContext sc = frame->GetSymbolContext(
413b9c1b51eSKate Stone           eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol);
414b9c1b51eSKate Stone       if (sc.symbol != nullptr) {
41505097246SAdrian Prantl         // First try an exact match, since that's cheap with ConstStrings.
41605097246SAdrian Prantl         // Then do a strstr compare.
417b9c1b51eSKate Stone         if (step_in_range_plan->m_step_into_target == sc.GetFunctionName()) {
4184b4b2478SJim Ingham           should_stop_here = true;
419b9c1b51eSKate Stone         } else {
420b9c1b51eSKate Stone           const char *target_name =
421b9c1b51eSKate Stone               step_in_range_plan->m_step_into_target.AsCString();
422c627682eSJim Ingham           const char *function_name = sc.GetFunctionName().AsCString();
423c627682eSJim Ingham 
424e65b2cf2SEugene Zelenko           if (function_name == nullptr)
4254b4b2478SJim Ingham             should_stop_here = false;
426e65b2cf2SEugene Zelenko           else if (strstr(function_name, target_name) == nullptr)
4274b4b2478SJim Ingham             should_stop_here = false;
428c627682eSJim Ingham         }
4294b4b2478SJim Ingham         if (log && !should_stop_here)
430b9c1b51eSKate Stone           log->Printf("Stepping out of frame %s which did not match step into "
431b9c1b51eSKate Stone                       "target %s.",
4323101ba33SJim Ingham                       sc.GetFunctionName().AsCString(),
4333101ba33SJim Ingham                       step_in_range_plan->m_step_into_target.AsCString());
434c627682eSJim Ingham       }
435c627682eSJim Ingham     }
436c627682eSJim Ingham 
437b9c1b51eSKate Stone     if (should_stop_here) {
438b9c1b51eSKate Stone       ThreadPlanStepInRange *step_in_range_plan =
439b9c1b51eSKate Stone           static_cast<ThreadPlanStepInRange *>(current_plan);
440b9c1b51eSKate Stone       // Don't log the should_step_out here, it's easier to do it in
441b9c1b51eSKate Stone       // FrameMatchesAvoidCriteria.
4424b4b2478SJim Ingham       should_stop_here = !step_in_range_plan->FrameMatchesAvoidCriteria();
443a56c8006SJim Ingham     }
444a56c8006SJim Ingham   }
445a56c8006SJim Ingham 
4464b4b2478SJim Ingham   return should_stop_here;
44730fdc8d8SChris Lattner }
448fbbfe6ecSJim Ingham 
449b9c1b51eSKate Stone bool ThreadPlanStepInRange::DoPlanExplainsStop(Event *event_ptr) {
450fbbfe6ecSJim Ingham   // We always explain a stop.  Either we've just done a single step, in which
45105097246SAdrian Prantl   // case we'll do our ordinary processing, or we stopped for some reason that
45205097246SAdrian Prantl   // isn't handled by our sub-plans, in which case we want to just stop right
45305097246SAdrian Prantl   // away. In general, we don't want to mark the plan as complete for
45405097246SAdrian Prantl   // unexplained stops. For instance, if you step in to some code with no debug
45505097246SAdrian Prantl   // info, so you step out and in the course of that hit a breakpoint, then you
45605097246SAdrian Prantl   // want to stop & show the user the breakpoint, but not unship the step in
45705097246SAdrian Prantl   // plan, since you still may want to complete that plan when you continue.
45805097246SAdrian Prantl   // This is particularly true when doing "step in to target function."
459c627682eSJim Ingham   // stepping.
460fbbfe6ecSJim Ingham   //
46105097246SAdrian Prantl   // The only variation is that if we are doing "step by running to next
46205097246SAdrian Prantl   // branch" in which case if we hit our branch breakpoint we don't set the
46305097246SAdrian Prantl   // plan to complete.
464fbbfe6ecSJim Ingham 
4659b03fa0cSJim Ingham   bool return_value = false;
466f02a2e96SJim Ingham 
467b9c1b51eSKate Stone   if (m_virtual_step) {
468221d51cfSJim Ingham     return_value = true;
469b9c1b51eSKate Stone   } else {
47060c4118cSJim Ingham     StopInfoSP stop_info_sp = GetPrivateStopInfo();
471b9c1b51eSKate Stone     if (stop_info_sp) {
472fbbfe6ecSJim Ingham       StopReason reason = stop_info_sp->GetStopReason();
473fbbfe6ecSJim Ingham 
474b9c1b51eSKate Stone       if (reason == eStopReasonBreakpoint) {
475b9c1b51eSKate Stone         if (NextRangeBreakpointExplainsStop(stop_info_sp)) {
476221d51cfSJim Ingham           return_value = true;
477221d51cfSJim Ingham         }
478b9c1b51eSKate Stone       } else if (IsUsuallyUnexplainedStopReason(reason)) {
4795160ce5cSGreg Clayton         Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
480fbbfe6ecSJim Ingham         if (log)
481b9c1b51eSKate Stone           log->PutCString("ThreadPlanStepInRange got asked if it explains the "
482b9c1b51eSKate Stone                           "stop for some reason other than step.");
483221d51cfSJim Ingham         return_value = false;
484b9c1b51eSKate Stone       } else {
485221d51cfSJim Ingham         return_value = true;
486fbbfe6ecSJim Ingham       }
487b9c1b51eSKate Stone     } else
488221d51cfSJim Ingham       return_value = true;
489221d51cfSJim Ingham   }
490221d51cfSJim Ingham 
491221d51cfSJim Ingham   return return_value;
492fbbfe6ecSJim Ingham }
493513c6bb8SJim Ingham 
494b9c1b51eSKate Stone bool ThreadPlanStepInRange::DoWillResume(lldb::StateType resume_state,
495b9c1b51eSKate Stone                                          bool current_plan) {
49669fc298aSTamas Berghammer   m_virtual_step = false;
497b9c1b51eSKate Stone   if (resume_state == eStateStepping && current_plan) {
498513c6bb8SJim Ingham     // See if we are about to step over a virtual inlined call.
499513c6bb8SJim Ingham     bool step_without_resume = m_thread.DecrementCurrentInlinedDepth();
500b9c1b51eSKate Stone     if (step_without_resume) {
5015160ce5cSGreg Clayton       Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
502513c6bb8SJim Ingham       if (log)
503b9c1b51eSKate Stone         log->Printf("ThreadPlanStepInRange::DoWillResume: returning false, "
504b9c1b51eSKate Stone                     "inline_depth: %d",
505513c6bb8SJim Ingham                     m_thread.GetCurrentInlinedDepth());
506513c6bb8SJim Ingham       SetStopInfo(StopInfo::CreateStopReasonToTrace(m_thread));
507f02a2e96SJim Ingham 
508b9c1b51eSKate Stone       // FIXME: Maybe it would be better to create a InlineStep stop reason, but
509b9c1b51eSKate Stone       // then
510f02a2e96SJim Ingham       // the whole rest of the world would have to handle that stop reason.
511f02a2e96SJim Ingham       m_virtual_step = true;
512513c6bb8SJim Ingham     }
513513c6bb8SJim Ingham     return !step_without_resume;
514513c6bb8SJim Ingham   }
515221d51cfSJim Ingham   return true;
516513c6bb8SJim Ingham }
517246cb611SDaniel Malea 
518b9c1b51eSKate Stone bool ThreadPlanStepInRange::IsVirtualStep() { return m_virtual_step; }
519