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"
21c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.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
32b9c1b51eSKate Stone // ThreadPlanStepInRange: Step through a stack range, either stepping over or
3305097246SAdrian Prantl // into based on the value of \a type.
3430fdc8d8SChris Lattner
ThreadPlanStepInRange(Thread & thread,const AddressRange & range,const SymbolContext & addr_context,const char * step_into_target,lldb::RunMode stop_others,LazyBool step_in_avoids_code_without_debug_info,LazyBool step_out_avoids_code_without_debug_info)35b9c1b51eSKate Stone ThreadPlanStepInRange::ThreadPlanStepInRange(
36b9c1b51eSKate Stone Thread &thread, const AddressRange &range,
37a5ab1dc4SDave Lee const SymbolContext &addr_context, const char *step_into_target,
38a5ab1dc4SDave Lee lldb::RunMode stop_others, LazyBool step_in_avoids_code_without_debug_info,
39b9c1b51eSKate Stone LazyBool step_out_avoids_code_without_debug_info)
40b9c1b51eSKate Stone : ThreadPlanStepRange(ThreadPlan::eKindStepInRange,
41b9c1b51eSKate Stone "Step Range stepping in", thread, range, addr_context,
42b9c1b51eSKate Stone stop_others),
43b9c1b51eSKate Stone ThreadPlanShouldStopHere(this), m_step_past_prologue(true),
44a5ab1dc4SDave Lee m_virtual_step(false), m_step_into_target(step_into_target) {
454b4b2478SJim Ingham SetCallbacks();
4630fdc8d8SChris Lattner SetFlagsToDefault();
47b9c1b51eSKate Stone SetupAvoidNoDebug(step_in_avoids_code_without_debug_info,
48b9c1b51eSKate Stone step_out_avoids_code_without_debug_info);
4930fdc8d8SChris Lattner }
5030fdc8d8SChris Lattner
51e65b2cf2SEugene Zelenko ThreadPlanStepInRange::~ThreadPlanStepInRange() = default;
5230fdc8d8SChris Lattner
SetupAvoidNoDebug(LazyBool step_in_avoids_code_without_debug_info,LazyBool step_out_avoids_code_without_debug_info)53b9c1b51eSKate Stone void ThreadPlanStepInRange::SetupAvoidNoDebug(
54b9c1b51eSKate Stone LazyBool step_in_avoids_code_without_debug_info,
55b9c1b51eSKate Stone LazyBool step_out_avoids_code_without_debug_info) {
564b4b2478SJim Ingham bool avoid_nodebug = true;
57e4598dc0SJim Ingham Thread &thread = GetThread();
58b9c1b51eSKate Stone switch (step_in_avoids_code_without_debug_info) {
594b4b2478SJim Ingham case eLazyBoolYes:
604b4b2478SJim Ingham avoid_nodebug = true;
614b4b2478SJim Ingham break;
624b4b2478SJim Ingham case eLazyBoolNo:
634b4b2478SJim Ingham avoid_nodebug = false;
644b4b2478SJim Ingham break;
654b4b2478SJim Ingham case eLazyBoolCalculate:
66e4598dc0SJim Ingham avoid_nodebug = thread.GetStepInAvoidsNoDebug();
674b4b2478SJim Ingham break;
684b4b2478SJim Ingham }
694b4b2478SJim Ingham if (avoid_nodebug)
704b4b2478SJim Ingham GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
714b4b2478SJim Ingham else
724b4b2478SJim Ingham GetFlags().Clear(ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
734b4b2478SJim Ingham
74b9c1b51eSKate Stone switch (step_out_avoids_code_without_debug_info) {
754b4b2478SJim Ingham case eLazyBoolYes:
764b4b2478SJim Ingham avoid_nodebug = true;
774b4b2478SJim Ingham break;
784b4b2478SJim Ingham case eLazyBoolNo:
794b4b2478SJim Ingham avoid_nodebug = false;
804b4b2478SJim Ingham break;
814b4b2478SJim Ingham case eLazyBoolCalculate:
82e4598dc0SJim Ingham avoid_nodebug = thread.GetStepOutAvoidsNoDebug();
834b4b2478SJim Ingham break;
844b4b2478SJim Ingham }
854b4b2478SJim Ingham if (avoid_nodebug)
864b4b2478SJim Ingham GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
874b4b2478SJim Ingham else
884b4b2478SJim Ingham GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
894b4b2478SJim Ingham }
904b4b2478SJim Ingham
GetDescription(Stream * s,lldb::DescriptionLevel level)91b9c1b51eSKate Stone void ThreadPlanStepInRange::GetDescription(Stream *s,
92b9c1b51eSKate Stone lldb::DescriptionLevel level) {
93e103ae92SJonas Devlieghere
94e103ae92SJonas Devlieghere auto PrintFailureIfAny = [&]() {
95e103ae92SJonas Devlieghere if (m_status.Success())
96e103ae92SJonas Devlieghere return;
97e103ae92SJonas Devlieghere s->Printf(" failed (%s)", m_status.AsCString());
98e103ae92SJonas Devlieghere };
99e103ae92SJonas Devlieghere
100b9c1b51eSKate Stone if (level == lldb::eDescriptionLevelBrief) {
1012bdbfd50SJim Ingham s->Printf("step in");
102e103ae92SJonas Devlieghere PrintFailureIfAny();
1032bdbfd50SJim Ingham return;
1042bdbfd50SJim Ingham }
1052bdbfd50SJim Ingham
1062bdbfd50SJim Ingham s->Printf("Stepping in");
1072bdbfd50SJim Ingham bool printed_line_info = false;
108b9c1b51eSKate Stone if (m_addr_context.line_entry.IsValid()) {
1092bdbfd50SJim Ingham s->Printf(" through line ");
1102bdbfd50SJim Ingham m_addr_context.line_entry.DumpStopContext(s, false);
1112bdbfd50SJim Ingham printed_line_info = true;
1122bdbfd50SJim Ingham }
1132bdbfd50SJim Ingham
1144d56e9c1SJim Ingham const char *step_into_target = m_step_into_target.AsCString();
1154d56e9c1SJim Ingham if (step_into_target && step_into_target[0] != '\0')
1162bdbfd50SJim Ingham s->Printf(" targeting %s", m_step_into_target.AsCString());
1172bdbfd50SJim Ingham
118b9c1b51eSKate Stone if (!printed_line_info || level == eDescriptionLevelVerbose) {
1192bdbfd50SJim Ingham s->Printf(" using ranges:");
1202bdbfd50SJim Ingham DumpRanges(s);
12130fdc8d8SChris Lattner }
1222bdbfd50SJim Ingham
123e103ae92SJonas Devlieghere PrintFailureIfAny();
124e103ae92SJonas Devlieghere
1252bdbfd50SJim Ingham s->PutChar('.');
12630fdc8d8SChris Lattner }
12730fdc8d8SChris Lattner
ShouldStop(Event * event_ptr)128b9c1b51eSKate Stone bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
129a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Step);
13030fdc8d8SChris Lattner
131b9c1b51eSKate Stone if (log) {
13230fdc8d8SChris Lattner StreamString s;
133e4598dc0SJim Ingham DumpAddress(s.AsRawOstream(), GetThread().GetRegisterContext()->GetPC(),
134e4598dc0SJim Ingham GetTarget().GetArchitecture().GetAddressByteSize());
13563e5fb76SJonas Devlieghere LLDB_LOGF(log, "ThreadPlanStepInRange reached %s.", s.GetData());
13630fdc8d8SChris Lattner }
13730fdc8d8SChris Lattner
13825f66700SJim Ingham if (IsPlanComplete())
13925f66700SJim Ingham return true;
14025f66700SJim Ingham
1414d56e9c1SJim Ingham m_no_more_plans = false;
142b9c1b51eSKate Stone if (m_sub_plan_sp && m_sub_plan_sp->IsPlanComplete()) {
143b9c1b51eSKate Stone if (!m_sub_plan_sp->PlanSucceeded()) {
1444d56e9c1SJim Ingham SetPlanComplete();
1454d56e9c1SJim Ingham m_no_more_plans = true;
1464d56e9c1SJim Ingham return true;
147b9c1b51eSKate Stone } else
1484d56e9c1SJim Ingham m_sub_plan_sp.reset();
1494d56e9c1SJim Ingham }
15030fdc8d8SChris Lattner
151b9c1b51eSKate Stone if (m_virtual_step) {
152b9c1b51eSKate Stone // If we've just completed a virtual step, all we need to do is check for a
15305097246SAdrian Prantl // ShouldStopHere plan, and otherwise we're done.
154b9c1b51eSKate Stone // FIXME - This can be both a step in and a step out. Probably should
155b9c1b51eSKate Stone // record which in the m_virtual_step.
156e103ae92SJonas Devlieghere m_sub_plan_sp =
157e103ae92SJonas Devlieghere CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger, m_status);
158b9c1b51eSKate Stone } else {
159b9c1b51eSKate Stone // Stepping through should be done running other threads in general, since
16005097246SAdrian Prantl // we're setting a breakpoint and continuing. So only stop others if we
16105097246SAdrian Prantl // are explicitly told to do so.
1629d790c5dSJim Ingham
163e65b2cf2SEugene Zelenko bool stop_others = (m_stop_others == lldb::eOnlyThisThread);
16430fdc8d8SChris Lattner
165b5c0d1ccSJim Ingham FrameComparison frame_order = CompareCurrentFrameToStartFrame();
166b5c0d1ccSJim Ingham
167e4598dc0SJim Ingham Thread &thread = GetThread();
168b9c1b51eSKate Stone if (frame_order == eFrameCompareOlder ||
169b9c1b51eSKate Stone frame_order == eFrameCompareSameParent) {
1705822173bSJim Ingham // If we're in an older frame then we should stop.
1715822173bSJim Ingham //
172b9c1b51eSKate Stone // A caveat to this is if we think the frame is older but we're actually
173b9c1b51eSKate Stone // in a trampoline.
174b9c1b51eSKate Stone // I'm going to make the assumption that you wouldn't RETURN to a
17505097246SAdrian Prantl // trampoline. So if we are in a trampoline we think the frame is older
17605097246SAdrian Prantl // because the trampoline confused the backtracer.
177e4598dc0SJim Ingham m_sub_plan_sp = thread.QueueThreadPlanForStepThrough(
178e103ae92SJonas Devlieghere m_stack_id, false, stop_others, m_status);
179b9c1b51eSKate Stone if (!m_sub_plan_sp) {
1804b4b2478SJim Ingham // Otherwise check the ShouldStopHere for step out:
181e103ae92SJonas Devlieghere m_sub_plan_sp =
182e103ae92SJonas Devlieghere CheckShouldStopHereAndQueueStepOut(frame_order, m_status);
183a4bb80b2SJim Ingham if (log) {
184a4bb80b2SJim Ingham if (m_sub_plan_sp)
18563e5fb76SJonas Devlieghere LLDB_LOGF(log,
18663e5fb76SJonas Devlieghere "ShouldStopHere found plan to step out of this frame.");
187a4bb80b2SJim Ingham else
18863e5fb76SJonas Devlieghere LLDB_LOGF(log, "ShouldStopHere no plan to step out of this frame.");
189a4bb80b2SJim Ingham }
190b9c1b51eSKate Stone } else if (log) {
19163e5fb76SJonas Devlieghere LLDB_LOGF(
19263e5fb76SJonas Devlieghere log, "Thought I stepped out, but in fact arrived at a trampoline.");
1934b4b2478SJim Ingham }
194b9c1b51eSKate Stone } else if (frame_order == eFrameCompareEqual && InSymbol()) {
19505097246SAdrian Prantl // If we are not in a place we should step through, we're done. One
19605097246SAdrian Prantl // tricky bit here is that some stubs don't push a frame, so we have to
19705097246SAdrian Prantl // check both the case of a frame that is younger, or the same as this
19805097246SAdrian Prantl // frame. However, if the frame is the same, and we are still in the
19905097246SAdrian Prantl // symbol we started in, the we don't need to do this. This first check
20005097246SAdrian Prantl // isn't strictly necessary, but it is more efficient.
2015822173bSJim Ingham
202b9c1b51eSKate Stone // If we're still in the range, keep going, either by running to the next
20305097246SAdrian Prantl // branch breakpoint, or by stepping.
204b9c1b51eSKate Stone if (InRange()) {
205564d8bc2SJim Ingham SetNextBranchBreakpoint();
206564d8bc2SJim Ingham return false;
207564d8bc2SJim Ingham }
208564d8bc2SJim Ingham
2095822173bSJim Ingham SetPlanComplete();
210c627682eSJim Ingham m_no_more_plans = true;
2115822173bSJim Ingham return true;
2125822173bSJim Ingham }
2135822173bSJim Ingham
214b9c1b51eSKate Stone // If we get to this point, we're not going to use a previously set "next
215b9c1b51eSKate Stone // branch" breakpoint, so delete it:
216564d8bc2SJim Ingham ClearNextBranchBreakpoint();
217564d8bc2SJim Ingham
2185822173bSJim Ingham // We may have set the plan up above in the FrameIsOlder section:
2195822173bSJim Ingham
2204d56e9c1SJim Ingham if (!m_sub_plan_sp)
221e4598dc0SJim Ingham m_sub_plan_sp = thread.QueueThreadPlanForStepThrough(
222e103ae92SJonas Devlieghere m_stack_id, false, stop_others, m_status);
22308b87e0dSJim Ingham
224b9c1b51eSKate Stone if (log) {
2254d56e9c1SJim Ingham if (m_sub_plan_sp)
22663e5fb76SJonas Devlieghere LLDB_LOGF(log, "Found a step through plan: %s",
22763e5fb76SJonas Devlieghere m_sub_plan_sp->GetName());
22808b87e0dSJim Ingham else
22963e5fb76SJonas Devlieghere LLDB_LOGF(log, "No step through plan found.");
23008b87e0dSJim Ingham }
23108b87e0dSJim Ingham
23205097246SAdrian Prantl // If not, give the "should_stop" callback a chance to push a plan to get
23305097246SAdrian Prantl // us out of here. But only do that if we actually have stepped in.
2344d56e9c1SJim Ingham if (!m_sub_plan_sp && frame_order == eFrameCompareYounger)
235e103ae92SJonas Devlieghere m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order, m_status);
23630fdc8d8SChris Lattner
237b9c1b51eSKate Stone // If we've stepped in and we are going to stop here, check to see if we
23805097246SAdrian Prantl // were asked to run past the prologue, and if so do that.
2397ce490c6SJim Ingham
240b9c1b51eSKate Stone if (!m_sub_plan_sp && frame_order == eFrameCompareYounger &&
241b9c1b51eSKate Stone m_step_past_prologue) {
242e4598dc0SJim Ingham lldb::StackFrameSP curr_frame = thread.GetStackFrameAtIndex(0);
243b9c1b51eSKate Stone if (curr_frame) {
2447ce490c6SJim Ingham size_t bytes_to_skip = 0;
245e4598dc0SJim Ingham lldb::addr_t curr_addr = thread.GetRegisterContext()->GetPC();
2467ce490c6SJim Ingham Address func_start_address;
2477ce490c6SJim Ingham
248b9c1b51eSKate Stone SymbolContext sc = curr_frame->GetSymbolContext(eSymbolContextFunction |
249b9c1b51eSKate Stone eSymbolContextSymbol);
2507ce490c6SJim Ingham
251b9c1b51eSKate Stone if (sc.function) {
2527ce490c6SJim Ingham func_start_address = sc.function->GetAddressRange().GetBaseAddress();
253e4598dc0SJim Ingham if (curr_addr == func_start_address.GetLoadAddress(&GetTarget()))
2547ce490c6SJim Ingham bytes_to_skip = sc.function->GetPrologueByteSize();
255b9c1b51eSKate Stone } else if (sc.symbol) {
256e7612134SGreg Clayton func_start_address = sc.symbol->GetAddress();
257e4598dc0SJim Ingham if (curr_addr == func_start_address.GetLoadAddress(&GetTarget()))
2587ce490c6SJim Ingham bytes_to_skip = sc.symbol->GetPrologueByteSize();
2597ce490c6SJim Ingham }
2607ce490c6SJim Ingham
26108581263SJim Ingham if (bytes_to_skip == 0 && sc.symbol) {
262e4598dc0SJim Ingham const Architecture *arch = GetTarget().GetArchitecturePlugin();
26308581263SJim Ingham if (arch) {
26408581263SJim Ingham Address curr_sec_addr;
265e4598dc0SJim Ingham GetTarget().GetSectionLoadList().ResolveLoadAddress(curr_addr,
26608581263SJim Ingham curr_sec_addr);
26708581263SJim Ingham bytes_to_skip = arch->GetBytesToSkip(*sc.symbol, curr_sec_addr);
26808581263SJim Ingham }
26908581263SJim Ingham }
27008581263SJim Ingham
271b9c1b51eSKate Stone if (bytes_to_skip != 0) {
2727ce490c6SJim Ingham func_start_address.Slide(bytes_to_skip);
273a007a6d8SPavel Labath log = GetLog(LLDBLog::Step);
27463e5fb76SJonas Devlieghere LLDB_LOGF(log, "Pushing past prologue ");
2757ce490c6SJim Ingham
276e4598dc0SJim Ingham m_sub_plan_sp = thread.QueueThreadPlanForRunToAddress(
277e103ae92SJonas Devlieghere false, func_start_address, true, m_status);
2787ce490c6SJim Ingham }
2797ce490c6SJim Ingham }
2807ce490c6SJim Ingham }
281f02a2e96SJim Ingham }
2827ce490c6SJim Ingham
283b9c1b51eSKate Stone if (!m_sub_plan_sp) {
28430fdc8d8SChris Lattner m_no_more_plans = true;
28530fdc8d8SChris Lattner SetPlanComplete();
28630fdc8d8SChris Lattner return true;
287b9c1b51eSKate Stone } else {
28830fdc8d8SChris Lattner m_no_more_plans = false;
2892bdbfd50SJim Ingham m_sub_plan_sp->SetPrivate(true);
29030fdc8d8SChris Lattner return false;
29130fdc8d8SChris Lattner }
29230fdc8d8SChris Lattner }
29330fdc8d8SChris Lattner
SetAvoidRegexp(const char * name)294b9c1b51eSKate Stone void ThreadPlanStepInRange::SetAvoidRegexp(const char *name) {
295f9d90bc5SJan Kratochvil if (m_avoid_regexp_up)
296bbea3610SRaphael Isemann *m_avoid_regexp_up = RegularExpression(name);
297f9d90bc5SJan Kratochvil else
298bbea3610SRaphael Isemann m_avoid_regexp_up = std::make_unique<RegularExpression>(name);
299a56c8006SJim Ingham }
300a56c8006SJim Ingham
SetDefaultFlagValue(uint32_t new_value)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
FrameMatchesAvoidCriteria()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) {
343*02def06eSDave Lee bool return_value = avoid_regexp_to_use->Execute(frame_function_name);
344*02def06eSDave Lee if (return_value) {
345a007a6d8SPavel Labath LLDB_LOGF(GetLog(LLDBLog::Step),
346*02def06eSDave Lee "Stepping out of function \"%s\" because it matches the "
347*02def06eSDave Lee "avoid regexp \"%s\".",
34895eae423SZachary Turner frame_function_name,
349*02def06eSDave Lee avoid_regexp_to_use->GetText().str().c_str());
350cf2667c4SJim Ingham }
3513101ba33SJim Ingham return return_value;
3523101ba33SJim Ingham }
353a56c8006SJim Ingham }
354a56c8006SJim Ingham }
355a56c8006SJim Ingham return false;
356a56c8006SJim Ingham }
357a56c8006SJim Ingham
DefaultShouldStopHereCallback(ThreadPlan * current_plan,Flags & flags,FrameComparison operation,Status & status,void * baton)358b9c1b51eSKate Stone bool ThreadPlanStepInRange::DefaultShouldStopHereCallback(
359b9c1b51eSKate Stone ThreadPlan *current_plan, Flags &flags, FrameComparison operation,
360e103ae92SJonas Devlieghere Status &status, void *baton) {
3614b4b2478SJim Ingham bool should_stop_here = true;
362b57e4a1bSJason Molenda StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
363a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Step);
36430fdc8d8SChris Lattner
365b9c1b51eSKate Stone // First see if the ThreadPlanShouldStopHere default implementation thinks we
366b9c1b51eSKate Stone // should get out of here:
367b9c1b51eSKate Stone should_stop_here = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback(
368e103ae92SJonas Devlieghere current_plan, flags, operation, status, baton);
3690c2b9d2aSJim Ingham if (!should_stop_here)
370ec4c96d6SRaphael Isemann return false;
371a56c8006SJim Ingham
372b9c1b51eSKate Stone if (should_stop_here && current_plan->GetKind() == eKindStepInRange &&
373b9c1b51eSKate Stone operation == eFrameCompareYounger) {
374b9c1b51eSKate Stone ThreadPlanStepInRange *step_in_range_plan =
375b9c1b51eSKate Stone static_cast<ThreadPlanStepInRange *>(current_plan);
376b9c1b51eSKate Stone if (step_in_range_plan->m_step_into_target) {
377b9c1b51eSKate Stone SymbolContext sc = frame->GetSymbolContext(
378b9c1b51eSKate Stone eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol);
379b9c1b51eSKate Stone if (sc.symbol != nullptr) {
38005097246SAdrian Prantl // First try an exact match, since that's cheap with ConstStrings.
38105097246SAdrian Prantl // Then do a strstr compare.
382b9c1b51eSKate Stone if (step_in_range_plan->m_step_into_target == sc.GetFunctionName()) {
3834b4b2478SJim Ingham should_stop_here = true;
384b9c1b51eSKate Stone } else {
385b9c1b51eSKate Stone const char *target_name =
386b9c1b51eSKate Stone step_in_range_plan->m_step_into_target.AsCString();
387c627682eSJim Ingham const char *function_name = sc.GetFunctionName().AsCString();
388c627682eSJim Ingham
389e65b2cf2SEugene Zelenko if (function_name == nullptr)
3904b4b2478SJim Ingham should_stop_here = false;
391e65b2cf2SEugene Zelenko else if (strstr(function_name, target_name) == nullptr)
3924b4b2478SJim Ingham should_stop_here = false;
393c627682eSJim Ingham }
3944b4b2478SJim Ingham if (log && !should_stop_here)
39563e5fb76SJonas Devlieghere LLDB_LOGF(log,
39663e5fb76SJonas Devlieghere "Stepping out of frame %s which did not match step into "
397b9c1b51eSKate Stone "target %s.",
3983101ba33SJim Ingham sc.GetFunctionName().AsCString(),
3993101ba33SJim Ingham step_in_range_plan->m_step_into_target.AsCString());
400c627682eSJim Ingham }
401c627682eSJim Ingham }
402c627682eSJim Ingham
403b9c1b51eSKate Stone if (should_stop_here) {
404b9c1b51eSKate Stone ThreadPlanStepInRange *step_in_range_plan =
405b9c1b51eSKate Stone static_cast<ThreadPlanStepInRange *>(current_plan);
406b9c1b51eSKate Stone // Don't log the should_step_out here, it's easier to do it in
407b9c1b51eSKate Stone // FrameMatchesAvoidCriteria.
4084b4b2478SJim Ingham should_stop_here = !step_in_range_plan->FrameMatchesAvoidCriteria();
409a56c8006SJim Ingham }
410a56c8006SJim Ingham }
411a56c8006SJim Ingham
4124b4b2478SJim Ingham return should_stop_here;
41330fdc8d8SChris Lattner }
414fbbfe6ecSJim Ingham
DoPlanExplainsStop(Event * event_ptr)415b9c1b51eSKate Stone bool ThreadPlanStepInRange::DoPlanExplainsStop(Event *event_ptr) {
416fbbfe6ecSJim Ingham // We always explain a stop. Either we've just done a single step, in which
41705097246SAdrian Prantl // case we'll do our ordinary processing, or we stopped for some reason that
41805097246SAdrian Prantl // isn't handled by our sub-plans, in which case we want to just stop right
41905097246SAdrian Prantl // away. In general, we don't want to mark the plan as complete for
42005097246SAdrian Prantl // unexplained stops. For instance, if you step in to some code with no debug
42105097246SAdrian Prantl // info, so you step out and in the course of that hit a breakpoint, then you
42205097246SAdrian Prantl // want to stop & show the user the breakpoint, but not unship the step in
42305097246SAdrian Prantl // plan, since you still may want to complete that plan when you continue.
42405097246SAdrian Prantl // This is particularly true when doing "step in to target function."
425c627682eSJim Ingham // stepping.
426fbbfe6ecSJim Ingham //
42705097246SAdrian Prantl // The only variation is that if we are doing "step by running to next
42805097246SAdrian Prantl // branch" in which case if we hit our branch breakpoint we don't set the
42905097246SAdrian Prantl // plan to complete.
430fbbfe6ecSJim Ingham
4319b03fa0cSJim Ingham bool return_value = false;
432f02a2e96SJim Ingham
433b9c1b51eSKate Stone if (m_virtual_step) {
434221d51cfSJim Ingham return_value = true;
435b9c1b51eSKate Stone } else {
43660c4118cSJim Ingham StopInfoSP stop_info_sp = GetPrivateStopInfo();
437b9c1b51eSKate Stone if (stop_info_sp) {
438fbbfe6ecSJim Ingham StopReason reason = stop_info_sp->GetStopReason();
439fbbfe6ecSJim Ingham
440b9c1b51eSKate Stone if (reason == eStopReasonBreakpoint) {
441b9c1b51eSKate Stone if (NextRangeBreakpointExplainsStop(stop_info_sp)) {
442221d51cfSJim Ingham return_value = true;
443221d51cfSJim Ingham }
444b9c1b51eSKate Stone } else if (IsUsuallyUnexplainedStopReason(reason)) {
445a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Step);
446fbbfe6ecSJim Ingham if (log)
447b9c1b51eSKate Stone log->PutCString("ThreadPlanStepInRange got asked if it explains the "
448b9c1b51eSKate Stone "stop for some reason other than step.");
449221d51cfSJim Ingham return_value = false;
450b9c1b51eSKate Stone } else {
451221d51cfSJim Ingham return_value = true;
452fbbfe6ecSJim Ingham }
453b9c1b51eSKate Stone } else
454221d51cfSJim Ingham return_value = true;
455221d51cfSJim Ingham }
456221d51cfSJim Ingham
457221d51cfSJim Ingham return return_value;
458fbbfe6ecSJim Ingham }
459513c6bb8SJim Ingham
DoWillResume(lldb::StateType resume_state,bool current_plan)460b9c1b51eSKate Stone bool ThreadPlanStepInRange::DoWillResume(lldb::StateType resume_state,
461b9c1b51eSKate Stone bool current_plan) {
46269fc298aSTamas Berghammer m_virtual_step = false;
463b9c1b51eSKate Stone if (resume_state == eStateStepping && current_plan) {
464e4598dc0SJim Ingham Thread &thread = GetThread();
465513c6bb8SJim Ingham // See if we are about to step over a virtual inlined call.
466e4598dc0SJim Ingham bool step_without_resume = thread.DecrementCurrentInlinedDepth();
467b9c1b51eSKate Stone if (step_without_resume) {
468a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Step);
46963e5fb76SJonas Devlieghere LLDB_LOGF(log,
47063e5fb76SJonas Devlieghere "ThreadPlanStepInRange::DoWillResume: returning false, "
471b9c1b51eSKate Stone "inline_depth: %d",
472e4598dc0SJim Ingham thread.GetCurrentInlinedDepth());
473e4598dc0SJim Ingham SetStopInfo(StopInfo::CreateStopReasonToTrace(thread));
474f02a2e96SJim Ingham
475b9c1b51eSKate Stone // FIXME: Maybe it would be better to create a InlineStep stop reason, but
476b9c1b51eSKate Stone // then
477f02a2e96SJim Ingham // the whole rest of the world would have to handle that stop reason.
478f02a2e96SJim Ingham m_virtual_step = true;
479513c6bb8SJim Ingham }
480513c6bb8SJim Ingham return !step_without_resume;
481513c6bb8SJim Ingham }
482221d51cfSJim Ingham return true;
483513c6bb8SJim Ingham }
484246cb611SDaniel Malea
IsVirtualStep()485b9c1b51eSKate Stone bool ThreadPlanStepInRange::IsVirtualStep() { return m_virtual_step; }
486