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 // C Includes
1130fdc8d8SChris Lattner // C++ Includes
1230fdc8d8SChris Lattner // Other libraries and framework includes
1330fdc8d8SChris Lattner // Project includes
14e65b2cf2SEugene Zelenko #include "lldb/Target/ThreadPlanStepInRange.h"
1530fdc8d8SChris Lattner #include "lldb/Core/Log.h"
164da6206dSJim Ingham #include "lldb/Core/Module.h"
17*b9c1b51eSKate Stone #include "lldb/Core/RegularExpression.h"
1830fdc8d8SChris Lattner #include "lldb/Core/Stream.h"
197ce490c6SJim Ingham #include "lldb/Symbol/Function.h"
20*b9c1b51eSKate Stone #include "lldb/Symbol/Symbol.h"
2130fdc8d8SChris Lattner #include "lldb/Target/Process.h"
2230fdc8d8SChris Lattner #include "lldb/Target/RegisterContext.h"
23514487e8SGreg Clayton #include "lldb/Target/Target.h"
2430fdc8d8SChris Lattner #include "lldb/Target/Thread.h"
2530fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepOut.h"
2630fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepThrough.h"
2730fdc8d8SChris Lattner 
2830fdc8d8SChris Lattner using namespace lldb;
2930fdc8d8SChris Lattner using namespace lldb_private;
3030fdc8d8SChris Lattner 
31*b9c1b51eSKate Stone uint32_t ThreadPlanStepInRange::s_default_flag_values =
32*b9c1b51eSKate Stone     ThreadPlanShouldStopHere::eStepInAvoidNoDebug;
3330fdc8d8SChris Lattner 
3430fdc8d8SChris Lattner //----------------------------------------------------------------------
35*b9c1b51eSKate Stone // ThreadPlanStepInRange: Step through a stack range, either stepping over or
36*b9c1b51eSKate Stone // into
3730fdc8d8SChris Lattner // based on the value of \a type.
3830fdc8d8SChris Lattner //----------------------------------------------------------------------
3930fdc8d8SChris Lattner 
40*b9c1b51eSKate Stone ThreadPlanStepInRange::ThreadPlanStepInRange(
41*b9c1b51eSKate Stone     Thread &thread, const AddressRange &range,
42*b9c1b51eSKate Stone     const SymbolContext &addr_context, lldb::RunMode stop_others,
434b4b2478SJim Ingham     LazyBool step_in_avoids_code_without_debug_info,
44*b9c1b51eSKate Stone     LazyBool step_out_avoids_code_without_debug_info)
45*b9c1b51eSKate Stone     : ThreadPlanStepRange(ThreadPlan::eKindStepInRange,
46*b9c1b51eSKate Stone                           "Step Range stepping in", thread, range, addr_context,
47*b9c1b51eSKate Stone                           stop_others),
48*b9c1b51eSKate Stone       ThreadPlanShouldStopHere(this), m_step_past_prologue(true),
49*b9c1b51eSKate Stone       m_virtual_step(false) {
504b4b2478SJim Ingham   SetCallbacks();
5130fdc8d8SChris Lattner   SetFlagsToDefault();
52*b9c1b51eSKate Stone   SetupAvoidNoDebug(step_in_avoids_code_without_debug_info,
53*b9c1b51eSKate Stone                     step_out_avoids_code_without_debug_info);
5430fdc8d8SChris Lattner }
5530fdc8d8SChris Lattner 
56*b9c1b51eSKate Stone ThreadPlanStepInRange::ThreadPlanStepInRange(
57*b9c1b51eSKate Stone     Thread &thread, const AddressRange &range,
58*b9c1b51eSKate Stone     const SymbolContext &addr_context, const char *step_into_target,
59*b9c1b51eSKate Stone     lldb::RunMode stop_others, LazyBool step_in_avoids_code_without_debug_info,
60*b9c1b51eSKate Stone     LazyBool step_out_avoids_code_without_debug_info)
61*b9c1b51eSKate Stone     : ThreadPlanStepRange(ThreadPlan::eKindStepInRange,
62*b9c1b51eSKate Stone                           "Step Range stepping in", thread, range, addr_context,
63*b9c1b51eSKate Stone                           stop_others),
64*b9c1b51eSKate Stone       ThreadPlanShouldStopHere(this), m_step_past_prologue(true),
65*b9c1b51eSKate Stone       m_virtual_step(false), m_step_into_target(step_into_target) {
664b4b2478SJim Ingham   SetCallbacks();
67c627682eSJim Ingham   SetFlagsToDefault();
68*b9c1b51eSKate Stone   SetupAvoidNoDebug(step_in_avoids_code_without_debug_info,
69*b9c1b51eSKate Stone                     step_out_avoids_code_without_debug_info);
70c627682eSJim Ingham }
71c627682eSJim Ingham 
72e65b2cf2SEugene Zelenko ThreadPlanStepInRange::~ThreadPlanStepInRange() = default;
7330fdc8d8SChris Lattner 
74*b9c1b51eSKate Stone void ThreadPlanStepInRange::SetupAvoidNoDebug(
75*b9c1b51eSKate Stone     LazyBool step_in_avoids_code_without_debug_info,
76*b9c1b51eSKate Stone     LazyBool step_out_avoids_code_without_debug_info) {
774b4b2478SJim Ingham   bool avoid_nodebug = true;
784b4b2478SJim Ingham 
79*b9c1b51eSKate Stone   switch (step_in_avoids_code_without_debug_info) {
804b4b2478SJim Ingham   case eLazyBoolYes:
814b4b2478SJim Ingham     avoid_nodebug = true;
824b4b2478SJim Ingham     break;
834b4b2478SJim Ingham   case eLazyBoolNo:
844b4b2478SJim Ingham     avoid_nodebug = false;
854b4b2478SJim Ingham     break;
864b4b2478SJim Ingham   case eLazyBoolCalculate:
874b4b2478SJim Ingham     avoid_nodebug = m_thread.GetStepInAvoidsNoDebug();
884b4b2478SJim Ingham     break;
894b4b2478SJim Ingham   }
904b4b2478SJim Ingham   if (avoid_nodebug)
914b4b2478SJim Ingham     GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
924b4b2478SJim Ingham   else
934b4b2478SJim Ingham     GetFlags().Clear(ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
944b4b2478SJim Ingham 
95*b9c1b51eSKate Stone   switch (step_out_avoids_code_without_debug_info) {
964b4b2478SJim Ingham   case eLazyBoolYes:
974b4b2478SJim Ingham     avoid_nodebug = true;
984b4b2478SJim Ingham     break;
994b4b2478SJim Ingham   case eLazyBoolNo:
1004b4b2478SJim Ingham     avoid_nodebug = false;
1014b4b2478SJim Ingham     break;
1024b4b2478SJim Ingham   case eLazyBoolCalculate:
1034b4b2478SJim Ingham     avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug();
1044b4b2478SJim Ingham     break;
1054b4b2478SJim Ingham   }
1064b4b2478SJim Ingham   if (avoid_nodebug)
1074b4b2478SJim Ingham     GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
1084b4b2478SJim Ingham   else
1094b4b2478SJim Ingham     GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
1104b4b2478SJim Ingham }
1114b4b2478SJim Ingham 
112*b9c1b51eSKate Stone void ThreadPlanStepInRange::GetDescription(Stream *s,
113*b9c1b51eSKate Stone                                            lldb::DescriptionLevel level) {
114*b9c1b51eSKate Stone   if (level == lldb::eDescriptionLevelBrief) {
1152bdbfd50SJim Ingham     s->Printf("step in");
1162bdbfd50SJim Ingham     return;
1172bdbfd50SJim Ingham   }
1182bdbfd50SJim Ingham 
1192bdbfd50SJim Ingham   s->Printf("Stepping in");
1202bdbfd50SJim Ingham   bool printed_line_info = false;
121*b9c1b51eSKate Stone   if (m_addr_context.line_entry.IsValid()) {
1222bdbfd50SJim Ingham     s->Printf(" through line ");
1232bdbfd50SJim Ingham     m_addr_context.line_entry.DumpStopContext(s, false);
1242bdbfd50SJim Ingham     printed_line_info = true;
1252bdbfd50SJim Ingham   }
1262bdbfd50SJim Ingham 
1274d56e9c1SJim Ingham   const char *step_into_target = m_step_into_target.AsCString();
1284d56e9c1SJim Ingham   if (step_into_target && step_into_target[0] != '\0')
1292bdbfd50SJim Ingham     s->Printf(" targeting %s", m_step_into_target.AsCString());
1302bdbfd50SJim Ingham 
131*b9c1b51eSKate Stone   if (!printed_line_info || level == eDescriptionLevelVerbose) {
1322bdbfd50SJim Ingham     s->Printf(" using ranges:");
1332bdbfd50SJim Ingham     DumpRanges(s);
13430fdc8d8SChris Lattner   }
1352bdbfd50SJim Ingham 
1362bdbfd50SJim Ingham   s->PutChar('.');
13730fdc8d8SChris Lattner }
13830fdc8d8SChris Lattner 
139*b9c1b51eSKate Stone bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
1405160ce5cSGreg Clayton   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
14130fdc8d8SChris Lattner 
142*b9c1b51eSKate Stone   if (log) {
14330fdc8d8SChris Lattner     StreamString s;
144*b9c1b51eSKate Stone     s.Address(
145*b9c1b51eSKate Stone         m_thread.GetRegisterContext()->GetPC(),
1461ac04c30SGreg Clayton         m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
14730fdc8d8SChris Lattner     log->Printf("ThreadPlanStepInRange reached %s.", s.GetData());
14830fdc8d8SChris Lattner   }
14930fdc8d8SChris Lattner 
15025f66700SJim Ingham   if (IsPlanComplete())
15125f66700SJim Ingham     return true;
15225f66700SJim Ingham 
1534d56e9c1SJim Ingham   m_no_more_plans = false;
154*b9c1b51eSKate Stone   if (m_sub_plan_sp && m_sub_plan_sp->IsPlanComplete()) {
155*b9c1b51eSKate Stone     if (!m_sub_plan_sp->PlanSucceeded()) {
1564d56e9c1SJim Ingham       SetPlanComplete();
1574d56e9c1SJim Ingham       m_no_more_plans = true;
1584d56e9c1SJim Ingham       return true;
159*b9c1b51eSKate Stone     } else
1604d56e9c1SJim Ingham       m_sub_plan_sp.reset();
1614d56e9c1SJim Ingham   }
16230fdc8d8SChris Lattner 
163*b9c1b51eSKate Stone   if (m_virtual_step) {
164*b9c1b51eSKate Stone     // If we've just completed a virtual step, all we need to do is check for a
165*b9c1b51eSKate Stone     // ShouldStopHere plan, and otherwise
166f02a2e96SJim Ingham     // we're done.
167*b9c1b51eSKate Stone     // FIXME - This can be both a step in and a step out.  Probably should
168*b9c1b51eSKate Stone     // record which in the m_virtual_step.
1694b4b2478SJim Ingham     m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger);
170*b9c1b51eSKate Stone   } else {
171*b9c1b51eSKate Stone     // Stepping through should be done running other threads in general, since
172*b9c1b51eSKate Stone     // we're setting a breakpoint and
1734a58e968SJim Ingham     // continuing.  So only stop others if we are explicitly told to do so.
1749d790c5dSJim Ingham 
175e65b2cf2SEugene Zelenko     bool stop_others = (m_stop_others == lldb::eOnlyThisThread);
17630fdc8d8SChris Lattner 
177b5c0d1ccSJim Ingham     FrameComparison frame_order = CompareCurrentFrameToStartFrame();
178b5c0d1ccSJim Ingham 
179*b9c1b51eSKate Stone     if (frame_order == eFrameCompareOlder ||
180*b9c1b51eSKate Stone         frame_order == eFrameCompareSameParent) {
1815822173bSJim Ingham       // If we're in an older frame then we should stop.
1825822173bSJim Ingham       //
183*b9c1b51eSKate Stone       // A caveat to this is if we think the frame is older but we're actually
184*b9c1b51eSKate Stone       // in a trampoline.
185*b9c1b51eSKate Stone       // I'm going to make the assumption that you wouldn't RETURN to a
186*b9c1b51eSKate Stone       // trampoline.  So if we are
187*b9c1b51eSKate Stone       // in a trampoline we think the frame is older because the trampoline
188*b9c1b51eSKate Stone       // confused the backtracer.
189*b9c1b51eSKate Stone       m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false,
190*b9c1b51eSKate Stone                                                              stop_others);
191*b9c1b51eSKate Stone       if (!m_sub_plan_sp) {
1924b4b2478SJim Ingham         // Otherwise check the ShouldStopHere for step out:
193862d1bbdSJim Ingham         m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order);
1944b4b2478SJim Ingham         if (log)
1954b4b2478SJim Ingham           log->Printf("ShouldStopHere says we should step out of this frame.");
196*b9c1b51eSKate Stone       } else if (log) {
197*b9c1b51eSKate Stone         log->Printf(
198*b9c1b51eSKate Stone             "Thought I stepped out, but in fact arrived at a trampoline.");
1994b4b2478SJim Ingham       }
200*b9c1b51eSKate Stone     } else if (frame_order == eFrameCompareEqual && InSymbol()) {
2015822173bSJim Ingham       // If we are not in a place we should step through, we're done.
202*b9c1b51eSKate Stone       // One tricky bit here is that some stubs don't push a frame, so we have
203*b9c1b51eSKate Stone       // to check
2045822173bSJim Ingham       // both the case of a frame that is younger, or the same as this frame.
205*b9c1b51eSKate Stone       // However, if the frame is the same, and we are still in the symbol we
206*b9c1b51eSKate Stone       // started
207*b9c1b51eSKate Stone       // in, the we don't need to do this.  This first check isn't strictly
208*b9c1b51eSKate Stone       // necessary,
2095822173bSJim Ingham       // but it is more efficient.
2105822173bSJim Ingham 
211*b9c1b51eSKate Stone       // If we're still in the range, keep going, either by running to the next
212*b9c1b51eSKate Stone       // branch breakpoint, or by
213564d8bc2SJim Ingham       // stepping.
214*b9c1b51eSKate Stone       if (InRange()) {
215564d8bc2SJim Ingham         SetNextBranchBreakpoint();
216564d8bc2SJim Ingham         return false;
217564d8bc2SJim Ingham       }
218564d8bc2SJim Ingham 
2195822173bSJim Ingham       SetPlanComplete();
220c627682eSJim Ingham       m_no_more_plans = true;
2215822173bSJim Ingham       return true;
2225822173bSJim Ingham     }
2235822173bSJim Ingham 
224*b9c1b51eSKate Stone     // If we get to this point, we're not going to use a previously set "next
225*b9c1b51eSKate Stone     // branch" breakpoint, so delete it:
226564d8bc2SJim Ingham     ClearNextBranchBreakpoint();
227564d8bc2SJim Ingham 
2285822173bSJim Ingham     // We may have set the plan up above in the FrameIsOlder section:
2295822173bSJim Ingham 
2304d56e9c1SJim Ingham     if (!m_sub_plan_sp)
231*b9c1b51eSKate Stone       m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false,
232*b9c1b51eSKate Stone                                                              stop_others);
23308b87e0dSJim Ingham 
234*b9c1b51eSKate Stone     if (log) {
2354d56e9c1SJim Ingham       if (m_sub_plan_sp)
2364d56e9c1SJim Ingham         log->Printf("Found a step through plan: %s", m_sub_plan_sp->GetName());
23708b87e0dSJim Ingham       else
23808b87e0dSJim Ingham         log->Printf("No step through plan found.");
23908b87e0dSJim Ingham     }
24008b87e0dSJim Ingham 
241*b9c1b51eSKate Stone     // If not, give the "should_stop" callback a chance to push a plan to get us
242*b9c1b51eSKate Stone     // out of here.
24330fdc8d8SChris Lattner     // But only do that if we actually have stepped in.
2444d56e9c1SJim Ingham     if (!m_sub_plan_sp && frame_order == eFrameCompareYounger)
2454b4b2478SJim Ingham       m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order);
24630fdc8d8SChris Lattner 
247*b9c1b51eSKate Stone     // If we've stepped in and we are going to stop here, check to see if we
248*b9c1b51eSKate Stone     // were asked to
2497ce490c6SJim Ingham     // run past the prologue, and if so do that.
2507ce490c6SJim Ingham 
251*b9c1b51eSKate Stone     if (!m_sub_plan_sp && frame_order == eFrameCompareYounger &&
252*b9c1b51eSKate Stone         m_step_past_prologue) {
253b57e4a1bSJason Molenda       lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0);
254*b9c1b51eSKate Stone       if (curr_frame) {
2557ce490c6SJim Ingham         size_t bytes_to_skip = 0;
2567ce490c6SJim Ingham         lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC();
2577ce490c6SJim Ingham         Address func_start_address;
2587ce490c6SJim Ingham 
259*b9c1b51eSKate Stone         SymbolContext sc = curr_frame->GetSymbolContext(eSymbolContextFunction |
260*b9c1b51eSKate Stone                                                         eSymbolContextSymbol);
2617ce490c6SJim Ingham 
262*b9c1b51eSKate Stone         if (sc.function) {
2637ce490c6SJim Ingham           func_start_address = sc.function->GetAddressRange().GetBaseAddress();
264*b9c1b51eSKate Stone           if (curr_addr ==
265*b9c1b51eSKate Stone               func_start_address.GetLoadAddress(
266*b9c1b51eSKate Stone                   m_thread.CalculateTarget().get()))
2677ce490c6SJim Ingham             bytes_to_skip = sc.function->GetPrologueByteSize();
268*b9c1b51eSKate Stone         } else if (sc.symbol) {
269e7612134SGreg Clayton           func_start_address = sc.symbol->GetAddress();
270*b9c1b51eSKate Stone           if (curr_addr ==
271*b9c1b51eSKate Stone               func_start_address.GetLoadAddress(
272*b9c1b51eSKate Stone                   m_thread.CalculateTarget().get()))
2737ce490c6SJim Ingham             bytes_to_skip = sc.symbol->GetPrologueByteSize();
2747ce490c6SJim Ingham         }
2757ce490c6SJim Ingham 
276*b9c1b51eSKate Stone         if (bytes_to_skip != 0) {
2777ce490c6SJim Ingham           func_start_address.Slide(bytes_to_skip);
27820ad3c40SCaroline Tice           log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP);
2797ce490c6SJim Ingham           if (log)
2807ce490c6SJim Ingham             log->Printf("Pushing past prologue ");
2817ce490c6SJim Ingham 
282*b9c1b51eSKate Stone           m_sub_plan_sp = m_thread.QueueThreadPlanForRunToAddress(
283*b9c1b51eSKate Stone               false, func_start_address, true);
2847ce490c6SJim Ingham         }
2857ce490c6SJim Ingham       }
2867ce490c6SJim Ingham     }
287f02a2e96SJim Ingham   }
2887ce490c6SJim Ingham 
289*b9c1b51eSKate Stone   if (!m_sub_plan_sp) {
29030fdc8d8SChris Lattner     m_no_more_plans = true;
29130fdc8d8SChris Lattner     SetPlanComplete();
29230fdc8d8SChris Lattner     return true;
293*b9c1b51eSKate Stone   } else {
29430fdc8d8SChris Lattner     m_no_more_plans = false;
2952bdbfd50SJim Ingham     m_sub_plan_sp->SetPrivate(true);
29630fdc8d8SChris Lattner     return false;
29730fdc8d8SChris Lattner   }
29830fdc8d8SChris Lattner }
29930fdc8d8SChris Lattner 
300*b9c1b51eSKate Stone void ThreadPlanStepInRange::SetAvoidRegexp(const char *name) {
301e65b2cf2SEugene Zelenko   if (!m_avoid_regexp_ap)
302a56c8006SJim Ingham     m_avoid_regexp_ap.reset(new RegularExpression(name));
303a56c8006SJim Ingham 
304a56c8006SJim Ingham   m_avoid_regexp_ap->Compile(name);
305a56c8006SJim Ingham }
306a56c8006SJim Ingham 
307*b9c1b51eSKate Stone void ThreadPlanStepInRange::SetDefaultFlagValue(uint32_t new_value) {
30830fdc8d8SChris Lattner   // TODO: Should we test this for sanity?
30930fdc8d8SChris Lattner   ThreadPlanStepInRange::s_default_flag_values = new_value;
31030fdc8d8SChris Lattner }
31130fdc8d8SChris Lattner 
312*b9c1b51eSKate Stone bool ThreadPlanStepInRange::FrameMatchesAvoidCriteria() {
313b57e4a1bSJason Molenda   StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
314a56c8006SJim Ingham 
3154da6206dSJim Ingham   // Check the library list first, as that's cheapest:
316a786e539SJim Ingham   bool libraries_say_avoid = false;
317a786e539SJim Ingham 
3184da6206dSJim Ingham   FileSpecList libraries_to_avoid(GetThread().GetLibrariesToAvoid());
3194da6206dSJim Ingham   size_t num_libraries = libraries_to_avoid.GetSize();
320*b9c1b51eSKate Stone   if (num_libraries > 0) {
3214da6206dSJim Ingham     SymbolContext sc(frame->GetSymbolContext(eSymbolContextModule));
3224da6206dSJim Ingham     FileSpec frame_library(sc.module_sp->GetFileSpec());
3234da6206dSJim Ingham 
324*b9c1b51eSKate Stone     if (frame_library) {
325*b9c1b51eSKate Stone       for (size_t i = 0; i < num_libraries; i++) {
3264da6206dSJim Ingham         const FileSpec &file_spec(libraries_to_avoid.GetFileSpecAtIndex(i));
327*b9c1b51eSKate Stone         if (FileSpec::Equal(file_spec, frame_library, false)) {
3284da6206dSJim Ingham           libraries_say_avoid = true;
3294da6206dSJim Ingham           break;
3304da6206dSJim Ingham         }
3314da6206dSJim Ingham       }
3324da6206dSJim Ingham     }
333a786e539SJim Ingham   }
3344da6206dSJim Ingham   if (libraries_say_avoid)
3354da6206dSJim Ingham     return true;
3364da6206dSJim Ingham 
33767cc0636SGreg Clayton   const RegularExpression *avoid_regexp_to_use = m_avoid_regexp_ap.get();
338e65b2cf2SEugene Zelenko   if (avoid_regexp_to_use == nullptr)
339ee8aea10SJim Ingham     avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp();
340ee8aea10SJim Ingham 
341*b9c1b51eSKate Stone   if (avoid_regexp_to_use != nullptr) {
342*b9c1b51eSKate Stone     SymbolContext sc = frame->GetSymbolContext(
343*b9c1b51eSKate Stone         eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol);
344*b9c1b51eSKate Stone     if (sc.symbol != nullptr) {
345*b9c1b51eSKate Stone       const char *frame_function_name =
346*b9c1b51eSKate Stone           sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments)
347*b9c1b51eSKate Stone               .GetCString();
348*b9c1b51eSKate Stone       if (frame_function_name) {
349cf2667c4SJim Ingham         size_t num_matches = 0;
3505160ce5cSGreg Clayton         Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
3513101ba33SJim Ingham         if (log)
352cf2667c4SJim Ingham           num_matches = 1;
353bc43cab5SGreg Clayton 
354bc43cab5SGreg Clayton         RegularExpression::Match regex_match(num_matches);
355bc43cab5SGreg Clayton 
356*b9c1b51eSKate Stone         bool return_value =
357*b9c1b51eSKate Stone             avoid_regexp_to_use->Execute(frame_function_name, &regex_match);
358*b9c1b51eSKate Stone         if (return_value) {
359*b9c1b51eSKate Stone           if (log) {
360cf2667c4SJim Ingham             std::string match;
361bc43cab5SGreg Clayton             regex_match.GetMatchAtIndex(frame_function_name, 0, match);
362*b9c1b51eSKate Stone             log->Printf("Stepping out of function \"%s\" because it matches "
363*b9c1b51eSKate Stone                         "the avoid regexp \"%s\" - match substring: \"%s\".",
364*b9c1b51eSKate Stone                         frame_function_name, avoid_regexp_to_use->GetText(),
365cf2667c4SJim Ingham                         match.c_str());
366cf2667c4SJim Ingham           }
3673101ba33SJim Ingham         }
3683101ba33SJim Ingham         return return_value;
3693101ba33SJim Ingham       }
370a56c8006SJim Ingham     }
371a56c8006SJim Ingham   }
372a56c8006SJim Ingham   return false;
373a56c8006SJim Ingham }
374a56c8006SJim Ingham 
375*b9c1b51eSKate Stone bool ThreadPlanStepInRange::DefaultShouldStopHereCallback(
376*b9c1b51eSKate Stone     ThreadPlan *current_plan, Flags &flags, FrameComparison operation,
377*b9c1b51eSKate Stone     void *baton) {
3784b4b2478SJim Ingham   bool should_stop_here = true;
379b57e4a1bSJason Molenda   StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
3805160ce5cSGreg Clayton   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
38130fdc8d8SChris Lattner 
382*b9c1b51eSKate Stone   // First see if the ThreadPlanShouldStopHere default implementation thinks we
383*b9c1b51eSKate Stone   // should get out of here:
384*b9c1b51eSKate Stone   should_stop_here = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback(
385*b9c1b51eSKate Stone       current_plan, flags, operation, baton);
3860c2b9d2aSJim Ingham   if (!should_stop_here)
3870c2b9d2aSJim Ingham     return should_stop_here;
388a56c8006SJim Ingham 
389*b9c1b51eSKate Stone   if (should_stop_here && current_plan->GetKind() == eKindStepInRange &&
390*b9c1b51eSKate Stone       operation == eFrameCompareYounger) {
391*b9c1b51eSKate Stone     ThreadPlanStepInRange *step_in_range_plan =
392*b9c1b51eSKate Stone         static_cast<ThreadPlanStepInRange *>(current_plan);
393*b9c1b51eSKate Stone     if (step_in_range_plan->m_step_into_target) {
394*b9c1b51eSKate Stone       SymbolContext sc = frame->GetSymbolContext(
395*b9c1b51eSKate Stone           eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol);
396*b9c1b51eSKate Stone       if (sc.symbol != nullptr) {
397*b9c1b51eSKate Stone         // First try an exact match, since that's cheap with ConstStrings.  Then
398*b9c1b51eSKate Stone         // do a strstr compare.
399*b9c1b51eSKate Stone         if (step_in_range_plan->m_step_into_target == sc.GetFunctionName()) {
4004b4b2478SJim Ingham           should_stop_here = true;
401*b9c1b51eSKate Stone         } else {
402*b9c1b51eSKate Stone           const char *target_name =
403*b9c1b51eSKate Stone               step_in_range_plan->m_step_into_target.AsCString();
404c627682eSJim Ingham           const char *function_name = sc.GetFunctionName().AsCString();
405c627682eSJim Ingham 
406e65b2cf2SEugene Zelenko           if (function_name == nullptr)
4074b4b2478SJim Ingham             should_stop_here = false;
408e65b2cf2SEugene Zelenko           else if (strstr(function_name, target_name) == nullptr)
4094b4b2478SJim Ingham             should_stop_here = false;
410c627682eSJim Ingham         }
4114b4b2478SJim Ingham         if (log && !should_stop_here)
412*b9c1b51eSKate Stone           log->Printf("Stepping out of frame %s which did not match step into "
413*b9c1b51eSKate Stone                       "target %s.",
4143101ba33SJim Ingham                       sc.GetFunctionName().AsCString(),
4153101ba33SJim Ingham                       step_in_range_plan->m_step_into_target.AsCString());
416c627682eSJim Ingham       }
417c627682eSJim Ingham     }
418c627682eSJim Ingham 
419*b9c1b51eSKate Stone     if (should_stop_here) {
420*b9c1b51eSKate Stone       ThreadPlanStepInRange *step_in_range_plan =
421*b9c1b51eSKate Stone           static_cast<ThreadPlanStepInRange *>(current_plan);
422*b9c1b51eSKate Stone       // Don't log the should_step_out here, it's easier to do it in
423*b9c1b51eSKate Stone       // FrameMatchesAvoidCriteria.
4244b4b2478SJim Ingham       should_stop_here = !step_in_range_plan->FrameMatchesAvoidCriteria();
425a56c8006SJim Ingham     }
426a56c8006SJim Ingham   }
427a56c8006SJim Ingham 
4284b4b2478SJim Ingham   return should_stop_here;
42930fdc8d8SChris Lattner }
430fbbfe6ecSJim Ingham 
431*b9c1b51eSKate Stone bool ThreadPlanStepInRange::DoPlanExplainsStop(Event *event_ptr) {
432fbbfe6ecSJim Ingham   // We always explain a stop.  Either we've just done a single step, in which
433fbbfe6ecSJim Ingham   // case we'll do our ordinary processing, or we stopped for some
434*b9c1b51eSKate Stone   // reason that isn't handled by our sub-plans, in which case we want to just
435*b9c1b51eSKate Stone   // stop right
436fbbfe6ecSJim Ingham   // away.
437*b9c1b51eSKate Stone   // In general, we don't want to mark the plan as complete for unexplained
438*b9c1b51eSKate Stone   // stops.
439*b9c1b51eSKate Stone   // For instance, if you step in to some code with no debug info, so you step
440*b9c1b51eSKate Stone   // out
441*b9c1b51eSKate Stone   // and in the course of that hit a breakpoint, then you want to stop & show
442*b9c1b51eSKate Stone   // the user
443*b9c1b51eSKate Stone   // the breakpoint, but not unship the step in plan, since you still may want
444*b9c1b51eSKate Stone   // to complete that
445*b9c1b51eSKate Stone   // plan when you continue.  This is particularly true when doing "step in to
446*b9c1b51eSKate Stone   // target function."
447c627682eSJim Ingham   // stepping.
448fbbfe6ecSJim Ingham   //
449*b9c1b51eSKate Stone   // The only variation is that if we are doing "step by running to next branch"
450*b9c1b51eSKate Stone   // in which case
451fbbfe6ecSJim Ingham   // if we hit our branch breakpoint we don't set the plan to complete.
452fbbfe6ecSJim Ingham 
4539b03fa0cSJim Ingham   bool return_value = false;
454f02a2e96SJim Ingham 
455*b9c1b51eSKate Stone   if (m_virtual_step) {
456221d51cfSJim Ingham     return_value = true;
457*b9c1b51eSKate Stone   } else {
45860c4118cSJim Ingham     StopInfoSP stop_info_sp = GetPrivateStopInfo();
459*b9c1b51eSKate Stone     if (stop_info_sp) {
460fbbfe6ecSJim Ingham       StopReason reason = stop_info_sp->GetStopReason();
461fbbfe6ecSJim Ingham 
462*b9c1b51eSKate Stone       if (reason == eStopReasonBreakpoint) {
463*b9c1b51eSKate Stone         if (NextRangeBreakpointExplainsStop(stop_info_sp)) {
464221d51cfSJim Ingham           return_value = true;
465221d51cfSJim Ingham         }
466*b9c1b51eSKate Stone       } else if (IsUsuallyUnexplainedStopReason(reason)) {
4675160ce5cSGreg Clayton         Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
468fbbfe6ecSJim Ingham         if (log)
469*b9c1b51eSKate Stone           log->PutCString("ThreadPlanStepInRange got asked if it explains the "
470*b9c1b51eSKate Stone                           "stop for some reason other than step.");
471221d51cfSJim Ingham         return_value = false;
472*b9c1b51eSKate Stone       } else {
473221d51cfSJim Ingham         return_value = true;
474fbbfe6ecSJim Ingham       }
475*b9c1b51eSKate Stone     } else
476221d51cfSJim Ingham       return_value = true;
477221d51cfSJim Ingham   }
478221d51cfSJim Ingham 
479221d51cfSJim Ingham   return return_value;
480fbbfe6ecSJim Ingham }
481513c6bb8SJim Ingham 
482*b9c1b51eSKate Stone bool ThreadPlanStepInRange::DoWillResume(lldb::StateType resume_state,
483*b9c1b51eSKate Stone                                          bool current_plan) {
48469fc298aSTamas Berghammer   m_virtual_step = false;
485*b9c1b51eSKate Stone   if (resume_state == eStateStepping && current_plan) {
486513c6bb8SJim Ingham     // See if we are about to step over a virtual inlined call.
487513c6bb8SJim Ingham     bool step_without_resume = m_thread.DecrementCurrentInlinedDepth();
488*b9c1b51eSKate Stone     if (step_without_resume) {
4895160ce5cSGreg Clayton       Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
490513c6bb8SJim Ingham       if (log)
491*b9c1b51eSKate Stone         log->Printf("ThreadPlanStepInRange::DoWillResume: returning false, "
492*b9c1b51eSKate Stone                     "inline_depth: %d",
493513c6bb8SJim Ingham                     m_thread.GetCurrentInlinedDepth());
494513c6bb8SJim Ingham       SetStopInfo(StopInfo::CreateStopReasonToTrace(m_thread));
495f02a2e96SJim Ingham 
496*b9c1b51eSKate Stone       // FIXME: Maybe it would be better to create a InlineStep stop reason, but
497*b9c1b51eSKate Stone       // then
498f02a2e96SJim Ingham       // the whole rest of the world would have to handle that stop reason.
499f02a2e96SJim Ingham       m_virtual_step = true;
500513c6bb8SJim Ingham     }
501513c6bb8SJim Ingham     return !step_without_resume;
502513c6bb8SJim Ingham   }
503221d51cfSJim Ingham   return true;
504513c6bb8SJim Ingham }
505246cb611SDaniel Malea 
506*b9c1b51eSKate Stone bool ThreadPlanStepInRange::IsVirtualStep() { return m_virtual_step; }
507