xref: /src/contrib/llvm-project/lldb/source/Target/ThreadPlanStepOverRange.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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