1*0b57cec5SDimitry Andric //===-- ThreadPlanStepOverRange.cpp ---------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepOverRange.h"
10*0b57cec5SDimitry Andric #include "lldb/Symbol/Block.h"
11*0b57cec5SDimitry Andric #include "lldb/Symbol/CompileUnit.h"
12*0b57cec5SDimitry Andric #include "lldb/Symbol/Function.h"
13*0b57cec5SDimitry Andric #include "lldb/Symbol/LineTable.h"
14*0b57cec5SDimitry Andric #include "lldb/Target/Process.h"
15*0b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
16*0b57cec5SDimitry Andric #include "lldb/Target/Target.h"
17*0b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
18*0b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepOut.h"
19*0b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepThrough.h"
20*0b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
21*0b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
22*0b57cec5SDimitry Andric 
23*0b57cec5SDimitry Andric using namespace lldb_private;
24*0b57cec5SDimitry Andric using namespace lldb;
25*0b57cec5SDimitry Andric 
26*0b57cec5SDimitry Andric uint32_t ThreadPlanStepOverRange::s_default_flag_values = 0;
27*0b57cec5SDimitry Andric 
28*0b57cec5SDimitry Andric // ThreadPlanStepOverRange: Step through a stack range, either stepping over or
29*0b57cec5SDimitry Andric // into based on the value of \a type.
30*0b57cec5SDimitry Andric 
ThreadPlanStepOverRange(Thread & thread,const AddressRange & range,const SymbolContext & addr_context,lldb::RunMode stop_others,LazyBool step_out_avoids_code_without_debug_info)31*0b57cec5SDimitry Andric ThreadPlanStepOverRange::ThreadPlanStepOverRange(
32*0b57cec5SDimitry Andric     Thread &thread, const AddressRange &range,
33*0b57cec5SDimitry Andric     const SymbolContext &addr_context, lldb::RunMode stop_others,
34*0b57cec5SDimitry Andric     LazyBool step_out_avoids_code_without_debug_info)
35*0b57cec5SDimitry Andric     : ThreadPlanStepRange(ThreadPlan::eKindStepOverRange,
36*0b57cec5SDimitry Andric                           "Step range stepping over", thread, range,
37*0b57cec5SDimitry Andric                           addr_context, stop_others),
38*0b57cec5SDimitry Andric       ThreadPlanShouldStopHere(this), m_first_resume(true) {
39*0b57cec5SDimitry Andric   SetFlagsToDefault();
40*0b57cec5SDimitry Andric   SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
41*0b57cec5SDimitry Andric }
42*0b57cec5SDimitry Andric 
43*0b57cec5SDimitry Andric ThreadPlanStepOverRange::~ThreadPlanStepOverRange() = default;
44*0b57cec5SDimitry Andric 
GetDescription(Stream * s,lldb::DescriptionLevel level)45*0b57cec5SDimitry Andric void ThreadPlanStepOverRange::GetDescription(Stream *s,
46*0b57cec5SDimitry Andric                                              lldb::DescriptionLevel level) {
47*0b57cec5SDimitry Andric   auto PrintFailureIfAny = [&]() {
48*0b57cec5SDimitry Andric     if (m_status.Success())
49*0b57cec5SDimitry Andric       return;
50*0b57cec5SDimitry Andric     s->Printf(" failed (%s)", m_status.AsCString());
51*0b57cec5SDimitry Andric   };
52*0b57cec5SDimitry Andric 
53*0b57cec5SDimitry Andric   if (level == lldb::eDescriptionLevelBrief) {
54*0b57cec5SDimitry Andric     s->Printf("step over");
55*0b57cec5SDimitry Andric     PrintFailureIfAny();
56*0b57cec5SDimitry Andric     return;
57*0b57cec5SDimitry Andric   }
58*0b57cec5SDimitry Andric 
59*0b57cec5SDimitry Andric   s->Printf("Stepping over");
60*0b57cec5SDimitry Andric   bool printed_line_info = false;
61*0b57cec5SDimitry Andric   if (m_addr_context.line_entry.IsValid()) {
62*0b57cec5SDimitry Andric     s->Printf(" line ");
63*0b57cec5SDimitry Andric     m_addr_context.line_entry.DumpStopContext(s, false);
64*0b57cec5SDimitry Andric     printed_line_info = true;
65*0b57cec5SDimitry Andric   }
66*0b57cec5SDimitry Andric 
67*0b57cec5SDimitry Andric   if (!printed_line_info || level == eDescriptionLevelVerbose) {
68*0b57cec5SDimitry Andric     s->Printf(" using ranges: ");
69*0b57cec5SDimitry Andric     DumpRanges(s);
70*0b57cec5SDimitry Andric   }
71*0b57cec5SDimitry Andric 
72*0b57cec5SDimitry Andric   PrintFailureIfAny();
73*0b57cec5SDimitry Andric 
74*0b57cec5SDimitry Andric   s->PutChar('.');
75*0b57cec5SDimitry Andric }
76*0b57cec5SDimitry Andric 
SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info)77*0b57cec5SDimitry Andric void ThreadPlanStepOverRange::SetupAvoidNoDebug(
78*0b57cec5SDimitry Andric     LazyBool step_out_avoids_code_without_debug_info) {
79*0b57cec5SDimitry Andric   bool avoid_nodebug = true;
80*0b57cec5SDimitry Andric   switch (step_out_avoids_code_without_debug_info) {
81*0b57cec5SDimitry Andric   case eLazyBoolYes:
82*0b57cec5SDimitry Andric     avoid_nodebug = true;
83*0b57cec5SDimitry Andric     break;
84*0b57cec5SDimitry Andric   case eLazyBoolNo:
85*0b57cec5SDimitry Andric     avoid_nodebug = false;
86*0b57cec5SDimitry Andric     break;
87*0b57cec5SDimitry Andric   case eLazyBoolCalculate:
88*0b57cec5SDimitry Andric     avoid_nodebug = GetThread().GetStepOutAvoidsNoDebug();
89*0b57cec5SDimitry Andric     break;
90*0b57cec5SDimitry Andric   }
91*0b57cec5SDimitry Andric   if (avoid_nodebug)
92*0b57cec5SDimitry Andric     GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
93*0b57cec5SDimitry Andric   else
94*0b57cec5SDimitry Andric     GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
95*0b57cec5SDimitry Andric   // Step Over plans should always avoid no-debug on step in.  Seems like you
96*0b57cec5SDimitry Andric   // shouldn't have to say this, but a tail call looks more like a step in that
97*0b57cec5SDimitry Andric   // a step out, so we want to catch this case.
98*0b57cec5SDimitry Andric   GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
99*0b57cec5SDimitry Andric }
100*0b57cec5SDimitry Andric 
IsEquivalentContext(const SymbolContext & context)101*0b57cec5SDimitry Andric bool ThreadPlanStepOverRange::IsEquivalentContext(
102*0b57cec5SDimitry Andric     const SymbolContext &context) {
103*0b57cec5SDimitry Andric   // Match as much as is specified in the m_addr_context: This is a fairly
104*0b57cec5SDimitry Andric   // loose sanity check.  Note, sometimes the target doesn't get filled in so I
105*0b57cec5SDimitry Andric   // left out the target check.  And sometimes the module comes in as the .o
106*0b57cec5SDimitry Andric   // file from the inlined range, so I left that out too...
107*0b57cec5SDimitry Andric   if (m_addr_context.comp_unit) {
108*0b57cec5SDimitry Andric     if (m_addr_context.comp_unit != context.comp_unit)
109*0b57cec5SDimitry Andric       return false;
110*0b57cec5SDimitry Andric     if (m_addr_context.function) {
111*0b57cec5SDimitry Andric       if (m_addr_context.function != context.function)
112*0b57cec5SDimitry Andric         return false;
113*0b57cec5SDimitry Andric       // It is okay to return to a different block of a straight function, we
114*0b57cec5SDimitry Andric       // only have to be more careful if returning from one inlined block to
115*0b57cec5SDimitry Andric       // another.
116*0b57cec5SDimitry Andric       if (m_addr_context.block->GetInlinedFunctionInfo() == nullptr &&
117*0b57cec5SDimitry Andric           context.block->GetInlinedFunctionInfo() == nullptr)
118*0b57cec5SDimitry Andric         return true;
119*0b57cec5SDimitry Andric       return m_addr_context.block == context.block;
120*0b57cec5SDimitry Andric     }
121*0b57cec5SDimitry Andric   }
122*0b57cec5SDimitry Andric   // Fall back to symbol if we have no decision from comp_unit/function/block.
123*0b57cec5SDimitry Andric   return m_addr_context.symbol && m_addr_context.symbol == context.symbol;
124*0b57cec5SDimitry Andric }
125*0b57cec5SDimitry Andric 
ShouldStop(Event * event_ptr)126*0b57cec5SDimitry Andric bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
127*0b57cec5SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
128*0b57cec5SDimitry Andric   Thread &thread = GetThread();
129*0b57cec5SDimitry Andric 
130*0b57cec5SDimitry Andric   if (log) {
131*0b57cec5SDimitry Andric     StreamString s;
132*0b57cec5SDimitry Andric     DumpAddress(s.AsRawOstream(), thread.GetRegisterContext()->GetPC(),
133*0b57cec5SDimitry Andric                 GetTarget().GetArchitecture().GetAddressByteSize());
134*0b57cec5SDimitry Andric     LLDB_LOGF(log, "ThreadPlanStepOverRange reached %s.", s.GetData());
135*0b57cec5SDimitry Andric   }
136*0b57cec5SDimitry Andric 
137*0b57cec5SDimitry Andric   // If we're out of the range but in the same frame or in our caller's frame
138*0b57cec5SDimitry Andric   // then we should stop. When stepping out we only stop others if we are
139*0b57cec5SDimitry Andric   // forcing running one thread.
140*0b57cec5SDimitry Andric   bool stop_others = (m_stop_others == lldb::eOnlyThisThread);
141*0b57cec5SDimitry Andric   ThreadPlanSP new_plan_sp;
142*0b57cec5SDimitry Andric   FrameComparison frame_order = CompareCurrentFrameToStartFrame();
143*0b57cec5SDimitry Andric 
144*0b57cec5SDimitry Andric   if (frame_order == eFrameCompareOlder) {
145*0b57cec5SDimitry Andric     // If we're in an older frame then we should stop.
146*0b57cec5SDimitry Andric     //
147*0b57cec5SDimitry Andric     // A caveat to this is if we think the frame is older but we're actually in
148*0b57cec5SDimitry Andric     // a trampoline.
149*0b57cec5SDimitry Andric     // I'm going to make the assumption that you wouldn't RETURN to a
150*0b57cec5SDimitry Andric     // trampoline.  So if we are in a trampoline we think the frame is older
151*0b57cec5SDimitry Andric     // because the trampoline confused the backtracer. As below, we step
152*0b57cec5SDimitry Andric     // through first, and then try to figure out how to get back out again.
153*0b57cec5SDimitry Andric 
154*0b57cec5SDimitry Andric     new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false,
155*0b57cec5SDimitry Andric                                                        stop_others, m_status);
156*0b57cec5SDimitry Andric 
157*0b57cec5SDimitry Andric     if (new_plan_sp && log)
158*0b57cec5SDimitry Andric       LLDB_LOGF(log,
159*0b57cec5SDimitry Andric                 "Thought I stepped out, but in fact arrived at a trampoline.");
160*0b57cec5SDimitry Andric   } else if (frame_order == eFrameCompareYounger) {
161*0b57cec5SDimitry Andric     // Make sure we really are in a new frame.  Do that by unwinding and seeing
162*0b57cec5SDimitry Andric     // if the start function really is our start function...
163*0b57cec5SDimitry Andric     for (uint32_t i = 1;; ++i) {
164*0b57cec5SDimitry Andric       StackFrameSP older_frame_sp = thread.GetStackFrameAtIndex(i);
165*0b57cec5SDimitry Andric       if (!older_frame_sp) {
166*0b57cec5SDimitry Andric         // We can't unwind the next frame we should just get out of here &
167*0b57cec5SDimitry Andric         // stop...
168*0b57cec5SDimitry Andric         break;
169*0b57cec5SDimitry Andric       }
170*0b57cec5SDimitry Andric 
171*0b57cec5SDimitry Andric       const SymbolContext &older_context =
172*0b57cec5SDimitry Andric           older_frame_sp->GetSymbolContext(eSymbolContextEverything);
173*0b57cec5SDimitry Andric       if (IsEquivalentContext(older_context)) {
174*0b57cec5SDimitry Andric         // If we have the  next-branch-breakpoint in the range, we can just
175*0b57cec5SDimitry Andric         // rely on that breakpoint to trigger once we return to the range.
176*0b57cec5SDimitry Andric         if (m_next_branch_bp_sp)
177*0b57cec5SDimitry Andric           return false;
178*0b57cec5SDimitry Andric         new_plan_sp = thread.QueueThreadPlanForStepOutNoShouldStop(
179*0b57cec5SDimitry Andric             false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
180*0b57cec5SDimitry Andric             m_status, true);
181*0b57cec5SDimitry Andric         break;
182*0b57cec5SDimitry Andric       } else {
183*0b57cec5SDimitry Andric         new_plan_sp = thread.QueueThreadPlanForStepThrough(
184*0b57cec5SDimitry Andric             m_stack_id, false, stop_others, m_status);
185*0b57cec5SDimitry Andric         // If we found a way through, then we should stop recursing.
186*0b57cec5SDimitry Andric         if (new_plan_sp)
187*0b57cec5SDimitry Andric           break;
188*0b57cec5SDimitry Andric       }
189*0b57cec5SDimitry Andric     }
190*0b57cec5SDimitry Andric   } else {
191*0b57cec5SDimitry Andric     // If we're still in the range, keep going.
192*0b57cec5SDimitry Andric     if (InRange()) {
193*0b57cec5SDimitry Andric       SetNextBranchBreakpoint();
194*0b57cec5SDimitry Andric       return false;
195*0b57cec5SDimitry Andric     }
196*0b57cec5SDimitry Andric 
197*0b57cec5SDimitry Andric     if (!InSymbol()) {
198*0b57cec5SDimitry Andric       // This one is a little tricky.  Sometimes we may be in a stub or
199*0b57cec5SDimitry Andric       // something similar, in which case we need to get out of there.  But if
200*0b57cec5SDimitry Andric       // we are in a stub then it's likely going to be hard to get out from
201*0b57cec5SDimitry Andric       // here.  It is probably easiest to step into the stub, and then it will
202*0b57cec5SDimitry Andric       // be straight-forward to step out.
203*0b57cec5SDimitry Andric       new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false,
204*0b57cec5SDimitry Andric                                                          stop_others, m_status);
205*0b57cec5SDimitry Andric     } else {
206*0b57cec5SDimitry Andric       // The current clang (at least through 424) doesn't always get the
207*0b57cec5SDimitry Andric       // address range for the DW_TAG_inlined_subroutines right, so that when
208*0b57cec5SDimitry Andric       // you leave the inlined range the line table says you are still in the
209*0b57cec5SDimitry Andric       // source file of the inlining function.  This is bad, because now you
210*0b57cec5SDimitry Andric       // are missing the stack frame for the function containing the inlining,
211*0b57cec5SDimitry Andric       // and if you sensibly do "finish" to get out of this function you will
212*0b57cec5SDimitry Andric       // instead exit the containing function. To work around this, we check
213*0b57cec5SDimitry Andric       // whether we are still in the source file we started in, and if not
214*0b57cec5SDimitry Andric       // assume it is an error, and push a plan to get us out of this line and
215*0b57cec5SDimitry Andric       // back to the containing file.
216*0b57cec5SDimitry Andric 
217*0b57cec5SDimitry Andric       if (m_addr_context.line_entry.IsValid()) {
218*0b57cec5SDimitry Andric         SymbolContext sc;
219*0b57cec5SDimitry Andric         StackFrameSP frame_sp = thread.GetStackFrameAtIndex(0);
220*0b57cec5SDimitry Andric         sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
221*0b57cec5SDimitry Andric         if (sc.line_entry.IsValid()) {
222*0b57cec5SDimitry Andric           if (sc.line_entry.original_file !=
223*0b57cec5SDimitry Andric                   m_addr_context.line_entry.original_file &&
224*0b57cec5SDimitry Andric               sc.comp_unit == m_addr_context.comp_unit &&
225*0b57cec5SDimitry Andric               sc.function == m_addr_context.function) {
226*0b57cec5SDimitry Andric             // Okay, find the next occurrence of this file in the line table:
227*0b57cec5SDimitry Andric             LineTable *line_table = m_addr_context.comp_unit->GetLineTable();
228*0b57cec5SDimitry Andric             if (line_table) {
229*0b57cec5SDimitry Andric               Address cur_address = frame_sp->GetFrameCodeAddress();
230*0b57cec5SDimitry Andric               uint32_t entry_idx;
231*0b57cec5SDimitry Andric               LineEntry line_entry;
232*0b57cec5SDimitry Andric               if (line_table->FindLineEntryByAddress(cur_address, line_entry,
233*0b57cec5SDimitry Andric                                                      &entry_idx)) {
234*0b57cec5SDimitry Andric                 LineEntry next_line_entry;
235*0b57cec5SDimitry Andric                 bool step_past_remaining_inline = false;
236*0b57cec5SDimitry Andric                 if (entry_idx > 0) {
237*0b57cec5SDimitry Andric                   // We require the previous line entry and the current line
238*0b57cec5SDimitry Andric                   // entry come from the same file. The other requirement is
239*0b57cec5SDimitry Andric                   // that the previous line table entry be part of an inlined
240*0b57cec5SDimitry Andric                   // block, we don't want to step past cases where people have
241*0b57cec5SDimitry Andric                   // inlined some code fragment by using #include <source-
242*0b57cec5SDimitry Andric                   // fragment.c> directly.
243*0b57cec5SDimitry Andric                   LineEntry prev_line_entry;
244*0b57cec5SDimitry Andric                   if (line_table->GetLineEntryAtIndex(entry_idx - 1,
245*0b57cec5SDimitry Andric                                                       prev_line_entry) &&
246*0b57cec5SDimitry Andric                       prev_line_entry.original_file ==
247*0b57cec5SDimitry Andric                           line_entry.original_file) {
248*0b57cec5SDimitry Andric                     SymbolContext prev_sc;
249*0b57cec5SDimitry Andric                     Address prev_address =
250*0b57cec5SDimitry Andric                         prev_line_entry.range.GetBaseAddress();
251*0b57cec5SDimitry Andric                     prev_address.CalculateSymbolContext(&prev_sc);
252*0b57cec5SDimitry Andric                     if (prev_sc.block) {
253*0b57cec5SDimitry Andric                       Block *inlined_block =
254*0b57cec5SDimitry Andric                           prev_sc.block->GetContainingInlinedBlock();
255*0b57cec5SDimitry Andric                       if (inlined_block) {
256*0b57cec5SDimitry Andric                         AddressRange inline_range;
257*0b57cec5SDimitry Andric                         inlined_block->GetRangeContainingAddress(prev_address,
258*0b57cec5SDimitry Andric                                                                  inline_range);
259*0b57cec5SDimitry Andric                         if (!inline_range.ContainsFileAddress(cur_address)) {
260*0b57cec5SDimitry Andric 
261*0b57cec5SDimitry Andric                           step_past_remaining_inline = true;
262*0b57cec5SDimitry Andric                         }
263*0b57cec5SDimitry Andric                       }
264*0b57cec5SDimitry Andric                     }
265*0b57cec5SDimitry Andric                   }
266*0b57cec5SDimitry Andric                 }
267*0b57cec5SDimitry Andric 
268*0b57cec5SDimitry Andric                 if (step_past_remaining_inline) {
269*0b57cec5SDimitry Andric                   uint32_t look_ahead_step = 1;
270*0b57cec5SDimitry Andric                   while (line_table->GetLineEntryAtIndex(
271*0b57cec5SDimitry Andric                       entry_idx + look_ahead_step, next_line_entry)) {
272*0b57cec5SDimitry Andric                     // Make sure we haven't wandered out of the function we
273*0b57cec5SDimitry Andric                     // started from...
274*0b57cec5SDimitry Andric                     Address next_line_address =
275*0b57cec5SDimitry Andric                         next_line_entry.range.GetBaseAddress();
276*0b57cec5SDimitry Andric                     Function *next_line_function =
277*0b57cec5SDimitry Andric                         next_line_address.CalculateSymbolContextFunction();
278*0b57cec5SDimitry Andric                     if (next_line_function != m_addr_context.function)
279*0b57cec5SDimitry Andric                       break;
280*0b57cec5SDimitry Andric 
281*0b57cec5SDimitry Andric                     if (next_line_entry.original_file ==
282*0b57cec5SDimitry Andric                         m_addr_context.line_entry.original_file) {
283*0b57cec5SDimitry Andric                       const bool abort_other_plans = false;
284*0b57cec5SDimitry Andric                       const RunMode stop_other_threads = RunMode::eAllThreads;
285*0b57cec5SDimitry Andric                       lldb::addr_t cur_pc = thread.GetStackFrameAtIndex(0)
286*0b57cec5SDimitry Andric                                                 ->GetRegisterContext()
287*0b57cec5SDimitry Andric                                                 ->GetPC();
288*0b57cec5SDimitry Andric                       AddressRange step_range(
289*0b57cec5SDimitry Andric                           cur_pc,
290*0b57cec5SDimitry Andric                           next_line_address.GetLoadAddress(&GetTarget()) -
291*0b57cec5SDimitry Andric                               cur_pc);
292*0b57cec5SDimitry Andric 
293*0b57cec5SDimitry Andric                       new_plan_sp = thread.QueueThreadPlanForStepOverRange(
294*0b57cec5SDimitry Andric                           abort_other_plans, step_range, sc, stop_other_threads,
295*0b57cec5SDimitry Andric                           m_status);
296*0b57cec5SDimitry Andric                       break;
297*0b57cec5SDimitry Andric                     }
298*0b57cec5SDimitry Andric                     look_ahead_step++;
299*0b57cec5SDimitry Andric                   }
300*0b57cec5SDimitry Andric                 }
301*0b57cec5SDimitry Andric               }
302*0b57cec5SDimitry Andric             }
303*0b57cec5SDimitry Andric           }
304*0b57cec5SDimitry Andric         }
305*0b57cec5SDimitry Andric       }
306*0b57cec5SDimitry Andric     }
307*0b57cec5SDimitry Andric   }
308*0b57cec5SDimitry Andric 
309*0b57cec5SDimitry Andric   // If we get to this point, we're not going to use a previously set "next
310*0b57cec5SDimitry Andric   // branch" breakpoint, so delete it:
311*0b57cec5SDimitry Andric   ClearNextBranchBreakpoint();
312*0b57cec5SDimitry Andric 
313*0b57cec5SDimitry Andric   // If we haven't figured out something to do yet, then ask the ShouldStopHere
314*0b57cec5SDimitry Andric   // callback:
315*0b57cec5SDimitry Andric   if (!new_plan_sp) {
316*0b57cec5SDimitry Andric     new_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order, m_status);
317*0b57cec5SDimitry Andric   }
318*0b57cec5SDimitry Andric 
319*0b57cec5SDimitry Andric   if (!new_plan_sp)
320*0b57cec5SDimitry Andric     m_no_more_plans = true;
321*0b57cec5SDimitry Andric   else {
322*0b57cec5SDimitry Andric     // Any new plan will be an implementation plan, so mark it private:
323*0b57cec5SDimitry Andric     new_plan_sp->SetPrivate(true);
324*0b57cec5SDimitry Andric     m_no_more_plans = false;
325*0b57cec5SDimitry Andric   }
326*0b57cec5SDimitry Andric 
327*0b57cec5SDimitry Andric   if (!new_plan_sp) {
328*0b57cec5SDimitry Andric     // For efficiencies sake, we know we're done here so we don't have to do
329*0b57cec5SDimitry Andric     // this calculation again in MischiefManaged.
330*0b57cec5SDimitry Andric     SetPlanComplete(m_status.Success());
331*0b57cec5SDimitry Andric     return true;
332*0b57cec5SDimitry Andric   } else
333*0b57cec5SDimitry Andric     return false;
334*0b57cec5SDimitry Andric }
335*0b57cec5SDimitry Andric 
DoPlanExplainsStop(Event * event_ptr)336*0b57cec5SDimitry Andric bool ThreadPlanStepOverRange::DoPlanExplainsStop(Event *event_ptr) {
337*0b57cec5SDimitry Andric   // For crashes, breakpoint hits, signals, etc, let the base plan (or some
338*0b57cec5SDimitry Andric   // plan above us) handle the stop.  That way the user can see the stop, step
339*0b57cec5SDimitry Andric   // around, and then when they are done, continue and have their step
340*0b57cec5SDimitry Andric   // complete.  The exception is if we've hit our "run to next branch"
341*0b57cec5SDimitry Andric   // breakpoint. Note, unlike the step in range plan, we don't mark ourselves
342*0b57cec5SDimitry Andric   // complete if we hit an unexplained breakpoint/crash.
343*0b57cec5SDimitry Andric 
344*0b57cec5SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
345*0b57cec5SDimitry Andric   StopInfoSP stop_info_sp = GetPrivateStopInfo();
346*0b57cec5SDimitry Andric   bool return_value;
347*0b57cec5SDimitry Andric 
348*0b57cec5SDimitry Andric   if (stop_info_sp) {
349*0b57cec5SDimitry Andric     StopReason reason = stop_info_sp->GetStopReason();
350*0b57cec5SDimitry Andric 
351*0b57cec5SDimitry Andric     if (reason == eStopReasonTrace) {
352*0b57cec5SDimitry Andric       return_value = true;
353*0b57cec5SDimitry Andric     } else if (reason == eStopReasonBreakpoint) {
354*0b57cec5SDimitry Andric       return_value = NextRangeBreakpointExplainsStop(stop_info_sp);
355*0b57cec5SDimitry Andric     } else {
356*0b57cec5SDimitry Andric       if (log)
357*0b57cec5SDimitry Andric         log->PutCString("ThreadPlanStepInRange got asked if it explains the "
358*0b57cec5SDimitry Andric                         "stop for some reason other than step.");
359*0b57cec5SDimitry Andric       return_value = false;
360*0b57cec5SDimitry Andric     }
361*0b57cec5SDimitry Andric   } else
362*0b57cec5SDimitry Andric     return_value = true;
363*0b57cec5SDimitry Andric 
364*0b57cec5SDimitry Andric   return return_value;
365*0b57cec5SDimitry Andric }
366*0b57cec5SDimitry Andric 
DoWillResume(lldb::StateType resume_state,bool current_plan)367*0b57cec5SDimitry Andric bool ThreadPlanStepOverRange::DoWillResume(lldb::StateType resume_state,
368*0b57cec5SDimitry Andric                                            bool current_plan) {
369*0b57cec5SDimitry Andric   if (resume_state != eStateSuspended && m_first_resume) {
370*0b57cec5SDimitry Andric     m_first_resume = false;
371*0b57cec5SDimitry Andric     if (resume_state == eStateStepping && current_plan) {
372*0b57cec5SDimitry Andric       Thread &thread = GetThread();
373*0b57cec5SDimitry Andric       // See if we are about to step over an inlined call in the middle of the
374*0b57cec5SDimitry Andric       // inlined stack, if so figure out its extents and reset our range to
375*0b57cec5SDimitry Andric       // step over that.
376*0b57cec5SDimitry Andric       bool in_inlined_stack = thread.DecrementCurrentInlinedDepth();
377*0b57cec5SDimitry Andric       if (in_inlined_stack) {
378*0b57cec5SDimitry Andric         Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
379*0b57cec5SDimitry Andric         LLDB_LOGF(log,
380*0b57cec5SDimitry Andric                   "ThreadPlanStepInRange::DoWillResume: adjusting range to "
381*0b57cec5SDimitry Andric                   "the frame at inlined depth %d.",
382*0b57cec5SDimitry Andric                   thread.GetCurrentInlinedDepth());
383*0b57cec5SDimitry Andric         StackFrameSP stack_sp = thread.GetStackFrameAtIndex(0);
384*0b57cec5SDimitry Andric         if (stack_sp) {
385*0b57cec5SDimitry Andric           Block *frame_block = stack_sp->GetFrameBlock();
386*0b57cec5SDimitry Andric           lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC();
387*0b57cec5SDimitry Andric           AddressRange my_range;
388*0b57cec5SDimitry Andric           if (frame_block->GetRangeContainingLoadAddress(
389*0b57cec5SDimitry Andric                   curr_pc, m_process.GetTarget(), my_range)) {
390*0b57cec5SDimitry Andric             m_address_ranges.clear();
391*0b57cec5SDimitry Andric             m_address_ranges.push_back(my_range);
392*0b57cec5SDimitry Andric             if (log) {
393*0b57cec5SDimitry Andric               StreamString s;
394*0b57cec5SDimitry Andric               const InlineFunctionInfo *inline_info =
395*0b57cec5SDimitry Andric                   frame_block->GetInlinedFunctionInfo();
396*0b57cec5SDimitry Andric               const char *name;
397*0b57cec5SDimitry Andric               if (inline_info)
398*0b57cec5SDimitry Andric                 name = inline_info->GetName().AsCString();
399*0b57cec5SDimitry Andric               else
400*0b57cec5SDimitry Andric                 name = "<unknown-notinlined>";
401*0b57cec5SDimitry Andric 
402*0b57cec5SDimitry Andric               s.Printf(
403*0b57cec5SDimitry Andric                   "Stepping over inlined function \"%s\" in inlined stack: ",
404*0b57cec5SDimitry Andric                   name);
405*0b57cec5SDimitry Andric               DumpRanges(&s);
406*0b57cec5SDimitry Andric               log->PutString(s.GetString());
407*0b57cec5SDimitry Andric             }
408*0b57cec5SDimitry Andric           }
409*0b57cec5SDimitry Andric         }
410*0b57cec5SDimitry Andric       }
411*0b57cec5SDimitry Andric     }
412*0b57cec5SDimitry Andric   }
413*0b57cec5SDimitry Andric 
414*0b57cec5SDimitry Andric   return true;
415 }
416