180814287SRaphael Isemann //===-- ThreadPlanStepInRange.cpp -----------------------------------------===//
230fdc8d8SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner 
9e65b2cf2SEugene Zelenko #include "lldb/Target/ThreadPlanStepInRange.h"
1008581263SJim Ingham #include "lldb/Core/Architecture.h"
114da6206dSJim Ingham #include "lldb/Core/Module.h"
127ce490c6SJim Ingham #include "lldb/Symbol/Function.h"
13b9c1b51eSKate Stone #include "lldb/Symbol/Symbol.h"
1430fdc8d8SChris Lattner #include "lldb/Target/Process.h"
1530fdc8d8SChris Lattner #include "lldb/Target/RegisterContext.h"
1608581263SJim Ingham #include "lldb/Target/SectionLoadList.h"
17514487e8SGreg Clayton #include "lldb/Target/Target.h"
1830fdc8d8SChris Lattner #include "lldb/Target/Thread.h"
1930fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepOut.h"
2030fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepThrough.h"
216f9e6901SZachary Turner #include "lldb/Utility/Log.h"
22bf9a7730SZachary Turner #include "lldb/Utility/RegularExpression.h"
23bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
2430fdc8d8SChris Lattner 
2530fdc8d8SChris Lattner using namespace lldb;
2630fdc8d8SChris Lattner using namespace lldb_private;
2730fdc8d8SChris Lattner 
28b9c1b51eSKate Stone uint32_t ThreadPlanStepInRange::s_default_flag_values =
29b9c1b51eSKate Stone     ThreadPlanShouldStopHere::eStepInAvoidNoDebug;
3030fdc8d8SChris Lattner 
31b9c1b51eSKate Stone // ThreadPlanStepInRange: Step through a stack range, either stepping over or
3205097246SAdrian Prantl // into based on the value of \a type.
3330fdc8d8SChris Lattner 
34b9c1b51eSKate Stone ThreadPlanStepInRange::ThreadPlanStepInRange(
35b9c1b51eSKate Stone     Thread &thread, const AddressRange &range,
36*a5ab1dc4SDave Lee     const SymbolContext &addr_context, const char *step_into_target,
37*a5ab1dc4SDave Lee     lldb::RunMode stop_others, LazyBool step_in_avoids_code_without_debug_info,
38b9c1b51eSKate Stone     LazyBool step_out_avoids_code_without_debug_info)
39b9c1b51eSKate Stone     : ThreadPlanStepRange(ThreadPlan::eKindStepInRange,
40b9c1b51eSKate Stone                           "Step Range stepping in", thread, range, addr_context,
41b9c1b51eSKate Stone                           stop_others),
42b9c1b51eSKate Stone       ThreadPlanShouldStopHere(this), m_step_past_prologue(true),
43*a5ab1dc4SDave Lee       m_virtual_step(false), m_step_into_target(step_into_target) {
444b4b2478SJim Ingham   SetCallbacks();
4530fdc8d8SChris Lattner   SetFlagsToDefault();
46b9c1b51eSKate Stone   SetupAvoidNoDebug(step_in_avoids_code_without_debug_info,
47b9c1b51eSKate Stone                     step_out_avoids_code_without_debug_info);
4830fdc8d8SChris Lattner }
4930fdc8d8SChris Lattner 
50e65b2cf2SEugene Zelenko ThreadPlanStepInRange::~ThreadPlanStepInRange() = default;
5130fdc8d8SChris Lattner 
52b9c1b51eSKate Stone void ThreadPlanStepInRange::SetupAvoidNoDebug(
53b9c1b51eSKate Stone     LazyBool step_in_avoids_code_without_debug_info,
54b9c1b51eSKate Stone     LazyBool step_out_avoids_code_without_debug_info) {
554b4b2478SJim Ingham   bool avoid_nodebug = true;
56e4598dc0SJim Ingham   Thread &thread = GetThread();
57b9c1b51eSKate Stone   switch (step_in_avoids_code_without_debug_info) {
584b4b2478SJim Ingham   case eLazyBoolYes:
594b4b2478SJim Ingham     avoid_nodebug = true;
604b4b2478SJim Ingham     break;
614b4b2478SJim Ingham   case eLazyBoolNo:
624b4b2478SJim Ingham     avoid_nodebug = false;
634b4b2478SJim Ingham     break;
644b4b2478SJim Ingham   case eLazyBoolCalculate:
65e4598dc0SJim Ingham     avoid_nodebug = thread.GetStepInAvoidsNoDebug();
664b4b2478SJim Ingham     break;
674b4b2478SJim Ingham   }
684b4b2478SJim Ingham   if (avoid_nodebug)
694b4b2478SJim Ingham     GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
704b4b2478SJim Ingham   else
714b4b2478SJim Ingham     GetFlags().Clear(ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
724b4b2478SJim Ingham 
73b9c1b51eSKate Stone   switch (step_out_avoids_code_without_debug_info) {
744b4b2478SJim Ingham   case eLazyBoolYes:
754b4b2478SJim Ingham     avoid_nodebug = true;
764b4b2478SJim Ingham     break;
774b4b2478SJim Ingham   case eLazyBoolNo:
784b4b2478SJim Ingham     avoid_nodebug = false;
794b4b2478SJim Ingham     break;
804b4b2478SJim Ingham   case eLazyBoolCalculate:
81e4598dc0SJim Ingham     avoid_nodebug = thread.GetStepOutAvoidsNoDebug();
824b4b2478SJim Ingham     break;
834b4b2478SJim Ingham   }
844b4b2478SJim Ingham   if (avoid_nodebug)
854b4b2478SJim Ingham     GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
864b4b2478SJim Ingham   else
874b4b2478SJim Ingham     GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
884b4b2478SJim Ingham }
894b4b2478SJim Ingham 
90b9c1b51eSKate Stone void ThreadPlanStepInRange::GetDescription(Stream *s,
91b9c1b51eSKate Stone                                            lldb::DescriptionLevel level) {
92e103ae92SJonas Devlieghere 
93e103ae92SJonas Devlieghere   auto PrintFailureIfAny = [&]() {
94e103ae92SJonas Devlieghere     if (m_status.Success())
95e103ae92SJonas Devlieghere       return;
96e103ae92SJonas Devlieghere     s->Printf(" failed (%s)", m_status.AsCString());
97e103ae92SJonas Devlieghere   };
98e103ae92SJonas Devlieghere 
99b9c1b51eSKate Stone   if (level == lldb::eDescriptionLevelBrief) {
1002bdbfd50SJim Ingham     s->Printf("step in");
101e103ae92SJonas Devlieghere     PrintFailureIfAny();
1022bdbfd50SJim Ingham     return;
1032bdbfd50SJim Ingham   }
1042bdbfd50SJim Ingham 
1052bdbfd50SJim Ingham   s->Printf("Stepping in");
1062bdbfd50SJim Ingham   bool printed_line_info = false;
107b9c1b51eSKate Stone   if (m_addr_context.line_entry.IsValid()) {
1082bdbfd50SJim Ingham     s->Printf(" through line ");
1092bdbfd50SJim Ingham     m_addr_context.line_entry.DumpStopContext(s, false);
1102bdbfd50SJim Ingham     printed_line_info = true;
1112bdbfd50SJim Ingham   }
1122bdbfd50SJim Ingham 
1134d56e9c1SJim Ingham   const char *step_into_target = m_step_into_target.AsCString();
1144d56e9c1SJim Ingham   if (step_into_target && step_into_target[0] != '\0')
1152bdbfd50SJim Ingham     s->Printf(" targeting %s", m_step_into_target.AsCString());
1162bdbfd50SJim Ingham 
117b9c1b51eSKate Stone   if (!printed_line_info || level == eDescriptionLevelVerbose) {
1182bdbfd50SJim Ingham     s->Printf(" using ranges:");
1192bdbfd50SJim Ingham     DumpRanges(s);
12030fdc8d8SChris Lattner   }
1212bdbfd50SJim Ingham 
122e103ae92SJonas Devlieghere   PrintFailureIfAny();
123e103ae92SJonas Devlieghere 
1242bdbfd50SJim Ingham   s->PutChar('.');
12530fdc8d8SChris Lattner }
12630fdc8d8SChris Lattner 
127b9c1b51eSKate Stone bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
1285160ce5cSGreg Clayton   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
12930fdc8d8SChris Lattner 
130b9c1b51eSKate Stone   if (log) {
13130fdc8d8SChris Lattner     StreamString s;
132e4598dc0SJim Ingham     DumpAddress(s.AsRawOstream(), GetThread().GetRegisterContext()->GetPC(),
133e4598dc0SJim Ingham                 GetTarget().GetArchitecture().GetAddressByteSize());
13463e5fb76SJonas Devlieghere     LLDB_LOGF(log, "ThreadPlanStepInRange reached %s.", s.GetData());
13530fdc8d8SChris Lattner   }
13630fdc8d8SChris Lattner 
13725f66700SJim Ingham   if (IsPlanComplete())
13825f66700SJim Ingham     return true;
13925f66700SJim Ingham 
1404d56e9c1SJim Ingham   m_no_more_plans = false;
141b9c1b51eSKate Stone   if (m_sub_plan_sp && m_sub_plan_sp->IsPlanComplete()) {
142b9c1b51eSKate Stone     if (!m_sub_plan_sp->PlanSucceeded()) {
1434d56e9c1SJim Ingham       SetPlanComplete();
1444d56e9c1SJim Ingham       m_no_more_plans = true;
1454d56e9c1SJim Ingham       return true;
146b9c1b51eSKate Stone     } else
1474d56e9c1SJim Ingham       m_sub_plan_sp.reset();
1484d56e9c1SJim Ingham   }
14930fdc8d8SChris Lattner 
150b9c1b51eSKate Stone   if (m_virtual_step) {
151b9c1b51eSKate Stone     // If we've just completed a virtual step, all we need to do is check for a
15205097246SAdrian Prantl     // ShouldStopHere plan, and otherwise we're done.
153b9c1b51eSKate Stone     // FIXME - This can be both a step in and a step out.  Probably should
154b9c1b51eSKate Stone     // record which in the m_virtual_step.
155e103ae92SJonas Devlieghere     m_sub_plan_sp =
156e103ae92SJonas Devlieghere         CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger, m_status);
157b9c1b51eSKate Stone   } else {
158b9c1b51eSKate Stone     // Stepping through should be done running other threads in general, since
15905097246SAdrian Prantl     // we're setting a breakpoint and continuing.  So only stop others if we
16005097246SAdrian Prantl     // are explicitly told to do so.
1619d790c5dSJim Ingham 
162e65b2cf2SEugene Zelenko     bool stop_others = (m_stop_others == lldb::eOnlyThisThread);
16330fdc8d8SChris Lattner 
164b5c0d1ccSJim Ingham     FrameComparison frame_order = CompareCurrentFrameToStartFrame();
165b5c0d1ccSJim Ingham 
166e4598dc0SJim Ingham     Thread &thread = GetThread();
167b9c1b51eSKate Stone     if (frame_order == eFrameCompareOlder ||
168b9c1b51eSKate Stone         frame_order == eFrameCompareSameParent) {
1695822173bSJim Ingham       // If we're in an older frame then we should stop.
1705822173bSJim Ingham       //
171b9c1b51eSKate Stone       // A caveat to this is if we think the frame is older but we're actually
172b9c1b51eSKate Stone       // in a trampoline.
173b9c1b51eSKate Stone       // I'm going to make the assumption that you wouldn't RETURN to a
17405097246SAdrian Prantl       // trampoline.  So if we are in a trampoline we think the frame is older
17505097246SAdrian Prantl       // because the trampoline confused the backtracer.
176e4598dc0SJim Ingham       m_sub_plan_sp = thread.QueueThreadPlanForStepThrough(
177e103ae92SJonas Devlieghere           m_stack_id, false, stop_others, m_status);
178b9c1b51eSKate Stone       if (!m_sub_plan_sp) {
1794b4b2478SJim Ingham         // Otherwise check the ShouldStopHere for step out:
180e103ae92SJonas Devlieghere         m_sub_plan_sp =
181e103ae92SJonas Devlieghere             CheckShouldStopHereAndQueueStepOut(frame_order, m_status);
182a4bb80b2SJim Ingham         if (log) {
183a4bb80b2SJim Ingham           if (m_sub_plan_sp)
18463e5fb76SJonas Devlieghere             LLDB_LOGF(log,
18563e5fb76SJonas Devlieghere                       "ShouldStopHere found plan to step out of this frame.");
186a4bb80b2SJim Ingham           else
18763e5fb76SJonas Devlieghere             LLDB_LOGF(log, "ShouldStopHere no plan to step out of this frame.");
188a4bb80b2SJim Ingham         }
189b9c1b51eSKate Stone       } else if (log) {
19063e5fb76SJonas Devlieghere         LLDB_LOGF(
19163e5fb76SJonas Devlieghere             log, "Thought I stepped out, but in fact arrived at a trampoline.");
1924b4b2478SJim Ingham       }
193b9c1b51eSKate Stone     } else if (frame_order == eFrameCompareEqual && InSymbol()) {
19405097246SAdrian Prantl       // If we are not in a place we should step through, we're done. One
19505097246SAdrian Prantl       // tricky bit here is that some stubs don't push a frame, so we have to
19605097246SAdrian Prantl       // check both the case of a frame that is younger, or the same as this
19705097246SAdrian Prantl       // frame. However, if the frame is the same, and we are still in the
19805097246SAdrian Prantl       // symbol we started in, the we don't need to do this.  This first check
19905097246SAdrian Prantl       // isn't strictly necessary, but it is more efficient.
2005822173bSJim Ingham 
201b9c1b51eSKate Stone       // If we're still in the range, keep going, either by running to the next
20205097246SAdrian Prantl       // branch breakpoint, or by stepping.
203b9c1b51eSKate Stone       if (InRange()) {
204564d8bc2SJim Ingham         SetNextBranchBreakpoint();
205564d8bc2SJim Ingham         return false;
206564d8bc2SJim Ingham       }
207564d8bc2SJim Ingham 
2085822173bSJim Ingham       SetPlanComplete();
209c627682eSJim Ingham       m_no_more_plans = true;
2105822173bSJim Ingham       return true;
2115822173bSJim Ingham     }
2125822173bSJim Ingham 
213b9c1b51eSKate Stone     // If we get to this point, we're not going to use a previously set "next
214b9c1b51eSKate Stone     // branch" breakpoint, so delete it:
215564d8bc2SJim Ingham     ClearNextBranchBreakpoint();
216564d8bc2SJim Ingham 
2175822173bSJim Ingham     // We may have set the plan up above in the FrameIsOlder section:
2185822173bSJim Ingham 
2194d56e9c1SJim Ingham     if (!m_sub_plan_sp)
220e4598dc0SJim Ingham       m_sub_plan_sp = thread.QueueThreadPlanForStepThrough(
221e103ae92SJonas Devlieghere           m_stack_id, false, stop_others, m_status);
22208b87e0dSJim Ingham 
223b9c1b51eSKate Stone     if (log) {
2244d56e9c1SJim Ingham       if (m_sub_plan_sp)
22563e5fb76SJonas Devlieghere         LLDB_LOGF(log, "Found a step through plan: %s",
22663e5fb76SJonas Devlieghere                   m_sub_plan_sp->GetName());
22708b87e0dSJim Ingham       else
22863e5fb76SJonas Devlieghere         LLDB_LOGF(log, "No step through plan found.");
22908b87e0dSJim Ingham     }
23008b87e0dSJim Ingham 
23105097246SAdrian Prantl     // If not, give the "should_stop" callback a chance to push a plan to get
23205097246SAdrian Prantl     // us out of here. But only do that if we actually have stepped in.
2334d56e9c1SJim Ingham     if (!m_sub_plan_sp && frame_order == eFrameCompareYounger)
234e103ae92SJonas Devlieghere       m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order, m_status);
23530fdc8d8SChris Lattner 
236b9c1b51eSKate Stone     // If we've stepped in and we are going to stop here, check to see if we
23705097246SAdrian Prantl     // were asked to run past the prologue, and if so do that.
2387ce490c6SJim Ingham 
239b9c1b51eSKate Stone     if (!m_sub_plan_sp && frame_order == eFrameCompareYounger &&
240b9c1b51eSKate Stone         m_step_past_prologue) {
241e4598dc0SJim Ingham       lldb::StackFrameSP curr_frame = thread.GetStackFrameAtIndex(0);
242b9c1b51eSKate Stone       if (curr_frame) {
2437ce490c6SJim Ingham         size_t bytes_to_skip = 0;
244e4598dc0SJim Ingham         lldb::addr_t curr_addr = thread.GetRegisterContext()->GetPC();
2457ce490c6SJim Ingham         Address func_start_address;
2467ce490c6SJim Ingham 
247b9c1b51eSKate Stone         SymbolContext sc = curr_frame->GetSymbolContext(eSymbolContextFunction |
248b9c1b51eSKate Stone                                                         eSymbolContextSymbol);
2497ce490c6SJim Ingham 
250b9c1b51eSKate Stone         if (sc.function) {
2517ce490c6SJim Ingham           func_start_address = sc.function->GetAddressRange().GetBaseAddress();
252e4598dc0SJim Ingham           if (curr_addr == func_start_address.GetLoadAddress(&GetTarget()))
2537ce490c6SJim Ingham             bytes_to_skip = sc.function->GetPrologueByteSize();
254b9c1b51eSKate Stone         } else if (sc.symbol) {
255e7612134SGreg Clayton           func_start_address = sc.symbol->GetAddress();
256e4598dc0SJim Ingham           if (curr_addr == func_start_address.GetLoadAddress(&GetTarget()))
2577ce490c6SJim Ingham             bytes_to_skip = sc.symbol->GetPrologueByteSize();
2587ce490c6SJim Ingham         }
2597ce490c6SJim Ingham 
26008581263SJim Ingham         if (bytes_to_skip == 0 && sc.symbol) {
261e4598dc0SJim Ingham           const Architecture *arch = GetTarget().GetArchitecturePlugin();
26208581263SJim Ingham           if (arch) {
26308581263SJim Ingham             Address curr_sec_addr;
264e4598dc0SJim Ingham             GetTarget().GetSectionLoadList().ResolveLoadAddress(curr_addr,
26508581263SJim Ingham                                                                 curr_sec_addr);
26608581263SJim Ingham             bytes_to_skip = arch->GetBytesToSkip(*sc.symbol, curr_sec_addr);
26708581263SJim Ingham           }
26808581263SJim Ingham         }
26908581263SJim Ingham 
270b9c1b51eSKate Stone         if (bytes_to_skip != 0) {
2717ce490c6SJim Ingham           func_start_address.Slide(bytes_to_skip);
27220ad3c40SCaroline Tice           log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP);
27363e5fb76SJonas Devlieghere           LLDB_LOGF(log, "Pushing past prologue ");
2747ce490c6SJim Ingham 
275e4598dc0SJim Ingham           m_sub_plan_sp = thread.QueueThreadPlanForRunToAddress(
276e103ae92SJonas Devlieghere               false, func_start_address, true, m_status);
2777ce490c6SJim Ingham         }
2787ce490c6SJim Ingham       }
2797ce490c6SJim Ingham     }
280f02a2e96SJim Ingham   }
2817ce490c6SJim Ingham 
282b9c1b51eSKate Stone   if (!m_sub_plan_sp) {
28330fdc8d8SChris Lattner     m_no_more_plans = true;
28430fdc8d8SChris Lattner     SetPlanComplete();
28530fdc8d8SChris Lattner     return true;
286b9c1b51eSKate Stone   } else {
28730fdc8d8SChris Lattner     m_no_more_plans = false;
2882bdbfd50SJim Ingham     m_sub_plan_sp->SetPrivate(true);
28930fdc8d8SChris Lattner     return false;
29030fdc8d8SChris Lattner   }
29130fdc8d8SChris Lattner }
29230fdc8d8SChris Lattner 
293b9c1b51eSKate Stone void ThreadPlanStepInRange::SetAvoidRegexp(const char *name) {
29495eae423SZachary Turner   auto name_ref = llvm::StringRef::withNullAsEmpty(name);
295f9d90bc5SJan Kratochvil   if (m_avoid_regexp_up)
296f9d90bc5SJan Kratochvil     *m_avoid_regexp_up = RegularExpression(name_ref);
297f9d90bc5SJan Kratochvil   else
29806412daeSJonas Devlieghere     m_avoid_regexp_up = std::make_unique<RegularExpression>(name_ref);
299a56c8006SJim Ingham }
300a56c8006SJim Ingham 
301b9c1b51eSKate Stone void ThreadPlanStepInRange::SetDefaultFlagValue(uint32_t new_value) {
30230fdc8d8SChris Lattner   // TODO: Should we test this for sanity?
30330fdc8d8SChris Lattner   ThreadPlanStepInRange::s_default_flag_values = new_value;
30430fdc8d8SChris Lattner }
30530fdc8d8SChris Lattner 
306b9c1b51eSKate Stone bool ThreadPlanStepInRange::FrameMatchesAvoidCriteria() {
307b57e4a1bSJason Molenda   StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
308a56c8006SJim Ingham 
3094da6206dSJim Ingham   // Check the library list first, as that's cheapest:
310a786e539SJim Ingham   bool libraries_say_avoid = false;
311a786e539SJim Ingham 
3124da6206dSJim Ingham   FileSpecList libraries_to_avoid(GetThread().GetLibrariesToAvoid());
3134da6206dSJim Ingham   size_t num_libraries = libraries_to_avoid.GetSize();
314b9c1b51eSKate Stone   if (num_libraries > 0) {
3154da6206dSJim Ingham     SymbolContext sc(frame->GetSymbolContext(eSymbolContextModule));
3164da6206dSJim Ingham     FileSpec frame_library(sc.module_sp->GetFileSpec());
3174da6206dSJim Ingham 
318b9c1b51eSKate Stone     if (frame_library) {
319b9c1b51eSKate Stone       for (size_t i = 0; i < num_libraries; i++) {
3204da6206dSJim Ingham         const FileSpec &file_spec(libraries_to_avoid.GetFileSpecAtIndex(i));
321532290e6SPavel Labath         if (FileSpec::Match(file_spec, frame_library)) {
3224da6206dSJim Ingham           libraries_say_avoid = true;
3234da6206dSJim Ingham           break;
3244da6206dSJim Ingham         }
3254da6206dSJim Ingham       }
3264da6206dSJim Ingham     }
327a786e539SJim Ingham   }
3284da6206dSJim Ingham   if (libraries_say_avoid)
3294da6206dSJim Ingham     return true;
3304da6206dSJim Ingham 
331d5b44036SJonas Devlieghere   const RegularExpression *avoid_regexp_to_use = m_avoid_regexp_up.get();
332e65b2cf2SEugene Zelenko   if (avoid_regexp_to_use == nullptr)
333ee8aea10SJim Ingham     avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp();
334ee8aea10SJim Ingham 
335b9c1b51eSKate Stone   if (avoid_regexp_to_use != nullptr) {
336b9c1b51eSKate Stone     SymbolContext sc = frame->GetSymbolContext(
337b9c1b51eSKate Stone         eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol);
338b9c1b51eSKate Stone     if (sc.symbol != nullptr) {
339b9c1b51eSKate Stone       const char *frame_function_name =
340b9c1b51eSKate Stone           sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments)
341b9c1b51eSKate Stone               .GetCString();
342b9c1b51eSKate Stone       if (frame_function_name) {
3433af3f1e8SJonas Devlieghere         llvm::SmallVector<llvm::StringRef, 2> matches;
344b9c1b51eSKate Stone         bool return_value =
3453af3f1e8SJonas Devlieghere             avoid_regexp_to_use->Execute(frame_function_name, &matches);
3463af3f1e8SJonas Devlieghere         if (return_value && matches.size() > 1) {
3473af3f1e8SJonas Devlieghere           std::string match = matches[1].str();
3483af3f1e8SJonas Devlieghere           LLDB_LOGF(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP),
34963e5fb76SJonas Devlieghere                     "Stepping out of function \"%s\" because it matches "
350b9c1b51eSKate Stone                     "the avoid regexp \"%s\" - match substring: \"%s\".",
35195eae423SZachary Turner                     frame_function_name,
35295eae423SZachary Turner                     avoid_regexp_to_use->GetText().str().c_str(),
353cf2667c4SJim Ingham                     match.c_str());
354cf2667c4SJim Ingham         }
3553101ba33SJim Ingham         return return_value;
3563101ba33SJim Ingham       }
357a56c8006SJim Ingham     }
358a56c8006SJim Ingham   }
359a56c8006SJim Ingham   return false;
360a56c8006SJim Ingham }
361a56c8006SJim Ingham 
362b9c1b51eSKate Stone bool ThreadPlanStepInRange::DefaultShouldStopHereCallback(
363b9c1b51eSKate Stone     ThreadPlan *current_plan, Flags &flags, FrameComparison operation,
364e103ae92SJonas Devlieghere     Status &status, void *baton) {
3654b4b2478SJim Ingham   bool should_stop_here = true;
366b57e4a1bSJason Molenda   StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
3675160ce5cSGreg Clayton   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
36830fdc8d8SChris Lattner 
369b9c1b51eSKate Stone   // First see if the ThreadPlanShouldStopHere default implementation thinks we
370b9c1b51eSKate Stone   // should get out of here:
371b9c1b51eSKate Stone   should_stop_here = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback(
372e103ae92SJonas Devlieghere       current_plan, flags, operation, status, baton);
3730c2b9d2aSJim Ingham   if (!should_stop_here)
374ec4c96d6SRaphael Isemann     return false;
375a56c8006SJim Ingham 
376b9c1b51eSKate Stone   if (should_stop_here && current_plan->GetKind() == eKindStepInRange &&
377b9c1b51eSKate Stone       operation == eFrameCompareYounger) {
378b9c1b51eSKate Stone     ThreadPlanStepInRange *step_in_range_plan =
379b9c1b51eSKate Stone         static_cast<ThreadPlanStepInRange *>(current_plan);
380b9c1b51eSKate Stone     if (step_in_range_plan->m_step_into_target) {
381b9c1b51eSKate Stone       SymbolContext sc = frame->GetSymbolContext(
382b9c1b51eSKate Stone           eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol);
383b9c1b51eSKate Stone       if (sc.symbol != nullptr) {
38405097246SAdrian Prantl         // First try an exact match, since that's cheap with ConstStrings.
38505097246SAdrian Prantl         // Then do a strstr compare.
386b9c1b51eSKate Stone         if (step_in_range_plan->m_step_into_target == sc.GetFunctionName()) {
3874b4b2478SJim Ingham           should_stop_here = true;
388b9c1b51eSKate Stone         } else {
389b9c1b51eSKate Stone           const char *target_name =
390b9c1b51eSKate Stone               step_in_range_plan->m_step_into_target.AsCString();
391c627682eSJim Ingham           const char *function_name = sc.GetFunctionName().AsCString();
392c627682eSJim Ingham 
393e65b2cf2SEugene Zelenko           if (function_name == nullptr)
3944b4b2478SJim Ingham             should_stop_here = false;
395e65b2cf2SEugene Zelenko           else if (strstr(function_name, target_name) == nullptr)
3964b4b2478SJim Ingham             should_stop_here = false;
397c627682eSJim Ingham         }
3984b4b2478SJim Ingham         if (log && !should_stop_here)
39963e5fb76SJonas Devlieghere           LLDB_LOGF(log,
40063e5fb76SJonas Devlieghere                     "Stepping out of frame %s which did not match step into "
401b9c1b51eSKate Stone                     "target %s.",
4023101ba33SJim Ingham                     sc.GetFunctionName().AsCString(),
4033101ba33SJim Ingham                     step_in_range_plan->m_step_into_target.AsCString());
404c627682eSJim Ingham       }
405c627682eSJim Ingham     }
406c627682eSJim Ingham 
407b9c1b51eSKate Stone     if (should_stop_here) {
408b9c1b51eSKate Stone       ThreadPlanStepInRange *step_in_range_plan =
409b9c1b51eSKate Stone           static_cast<ThreadPlanStepInRange *>(current_plan);
410b9c1b51eSKate Stone       // Don't log the should_step_out here, it's easier to do it in
411b9c1b51eSKate Stone       // FrameMatchesAvoidCriteria.
4124b4b2478SJim Ingham       should_stop_here = !step_in_range_plan->FrameMatchesAvoidCriteria();
413a56c8006SJim Ingham     }
414a56c8006SJim Ingham   }
415a56c8006SJim Ingham 
4164b4b2478SJim Ingham   return should_stop_here;
41730fdc8d8SChris Lattner }
418fbbfe6ecSJim Ingham 
419b9c1b51eSKate Stone bool ThreadPlanStepInRange::DoPlanExplainsStop(Event *event_ptr) {
420fbbfe6ecSJim Ingham   // We always explain a stop.  Either we've just done a single step, in which
42105097246SAdrian Prantl   // case we'll do our ordinary processing, or we stopped for some reason that
42205097246SAdrian Prantl   // isn't handled by our sub-plans, in which case we want to just stop right
42305097246SAdrian Prantl   // away. In general, we don't want to mark the plan as complete for
42405097246SAdrian Prantl   // unexplained stops. For instance, if you step in to some code with no debug
42505097246SAdrian Prantl   // info, so you step out and in the course of that hit a breakpoint, then you
42605097246SAdrian Prantl   // want to stop & show the user the breakpoint, but not unship the step in
42705097246SAdrian Prantl   // plan, since you still may want to complete that plan when you continue.
42805097246SAdrian Prantl   // This is particularly true when doing "step in to target function."
429c627682eSJim Ingham   // stepping.
430fbbfe6ecSJim Ingham   //
43105097246SAdrian Prantl   // The only variation is that if we are doing "step by running to next
43205097246SAdrian Prantl   // branch" in which case if we hit our branch breakpoint we don't set the
43305097246SAdrian Prantl   // plan to complete.
434fbbfe6ecSJim Ingham 
4359b03fa0cSJim Ingham   bool return_value = false;
436f02a2e96SJim Ingham 
437b9c1b51eSKate Stone   if (m_virtual_step) {
438221d51cfSJim Ingham     return_value = true;
439b9c1b51eSKate Stone   } else {
44060c4118cSJim Ingham     StopInfoSP stop_info_sp = GetPrivateStopInfo();
441b9c1b51eSKate Stone     if (stop_info_sp) {
442fbbfe6ecSJim Ingham       StopReason reason = stop_info_sp->GetStopReason();
443fbbfe6ecSJim Ingham 
444b9c1b51eSKate Stone       if (reason == eStopReasonBreakpoint) {
445b9c1b51eSKate Stone         if (NextRangeBreakpointExplainsStop(stop_info_sp)) {
446221d51cfSJim Ingham           return_value = true;
447221d51cfSJim Ingham         }
448b9c1b51eSKate Stone       } else if (IsUsuallyUnexplainedStopReason(reason)) {
4495160ce5cSGreg Clayton         Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
450fbbfe6ecSJim Ingham         if (log)
451b9c1b51eSKate Stone           log->PutCString("ThreadPlanStepInRange got asked if it explains the "
452b9c1b51eSKate Stone                           "stop for some reason other than step.");
453221d51cfSJim Ingham         return_value = false;
454b9c1b51eSKate Stone       } else {
455221d51cfSJim Ingham         return_value = true;
456fbbfe6ecSJim Ingham       }
457b9c1b51eSKate Stone     } else
458221d51cfSJim Ingham       return_value = true;
459221d51cfSJim Ingham   }
460221d51cfSJim Ingham 
461221d51cfSJim Ingham   return return_value;
462fbbfe6ecSJim Ingham }
463513c6bb8SJim Ingham 
464b9c1b51eSKate Stone bool ThreadPlanStepInRange::DoWillResume(lldb::StateType resume_state,
465b9c1b51eSKate Stone                                          bool current_plan) {
46669fc298aSTamas Berghammer   m_virtual_step = false;
467b9c1b51eSKate Stone   if (resume_state == eStateStepping && current_plan) {
468e4598dc0SJim Ingham     Thread &thread = GetThread();
469513c6bb8SJim Ingham     // See if we are about to step over a virtual inlined call.
470e4598dc0SJim Ingham     bool step_without_resume = thread.DecrementCurrentInlinedDepth();
471b9c1b51eSKate Stone     if (step_without_resume) {
4725160ce5cSGreg Clayton       Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
47363e5fb76SJonas Devlieghere       LLDB_LOGF(log,
47463e5fb76SJonas Devlieghere                 "ThreadPlanStepInRange::DoWillResume: returning false, "
475b9c1b51eSKate Stone                 "inline_depth: %d",
476e4598dc0SJim Ingham                 thread.GetCurrentInlinedDepth());
477e4598dc0SJim Ingham       SetStopInfo(StopInfo::CreateStopReasonToTrace(thread));
478f02a2e96SJim Ingham 
479b9c1b51eSKate Stone       // FIXME: Maybe it would be better to create a InlineStep stop reason, but
480b9c1b51eSKate Stone       // then
481f02a2e96SJim Ingham       // the whole rest of the world would have to handle that stop reason.
482f02a2e96SJim Ingham       m_virtual_step = true;
483513c6bb8SJim Ingham     }
484513c6bb8SJim Ingham     return !step_without_resume;
485513c6bb8SJim Ingham   }
486221d51cfSJim Ingham   return true;
487513c6bb8SJim Ingham }
488246cb611SDaniel Malea 
489b9c1b51eSKate Stone bool ThreadPlanStepInRange::IsVirtualStep() { return m_virtual_step; }
490