1cfca06d7SDimitry Andric //===-- ThreadPlanStepOverRange.cpp ---------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste
9e81d9d49SDimitry Andric #include "lldb/Target/ThreadPlanStepOverRange.h"
10f034231aSEd Maste #include "lldb/Symbol/Block.h"
11f034231aSEd Maste #include "lldb/Symbol/CompileUnit.h"
12f034231aSEd Maste #include "lldb/Symbol/Function.h"
13f034231aSEd Maste #include "lldb/Symbol/LineTable.h"
14f034231aSEd Maste #include "lldb/Target/Process.h"
15f034231aSEd Maste #include "lldb/Target/RegisterContext.h"
16f034231aSEd Maste #include "lldb/Target/Target.h"
17f034231aSEd Maste #include "lldb/Target/Thread.h"
18f034231aSEd Maste #include "lldb/Target/ThreadPlanStepOut.h"
19f034231aSEd Maste #include "lldb/Target/ThreadPlanStepThrough.h"
20145449b1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
2174a628f7SDimitry Andric #include "lldb/Utility/Log.h"
2274a628f7SDimitry Andric #include "lldb/Utility/Stream.h"
23f034231aSEd Maste
24f034231aSEd Maste using namespace lldb_private;
25f034231aSEd Maste using namespace lldb;
26f034231aSEd Maste
270cac4ca3SEd Maste uint32_t ThreadPlanStepOverRange::s_default_flag_values = 0;
28f034231aSEd Maste
2914f1b3e8SDimitry Andric // ThreadPlanStepOverRange: Step through a stack range, either stepping over or
30f73363f1SDimitry Andric // into based on the value of \a type.
31f034231aSEd Maste
ThreadPlanStepOverRange(Thread & thread,const AddressRange & range,const SymbolContext & addr_context,lldb::RunMode stop_others,LazyBool step_out_avoids_code_without_debug_info)3214f1b3e8SDimitry Andric ThreadPlanStepOverRange::ThreadPlanStepOverRange(
3314f1b3e8SDimitry Andric Thread &thread, const AddressRange &range,
3414f1b3e8SDimitry Andric const SymbolContext &addr_context, lldb::RunMode stop_others,
3514f1b3e8SDimitry Andric LazyBool step_out_avoids_code_without_debug_info)
3614f1b3e8SDimitry Andric : ThreadPlanStepRange(ThreadPlan::eKindStepOverRange,
3714f1b3e8SDimitry Andric "Step range stepping over", thread, range,
3814f1b3e8SDimitry Andric addr_context, stop_others),
3914f1b3e8SDimitry Andric ThreadPlanShouldStopHere(this), m_first_resume(true) {
400cac4ca3SEd Maste SetFlagsToDefault();
410cac4ca3SEd Maste SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
42f034231aSEd Maste }
43f034231aSEd Maste
44e81d9d49SDimitry Andric ThreadPlanStepOverRange::~ThreadPlanStepOverRange() = default;
45f034231aSEd Maste
GetDescription(Stream * s,lldb::DescriptionLevel level)4614f1b3e8SDimitry Andric void ThreadPlanStepOverRange::GetDescription(Stream *s,
4714f1b3e8SDimitry Andric lldb::DescriptionLevel level) {
4894994d37SDimitry Andric auto PrintFailureIfAny = [&]() {
4994994d37SDimitry Andric if (m_status.Success())
5094994d37SDimitry Andric return;
5194994d37SDimitry Andric s->Printf(" failed (%s)", m_status.AsCString());
5294994d37SDimitry Andric };
5394994d37SDimitry Andric
5414f1b3e8SDimitry Andric if (level == lldb::eDescriptionLevelBrief) {
55205afe67SEd Maste s->Printf("step over");
5694994d37SDimitry Andric PrintFailureIfAny();
57205afe67SEd Maste return;
58205afe67SEd Maste }
5994994d37SDimitry Andric
60205afe67SEd Maste s->Printf("Stepping over");
61205afe67SEd Maste bool printed_line_info = false;
6214f1b3e8SDimitry Andric if (m_addr_context.line_entry.IsValid()) {
63205afe67SEd Maste s->Printf(" line ");
64205afe67SEd Maste m_addr_context.line_entry.DumpStopContext(s, false);
65205afe67SEd Maste printed_line_info = true;
66205afe67SEd Maste }
67205afe67SEd Maste
6814f1b3e8SDimitry Andric if (!printed_line_info || level == eDescriptionLevelVerbose) {
69205afe67SEd Maste s->Printf(" using ranges: ");
70f034231aSEd Maste DumpRanges(s);
71f034231aSEd Maste }
72205afe67SEd Maste
7394994d37SDimitry Andric PrintFailureIfAny();
7494994d37SDimitry Andric
75205afe67SEd Maste s->PutChar('.');
76f034231aSEd Maste }
77f034231aSEd Maste
SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info)7814f1b3e8SDimitry Andric void ThreadPlanStepOverRange::SetupAvoidNoDebug(
7914f1b3e8SDimitry Andric LazyBool step_out_avoids_code_without_debug_info) {
800cac4ca3SEd Maste bool avoid_nodebug = true;
8114f1b3e8SDimitry Andric switch (step_out_avoids_code_without_debug_info) {
820cac4ca3SEd Maste case eLazyBoolYes:
830cac4ca3SEd Maste avoid_nodebug = true;
840cac4ca3SEd Maste break;
850cac4ca3SEd Maste case eLazyBoolNo:
860cac4ca3SEd Maste avoid_nodebug = false;
870cac4ca3SEd Maste break;
880cac4ca3SEd Maste case eLazyBoolCalculate:
89cfca06d7SDimitry Andric avoid_nodebug = GetThread().GetStepOutAvoidsNoDebug();
900cac4ca3SEd Maste break;
910cac4ca3SEd Maste }
920cac4ca3SEd Maste if (avoid_nodebug)
930cac4ca3SEd Maste GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
940cac4ca3SEd Maste else
950cac4ca3SEd Maste GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
9614f1b3e8SDimitry Andric // Step Over plans should always avoid no-debug on step in. Seems like you
97f73363f1SDimitry Andric // shouldn't have to say this, but a tail call looks more like a step in that
98f73363f1SDimitry Andric // a step out, so we want to catch this case.
990cac4ca3SEd Maste GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
1000cac4ca3SEd Maste }
1010cac4ca3SEd Maste
IsEquivalentContext(const SymbolContext & context)10214f1b3e8SDimitry Andric bool ThreadPlanStepOverRange::IsEquivalentContext(
10314f1b3e8SDimitry Andric const SymbolContext &context) {
104f73363f1SDimitry Andric // Match as much as is specified in the m_addr_context: This is a fairly
105f73363f1SDimitry Andric // loose sanity check. Note, sometimes the target doesn't get filled in so I
106f73363f1SDimitry Andric // left out the target check. And sometimes the module comes in as the .o
107f73363f1SDimitry Andric // file from the inlined range, so I left that out too...
10814f1b3e8SDimitry Andric if (m_addr_context.comp_unit) {
10914f1b3e8SDimitry Andric if (m_addr_context.comp_unit != context.comp_unit)
11014f1b3e8SDimitry Andric return false;
11114f1b3e8SDimitry Andric if (m_addr_context.function) {
11214f1b3e8SDimitry Andric if (m_addr_context.function != context.function)
11314f1b3e8SDimitry Andric return false;
11414f1b3e8SDimitry Andric // It is okay to return to a different block of a straight function, we
115f73363f1SDimitry Andric // only have to be more careful if returning from one inlined block to
116f73363f1SDimitry Andric // another.
11714f1b3e8SDimitry Andric if (m_addr_context.block->GetInlinedFunctionInfo() == nullptr &&
11814f1b3e8SDimitry Andric context.block->GetInlinedFunctionInfo() == nullptr)
119f21a844fSEd Maste return true;
12014f1b3e8SDimitry Andric return m_addr_context.block == context.block;
121f21a844fSEd Maste }
122f21a844fSEd Maste }
12314f1b3e8SDimitry Andric // Fall back to symbol if we have no decision from comp_unit/function/block.
12494994d37SDimitry Andric return m_addr_context.symbol && m_addr_context.symbol == context.symbol;
125f21a844fSEd Maste }
126f21a844fSEd Maste
ShouldStop(Event * event_ptr)12714f1b3e8SDimitry Andric bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
128145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Step);
129cfca06d7SDimitry Andric Thread &thread = GetThread();
130f034231aSEd Maste
13114f1b3e8SDimitry Andric if (log) {
132f034231aSEd Maste StreamString s;
133cfca06d7SDimitry Andric DumpAddress(s.AsRawOstream(), thread.GetRegisterContext()->GetPC(),
134cfca06d7SDimitry Andric GetTarget().GetArchitecture().GetAddressByteSize());
135ead24645SDimitry Andric LLDB_LOGF(log, "ThreadPlanStepOverRange reached %s.", s.GetData());
136f034231aSEd Maste }
137f034231aSEd Maste
138f034231aSEd Maste // If we're out of the range but in the same frame or in our caller's frame
139f73363f1SDimitry Andric // then we should stop. When stepping out we only stop others if we are
140f73363f1SDimitry Andric // forcing running one thread.
141e81d9d49SDimitry Andric bool stop_others = (m_stop_others == lldb::eOnlyThisThread);
142f034231aSEd Maste ThreadPlanSP new_plan_sp;
143f034231aSEd Maste FrameComparison frame_order = CompareCurrentFrameToStartFrame();
144f034231aSEd Maste
14514f1b3e8SDimitry Andric if (frame_order == eFrameCompareOlder) {
146f034231aSEd Maste // If we're in an older frame then we should stop.
147f034231aSEd Maste //
14814f1b3e8SDimitry Andric // A caveat to this is if we think the frame is older but we're actually in
14914f1b3e8SDimitry Andric // a trampoline.
15014f1b3e8SDimitry Andric // I'm going to make the assumption that you wouldn't RETURN to a
151f73363f1SDimitry Andric // trampoline. So if we are in a trampoline we think the frame is older
152f73363f1SDimitry Andric // because the trampoline confused the backtracer. As below, we step
153f73363f1SDimitry Andric // through first, and then try to figure out how to get back out again.
154f034231aSEd Maste
155cfca06d7SDimitry Andric new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false,
15694994d37SDimitry Andric stop_others, m_status);
157f034231aSEd Maste
158f034231aSEd Maste if (new_plan_sp && log)
159ead24645SDimitry Andric LLDB_LOGF(log,
16014f1b3e8SDimitry Andric "Thought I stepped out, but in fact arrived at a trampoline.");
16114f1b3e8SDimitry Andric } else if (frame_order == eFrameCompareYounger) {
16214f1b3e8SDimitry Andric // Make sure we really are in a new frame. Do that by unwinding and seeing
163f73363f1SDimitry Andric // if the start function really is our start function...
16414f1b3e8SDimitry Andric for (uint32_t i = 1;; ++i) {
165cfca06d7SDimitry Andric StackFrameSP older_frame_sp = thread.GetStackFrameAtIndex(i);
166f21a844fSEd Maste if (!older_frame_sp) {
16714f1b3e8SDimitry Andric // We can't unwind the next frame we should just get out of here &
16814f1b3e8SDimitry Andric // stop...
169f21a844fSEd Maste break;
170f21a844fSEd Maste }
171f21a844fSEd Maste
17214f1b3e8SDimitry Andric const SymbolContext &older_context =
17314f1b3e8SDimitry Andric older_frame_sp->GetSymbolContext(eSymbolContextEverything);
17414f1b3e8SDimitry Andric if (IsEquivalentContext(older_context)) {
175cfca06d7SDimitry Andric // If we have the next-branch-breakpoint in the range, we can just
176cfca06d7SDimitry Andric // rely on that breakpoint to trigger once we return to the range.
177cfca06d7SDimitry Andric if (m_next_branch_bp_sp)
178cfca06d7SDimitry Andric return false;
179cfca06d7SDimitry Andric new_plan_sp = thread.QueueThreadPlanForStepOutNoShouldStop(
18014f1b3e8SDimitry Andric false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
18194994d37SDimitry Andric m_status, true);
182f21a844fSEd Maste break;
18314f1b3e8SDimitry Andric } else {
184cfca06d7SDimitry Andric new_plan_sp = thread.QueueThreadPlanForStepThrough(
18594994d37SDimitry Andric m_stack_id, false, stop_others, m_status);
1860cac4ca3SEd Maste // If we found a way through, then we should stop recursing.
1870cac4ca3SEd Maste if (new_plan_sp)
1880cac4ca3SEd Maste break;
189f034231aSEd Maste }
190f034231aSEd Maste }
19114f1b3e8SDimitry Andric } else {
192f034231aSEd Maste // If we're still in the range, keep going.
19314f1b3e8SDimitry Andric if (InRange()) {
194f034231aSEd Maste SetNextBranchBreakpoint();
195f034231aSEd Maste return false;
196f034231aSEd Maste }
197f034231aSEd Maste
19814f1b3e8SDimitry Andric if (!InSymbol()) {
19914f1b3e8SDimitry Andric // This one is a little tricky. Sometimes we may be in a stub or
200f73363f1SDimitry Andric // something similar, in which case we need to get out of there. But if
201f73363f1SDimitry Andric // we are in a stub then it's likely going to be hard to get out from
202f73363f1SDimitry Andric // here. It is probably easiest to step into the stub, and then it will
203f73363f1SDimitry Andric // be straight-forward to step out.
204cfca06d7SDimitry Andric new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false,
205cfca06d7SDimitry Andric stop_others, m_status);
20614f1b3e8SDimitry Andric } else {
207f73363f1SDimitry Andric // The current clang (at least through 424) doesn't always get the
208f73363f1SDimitry Andric // address range for the DW_TAG_inlined_subroutines right, so that when
209f73363f1SDimitry Andric // you leave the inlined range the line table says you are still in the
210f73363f1SDimitry Andric // source file of the inlining function. This is bad, because now you
211f73363f1SDimitry Andric // are missing the stack frame for the function containing the inlining,
212f73363f1SDimitry Andric // and if you sensibly do "finish" to get out of this function you will
213f73363f1SDimitry Andric // instead exit the containing function. To work around this, we check
214f73363f1SDimitry Andric // whether we are still in the source file we started in, and if not
215f73363f1SDimitry Andric // assume it is an error, and push a plan to get us out of this line and
216f73363f1SDimitry Andric // back to the containing file.
217f034231aSEd Maste
21814f1b3e8SDimitry Andric if (m_addr_context.line_entry.IsValid()) {
219f034231aSEd Maste SymbolContext sc;
220cfca06d7SDimitry Andric StackFrameSP frame_sp = thread.GetStackFrameAtIndex(0);
221f034231aSEd Maste sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
22214f1b3e8SDimitry Andric if (sc.line_entry.IsValid()) {
223ac9a064cSDimitry Andric if (!sc.line_entry.original_file_sp->Equal(
224ac9a064cSDimitry Andric *m_addr_context.line_entry.original_file_sp,
225ac9a064cSDimitry Andric SupportFile::eEqualFileSpecAndChecksumIfSet) &&
22614f1b3e8SDimitry Andric sc.comp_unit == m_addr_context.comp_unit &&
22714f1b3e8SDimitry Andric sc.function == m_addr_context.function) {
2285e95aa85SEd Maste // Okay, find the next occurrence of this file in the line table:
229f034231aSEd Maste LineTable *line_table = m_addr_context.comp_unit->GetLineTable();
23014f1b3e8SDimitry Andric if (line_table) {
231f034231aSEd Maste Address cur_address = frame_sp->GetFrameCodeAddress();
232f034231aSEd Maste uint32_t entry_idx;
233f034231aSEd Maste LineEntry line_entry;
23414f1b3e8SDimitry Andric if (line_table->FindLineEntryByAddress(cur_address, line_entry,
23514f1b3e8SDimitry Andric &entry_idx)) {
236f034231aSEd Maste LineEntry next_line_entry;
237f034231aSEd Maste bool step_past_remaining_inline = false;
23814f1b3e8SDimitry Andric if (entry_idx > 0) {
23914f1b3e8SDimitry Andric // We require the previous line entry and the current line
240f73363f1SDimitry Andric // entry come from the same file. The other requirement is
241f73363f1SDimitry Andric // that the previous line table entry be part of an inlined
242f73363f1SDimitry Andric // block, we don't want to step past cases where people have
243f73363f1SDimitry Andric // inlined some code fragment by using #include <source-
244f73363f1SDimitry Andric // fragment.c> directly.
245f034231aSEd Maste LineEntry prev_line_entry;
24614f1b3e8SDimitry Andric if (line_table->GetLineEntryAtIndex(entry_idx - 1,
24714f1b3e8SDimitry Andric prev_line_entry) &&
248ac9a064cSDimitry Andric prev_line_entry.original_file_sp->Equal(
249ac9a064cSDimitry Andric *line_entry.original_file_sp,
250ac9a064cSDimitry Andric SupportFile::eEqualFileSpecAndChecksumIfSet)) {
251f034231aSEd Maste SymbolContext prev_sc;
25214f1b3e8SDimitry Andric Address prev_address =
25314f1b3e8SDimitry Andric prev_line_entry.range.GetBaseAddress();
254f034231aSEd Maste prev_address.CalculateSymbolContext(&prev_sc);
25514f1b3e8SDimitry Andric if (prev_sc.block) {
25614f1b3e8SDimitry Andric Block *inlined_block =
25714f1b3e8SDimitry Andric prev_sc.block->GetContainingInlinedBlock();
25814f1b3e8SDimitry Andric if (inlined_block) {
259f034231aSEd Maste AddressRange inline_range;
26014f1b3e8SDimitry Andric inlined_block->GetRangeContainingAddress(prev_address,
26114f1b3e8SDimitry Andric inline_range);
26214f1b3e8SDimitry Andric if (!inline_range.ContainsFileAddress(cur_address)) {
263f034231aSEd Maste
264f034231aSEd Maste step_past_remaining_inline = true;
265f034231aSEd Maste }
266f034231aSEd Maste }
267f034231aSEd Maste }
268f034231aSEd Maste }
269f034231aSEd Maste }
270f034231aSEd Maste
27114f1b3e8SDimitry Andric if (step_past_remaining_inline) {
272f034231aSEd Maste uint32_t look_ahead_step = 1;
27314f1b3e8SDimitry Andric while (line_table->GetLineEntryAtIndex(
27414f1b3e8SDimitry Andric entry_idx + look_ahead_step, next_line_entry)) {
27514f1b3e8SDimitry Andric // Make sure we haven't wandered out of the function we
27614f1b3e8SDimitry Andric // started from...
27714f1b3e8SDimitry Andric Address next_line_address =
27814f1b3e8SDimitry Andric next_line_entry.range.GetBaseAddress();
27914f1b3e8SDimitry Andric Function *next_line_function =
28014f1b3e8SDimitry Andric next_line_address.CalculateSymbolContextFunction();
281f034231aSEd Maste if (next_line_function != m_addr_context.function)
282f034231aSEd Maste break;
283f034231aSEd Maste
284ac9a064cSDimitry Andric if (next_line_entry.original_file_sp->Equal(
285ac9a064cSDimitry Andric *m_addr_context.line_entry.original_file_sp,
286ac9a064cSDimitry Andric SupportFile::eEqualFileSpecAndChecksumIfSet)) {
287f034231aSEd Maste const bool abort_other_plans = false;
288e81d9d49SDimitry Andric const RunMode stop_other_threads = RunMode::eAllThreads;
289cfca06d7SDimitry Andric lldb::addr_t cur_pc = thread.GetStackFrameAtIndex(0)
29014f1b3e8SDimitry Andric ->GetRegisterContext()
29114f1b3e8SDimitry Andric ->GetPC();
29214f1b3e8SDimitry Andric AddressRange step_range(
29314f1b3e8SDimitry Andric cur_pc,
29414f1b3e8SDimitry Andric next_line_address.GetLoadAddress(&GetTarget()) -
29514f1b3e8SDimitry Andric cur_pc);
296e81d9d49SDimitry Andric
297cfca06d7SDimitry Andric new_plan_sp = thread.QueueThreadPlanForStepOverRange(
29894994d37SDimitry Andric abort_other_plans, step_range, sc, stop_other_threads,
29994994d37SDimitry Andric m_status);
300f034231aSEd Maste break;
301f034231aSEd Maste }
302f034231aSEd Maste look_ahead_step++;
303f034231aSEd Maste }
304f034231aSEd Maste }
305f034231aSEd Maste }
306f034231aSEd Maste }
307f034231aSEd Maste }
308f034231aSEd Maste }
309f034231aSEd Maste }
310f034231aSEd Maste }
311f034231aSEd Maste }
312f034231aSEd Maste
31314f1b3e8SDimitry Andric // If we get to this point, we're not going to use a previously set "next
31414f1b3e8SDimitry Andric // branch" breakpoint, so delete it:
315f034231aSEd Maste ClearNextBranchBreakpoint();
316f034231aSEd Maste
31714f1b3e8SDimitry Andric // If we haven't figured out something to do yet, then ask the ShouldStopHere
31814f1b3e8SDimitry Andric // callback:
31914f1b3e8SDimitry Andric if (!new_plan_sp) {
32094994d37SDimitry Andric new_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order, m_status);
3210cac4ca3SEd Maste }
3220cac4ca3SEd Maste
323f034231aSEd Maste if (!new_plan_sp)
324f034231aSEd Maste m_no_more_plans = true;
32514f1b3e8SDimitry Andric else {
326205afe67SEd Maste // Any new plan will be an implementation plan, so mark it private:
327205afe67SEd Maste new_plan_sp->SetPrivate(true);
328f034231aSEd Maste m_no_more_plans = false;
329205afe67SEd Maste }
330f034231aSEd Maste
33114f1b3e8SDimitry Andric if (!new_plan_sp) {
33214f1b3e8SDimitry Andric // For efficiencies sake, we know we're done here so we don't have to do
333f73363f1SDimitry Andric // this calculation again in MischiefManaged.
33494994d37SDimitry Andric SetPlanComplete(m_status.Success());
335f034231aSEd Maste return true;
33614f1b3e8SDimitry Andric } else
337f034231aSEd Maste return false;
338f034231aSEd Maste }
339f034231aSEd Maste
DoPlanExplainsStop(Event * event_ptr)34014f1b3e8SDimitry Andric bool ThreadPlanStepOverRange::DoPlanExplainsStop(Event *event_ptr) {
341f73363f1SDimitry Andric // For crashes, breakpoint hits, signals, etc, let the base plan (or some
342f73363f1SDimitry Andric // plan above us) handle the stop. That way the user can see the stop, step
343f73363f1SDimitry Andric // around, and then when they are done, continue and have their step
344f73363f1SDimitry Andric // complete. The exception is if we've hit our "run to next branch"
345f73363f1SDimitry Andric // breakpoint. Note, unlike the step in range plan, we don't mark ourselves
346f73363f1SDimitry Andric // complete if we hit an unexplained breakpoint/crash.
347f034231aSEd Maste
348145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Step);
349f034231aSEd Maste StopInfoSP stop_info_sp = GetPrivateStopInfo();
350f034231aSEd Maste bool return_value;
351f034231aSEd Maste
35214f1b3e8SDimitry Andric if (stop_info_sp) {
353f034231aSEd Maste StopReason reason = stop_info_sp->GetStopReason();
354f034231aSEd Maste
35514f1b3e8SDimitry Andric if (reason == eStopReasonTrace) {
356f034231aSEd Maste return_value = true;
35714f1b3e8SDimitry Andric } else if (reason == eStopReasonBreakpoint) {
358e81d9d49SDimitry Andric return_value = NextRangeBreakpointExplainsStop(stop_info_sp);
35914f1b3e8SDimitry Andric } else {
360f034231aSEd Maste if (log)
361ac9a064cSDimitry Andric log->PutCString("ThreadPlanStepOverRange got asked if it explains the "
36214f1b3e8SDimitry Andric "stop for some reason other than step.");
363f034231aSEd Maste return_value = false;
364f034231aSEd Maste }
36514f1b3e8SDimitry Andric } else
366f034231aSEd Maste return_value = true;
367f034231aSEd Maste
368f034231aSEd Maste return return_value;
369f034231aSEd Maste }
370f034231aSEd Maste
DoWillResume(lldb::StateType resume_state,bool current_plan)37114f1b3e8SDimitry Andric bool ThreadPlanStepOverRange::DoWillResume(lldb::StateType resume_state,
37214f1b3e8SDimitry Andric bool current_plan) {
37314f1b3e8SDimitry Andric if (resume_state != eStateSuspended && m_first_resume) {
374f034231aSEd Maste m_first_resume = false;
37514f1b3e8SDimitry Andric if (resume_state == eStateStepping && current_plan) {
376cfca06d7SDimitry Andric Thread &thread = GetThread();
37714f1b3e8SDimitry Andric // See if we are about to step over an inlined call in the middle of the
378f73363f1SDimitry Andric // inlined stack, if so figure out its extents and reset our range to
379f73363f1SDimitry Andric // step over that.
380cfca06d7SDimitry Andric bool in_inlined_stack = thread.DecrementCurrentInlinedDepth();
38114f1b3e8SDimitry Andric if (in_inlined_stack) {
382145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Step);
383ead24645SDimitry Andric LLDB_LOGF(log,
384ead24645SDimitry Andric "ThreadPlanStepInRange::DoWillResume: adjusting range to "
38514f1b3e8SDimitry Andric "the frame at inlined depth %d.",
386cfca06d7SDimitry Andric thread.GetCurrentInlinedDepth());
387cfca06d7SDimitry Andric StackFrameSP stack_sp = thread.GetStackFrameAtIndex(0);
38814f1b3e8SDimitry Andric if (stack_sp) {
389f034231aSEd Maste Block *frame_block = stack_sp->GetFrameBlock();
390cfca06d7SDimitry Andric lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC();
391f034231aSEd Maste AddressRange my_range;
39214f1b3e8SDimitry Andric if (frame_block->GetRangeContainingLoadAddress(
393cfca06d7SDimitry Andric curr_pc, m_process.GetTarget(), my_range)) {
394f034231aSEd Maste m_address_ranges.clear();
395f034231aSEd Maste m_address_ranges.push_back(my_range);
39614f1b3e8SDimitry Andric if (log) {
397f034231aSEd Maste StreamString s;
39814f1b3e8SDimitry Andric const InlineFunctionInfo *inline_info =
39914f1b3e8SDimitry Andric frame_block->GetInlinedFunctionInfo();
400f034231aSEd Maste const char *name;
401f034231aSEd Maste if (inline_info)
402cfca06d7SDimitry Andric name = inline_info->GetName().AsCString();
403f034231aSEd Maste else
404f034231aSEd Maste name = "<unknown-notinlined>";
405f034231aSEd Maste
40614f1b3e8SDimitry Andric s.Printf(
40714f1b3e8SDimitry Andric "Stepping over inlined function \"%s\" in inlined stack: ",
40814f1b3e8SDimitry Andric name);
409f034231aSEd Maste DumpRanges(&s);
41014f1b3e8SDimitry Andric log->PutString(s.GetString());
411f034231aSEd Maste }
412f034231aSEd Maste }
413f034231aSEd Maste }
414f034231aSEd Maste }
415f034231aSEd Maste }
416f034231aSEd Maste }
417f034231aSEd Maste
418f034231aSEd Maste return true;
419f034231aSEd Maste }
420