15ffd83dbSDimitry Andric //===-- ThreadPlanStepOverRange.cpp ---------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepOverRange.h"
100b57cec5SDimitry Andric #include "lldb/Symbol/Block.h"
110b57cec5SDimitry Andric #include "lldb/Symbol/CompileUnit.h"
120b57cec5SDimitry Andric #include "lldb/Symbol/Function.h"
130b57cec5SDimitry Andric #include "lldb/Symbol/LineTable.h"
140b57cec5SDimitry Andric #include "lldb/Target/Process.h"
150b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
160b57cec5SDimitry Andric #include "lldb/Target/Target.h"
170b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
180b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepOut.h"
190b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepThrough.h"
2081ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
210b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
220b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric using namespace lldb_private;
250b57cec5SDimitry Andric using namespace lldb;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric uint32_t ThreadPlanStepOverRange::s_default_flag_values = 0;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric // ThreadPlanStepOverRange: Step through a stack range, either stepping over or
300b57cec5SDimitry Andric // into based on the value of \a type.
310b57cec5SDimitry Andric 
ThreadPlanStepOverRange(Thread & thread,const AddressRange & range,const SymbolContext & addr_context,lldb::RunMode stop_others,LazyBool step_out_avoids_code_without_debug_info)320b57cec5SDimitry Andric ThreadPlanStepOverRange::ThreadPlanStepOverRange(
330b57cec5SDimitry Andric     Thread &thread, const AddressRange &range,
340b57cec5SDimitry Andric     const SymbolContext &addr_context, lldb::RunMode stop_others,
350b57cec5SDimitry Andric     LazyBool step_out_avoids_code_without_debug_info)
360b57cec5SDimitry Andric     : ThreadPlanStepRange(ThreadPlan::eKindStepOverRange,
370b57cec5SDimitry Andric                           "Step range stepping over", thread, range,
380b57cec5SDimitry Andric                           addr_context, stop_others),
390b57cec5SDimitry Andric       ThreadPlanShouldStopHere(this), m_first_resume(true) {
400b57cec5SDimitry Andric   SetFlagsToDefault();
410b57cec5SDimitry Andric   SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric ThreadPlanStepOverRange::~ThreadPlanStepOverRange() = default;
450b57cec5SDimitry Andric 
GetDescription(Stream * s,lldb::DescriptionLevel level)460b57cec5SDimitry Andric void ThreadPlanStepOverRange::GetDescription(Stream *s,
470b57cec5SDimitry Andric                                              lldb::DescriptionLevel level) {
480b57cec5SDimitry Andric   auto PrintFailureIfAny = [&]() {
490b57cec5SDimitry Andric     if (m_status.Success())
500b57cec5SDimitry Andric       return;
510b57cec5SDimitry Andric     s->Printf(" failed (%s)", m_status.AsCString());
520b57cec5SDimitry Andric   };
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   if (level == lldb::eDescriptionLevelBrief) {
550b57cec5SDimitry Andric     s->Printf("step over");
560b57cec5SDimitry Andric     PrintFailureIfAny();
570b57cec5SDimitry Andric     return;
580b57cec5SDimitry Andric   }
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   s->Printf("Stepping over");
610b57cec5SDimitry Andric   bool printed_line_info = false;
620b57cec5SDimitry Andric   if (m_addr_context.line_entry.IsValid()) {
630b57cec5SDimitry Andric     s->Printf(" line ");
640b57cec5SDimitry Andric     m_addr_context.line_entry.DumpStopContext(s, false);
650b57cec5SDimitry Andric     printed_line_info = true;
660b57cec5SDimitry Andric   }
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   if (!printed_line_info || level == eDescriptionLevelVerbose) {
690b57cec5SDimitry Andric     s->Printf(" using ranges: ");
700b57cec5SDimitry Andric     DumpRanges(s);
710b57cec5SDimitry Andric   }
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   PrintFailureIfAny();
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   s->PutChar('.');
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric 
SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info)780b57cec5SDimitry Andric void ThreadPlanStepOverRange::SetupAvoidNoDebug(
790b57cec5SDimitry Andric     LazyBool step_out_avoids_code_without_debug_info) {
800b57cec5SDimitry Andric   bool avoid_nodebug = true;
810b57cec5SDimitry Andric   switch (step_out_avoids_code_without_debug_info) {
820b57cec5SDimitry Andric   case eLazyBoolYes:
830b57cec5SDimitry Andric     avoid_nodebug = true;
840b57cec5SDimitry Andric     break;
850b57cec5SDimitry Andric   case eLazyBoolNo:
860b57cec5SDimitry Andric     avoid_nodebug = false;
870b57cec5SDimitry Andric     break;
880b57cec5SDimitry Andric   case eLazyBoolCalculate:
895ffd83dbSDimitry Andric     avoid_nodebug = GetThread().GetStepOutAvoidsNoDebug();
900b57cec5SDimitry Andric     break;
910b57cec5SDimitry Andric   }
920b57cec5SDimitry Andric   if (avoid_nodebug)
930b57cec5SDimitry Andric     GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
940b57cec5SDimitry Andric   else
950b57cec5SDimitry Andric     GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
960b57cec5SDimitry Andric   // Step Over plans should always avoid no-debug on step in.  Seems like you
970b57cec5SDimitry Andric   // shouldn't have to say this, but a tail call looks more like a step in that
980b57cec5SDimitry Andric   // a step out, so we want to catch this case.
990b57cec5SDimitry Andric   GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric 
IsEquivalentContext(const SymbolContext & context)1020b57cec5SDimitry Andric bool ThreadPlanStepOverRange::IsEquivalentContext(
1030b57cec5SDimitry Andric     const SymbolContext &context) {
1040b57cec5SDimitry Andric   // Match as much as is specified in the m_addr_context: This is a fairly
1050b57cec5SDimitry Andric   // loose sanity check.  Note, sometimes the target doesn't get filled in so I
1060b57cec5SDimitry Andric   // left out the target check.  And sometimes the module comes in as the .o
1070b57cec5SDimitry Andric   // file from the inlined range, so I left that out too...
1080b57cec5SDimitry Andric   if (m_addr_context.comp_unit) {
1090b57cec5SDimitry Andric     if (m_addr_context.comp_unit != context.comp_unit)
1100b57cec5SDimitry Andric       return false;
1110b57cec5SDimitry Andric     if (m_addr_context.function) {
1120b57cec5SDimitry Andric       if (m_addr_context.function != context.function)
1130b57cec5SDimitry Andric         return false;
1140b57cec5SDimitry Andric       // It is okay to return to a different block of a straight function, we
1150b57cec5SDimitry Andric       // only have to be more careful if returning from one inlined block to
1160b57cec5SDimitry Andric       // another.
1170b57cec5SDimitry Andric       if (m_addr_context.block->GetInlinedFunctionInfo() == nullptr &&
1180b57cec5SDimitry Andric           context.block->GetInlinedFunctionInfo() == nullptr)
1190b57cec5SDimitry Andric         return true;
1200b57cec5SDimitry Andric       return m_addr_context.block == context.block;
1210b57cec5SDimitry Andric     }
1220b57cec5SDimitry Andric   }
1230b57cec5SDimitry Andric   // Fall back to symbol if we have no decision from comp_unit/function/block.
1240b57cec5SDimitry Andric   return m_addr_context.symbol && m_addr_context.symbol == context.symbol;
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric 
ShouldStop(Event * event_ptr)1270b57cec5SDimitry Andric bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
12881ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
1295ffd83dbSDimitry Andric   Thread &thread = GetThread();
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   if (log) {
1320b57cec5SDimitry Andric     StreamString s;
1335ffd83dbSDimitry Andric     DumpAddress(s.AsRawOstream(), thread.GetRegisterContext()->GetPC(),
1345ffd83dbSDimitry Andric                 GetTarget().GetArchitecture().GetAddressByteSize());
1359dba64beSDimitry Andric     LLDB_LOGF(log, "ThreadPlanStepOverRange reached %s.", s.GetData());
1360b57cec5SDimitry Andric   }
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   // If we're out of the range but in the same frame or in our caller's frame
1390b57cec5SDimitry Andric   // then we should stop. When stepping out we only stop others if we are
1400b57cec5SDimitry Andric   // forcing running one thread.
1410b57cec5SDimitry Andric   bool stop_others = (m_stop_others == lldb::eOnlyThisThread);
1420b57cec5SDimitry Andric   ThreadPlanSP new_plan_sp;
1430b57cec5SDimitry Andric   FrameComparison frame_order = CompareCurrentFrameToStartFrame();
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric   if (frame_order == eFrameCompareOlder) {
1460b57cec5SDimitry Andric     // If we're in an older frame then we should stop.
1470b57cec5SDimitry Andric     //
1480b57cec5SDimitry Andric     // A caveat to this is if we think the frame is older but we're actually in
1490b57cec5SDimitry Andric     // a trampoline.
1500b57cec5SDimitry Andric     // I'm going to make the assumption that you wouldn't RETURN to a
1510b57cec5SDimitry Andric     // trampoline.  So if we are in a trampoline we think the frame is older
1520b57cec5SDimitry Andric     // because the trampoline confused the backtracer. As below, we step
1530b57cec5SDimitry Andric     // through first, and then try to figure out how to get back out again.
1540b57cec5SDimitry Andric 
1555ffd83dbSDimitry Andric     new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false,
1560b57cec5SDimitry Andric                                                        stop_others, m_status);
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric     if (new_plan_sp && log)
1599dba64beSDimitry Andric       LLDB_LOGF(log,
1600b57cec5SDimitry Andric                 "Thought I stepped out, but in fact arrived at a trampoline.");
1610b57cec5SDimitry Andric   } else if (frame_order == eFrameCompareYounger) {
1620b57cec5SDimitry Andric     // Make sure we really are in a new frame.  Do that by unwinding and seeing
1630b57cec5SDimitry Andric     // if the start function really is our start function...
1640b57cec5SDimitry Andric     for (uint32_t i = 1;; ++i) {
1655ffd83dbSDimitry Andric       StackFrameSP older_frame_sp = thread.GetStackFrameAtIndex(i);
1660b57cec5SDimitry Andric       if (!older_frame_sp) {
1670b57cec5SDimitry Andric         // We can't unwind the next frame we should just get out of here &
1680b57cec5SDimitry Andric         // stop...
1690b57cec5SDimitry Andric         break;
1700b57cec5SDimitry Andric       }
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric       const SymbolContext &older_context =
1730b57cec5SDimitry Andric           older_frame_sp->GetSymbolContext(eSymbolContextEverything);
1740b57cec5SDimitry Andric       if (IsEquivalentContext(older_context)) {
1755ffd83dbSDimitry Andric         // If we have the  next-branch-breakpoint in the range, we can just
1765ffd83dbSDimitry Andric         // rely on that breakpoint to trigger once we return to the range.
1775ffd83dbSDimitry Andric         if (m_next_branch_bp_sp)
1785ffd83dbSDimitry Andric           return false;
1795ffd83dbSDimitry Andric         new_plan_sp = thread.QueueThreadPlanForStepOutNoShouldStop(
1800b57cec5SDimitry Andric             false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
1810b57cec5SDimitry Andric             m_status, true);
1820b57cec5SDimitry Andric         break;
1830b57cec5SDimitry Andric       } else {
1845ffd83dbSDimitry Andric         new_plan_sp = thread.QueueThreadPlanForStepThrough(
1850b57cec5SDimitry Andric             m_stack_id, false, stop_others, m_status);
1860b57cec5SDimitry Andric         // If we found a way through, then we should stop recursing.
1870b57cec5SDimitry Andric         if (new_plan_sp)
1880b57cec5SDimitry Andric           break;
1890b57cec5SDimitry Andric       }
1900b57cec5SDimitry Andric     }
1910b57cec5SDimitry Andric   } else {
1920b57cec5SDimitry Andric     // If we're still in the range, keep going.
1930b57cec5SDimitry Andric     if (InRange()) {
1940b57cec5SDimitry Andric       SetNextBranchBreakpoint();
1950b57cec5SDimitry Andric       return false;
1960b57cec5SDimitry Andric     }
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric     if (!InSymbol()) {
1990b57cec5SDimitry Andric       // This one is a little tricky.  Sometimes we may be in a stub or
2000b57cec5SDimitry Andric       // something similar, in which case we need to get out of there.  But if
2010b57cec5SDimitry Andric       // we are in a stub then it's likely going to be hard to get out from
2020b57cec5SDimitry Andric       // here.  It is probably easiest to step into the stub, and then it will
2030b57cec5SDimitry Andric       // be straight-forward to step out.
2045ffd83dbSDimitry Andric       new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false,
2055ffd83dbSDimitry Andric                                                          stop_others, m_status);
2060b57cec5SDimitry Andric     } else {
2070b57cec5SDimitry Andric       // The current clang (at least through 424) doesn't always get the
2080b57cec5SDimitry Andric       // address range for the DW_TAG_inlined_subroutines right, so that when
2090b57cec5SDimitry Andric       // you leave the inlined range the line table says you are still in the
2100b57cec5SDimitry Andric       // source file of the inlining function.  This is bad, because now you
2110b57cec5SDimitry Andric       // are missing the stack frame for the function containing the inlining,
2120b57cec5SDimitry Andric       // and if you sensibly do "finish" to get out of this function you will
2130b57cec5SDimitry Andric       // instead exit the containing function. To work around this, we check
2140b57cec5SDimitry Andric       // whether we are still in the source file we started in, and if not
2150b57cec5SDimitry Andric       // assume it is an error, and push a plan to get us out of this line and
2160b57cec5SDimitry Andric       // back to the containing file.
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric       if (m_addr_context.line_entry.IsValid()) {
2190b57cec5SDimitry Andric         SymbolContext sc;
2205ffd83dbSDimitry Andric         StackFrameSP frame_sp = thread.GetStackFrameAtIndex(0);
2210b57cec5SDimitry Andric         sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
2220b57cec5SDimitry Andric         if (sc.line_entry.IsValid()) {
223*a58f00eaSDimitry Andric           if (*sc.line_entry.original_file_sp !=
224*a58f00eaSDimitry Andric                   *m_addr_context.line_entry.original_file_sp &&
2250b57cec5SDimitry Andric               sc.comp_unit == m_addr_context.comp_unit &&
2260b57cec5SDimitry Andric               sc.function == m_addr_context.function) {
2270b57cec5SDimitry Andric             // Okay, find the next occurrence of this file in the line table:
2280b57cec5SDimitry Andric             LineTable *line_table = m_addr_context.comp_unit->GetLineTable();
2290b57cec5SDimitry Andric             if (line_table) {
2300b57cec5SDimitry Andric               Address cur_address = frame_sp->GetFrameCodeAddress();
2310b57cec5SDimitry Andric               uint32_t entry_idx;
2320b57cec5SDimitry Andric               LineEntry line_entry;
2330b57cec5SDimitry Andric               if (line_table->FindLineEntryByAddress(cur_address, line_entry,
2340b57cec5SDimitry Andric                                                      &entry_idx)) {
2350b57cec5SDimitry Andric                 LineEntry next_line_entry;
2360b57cec5SDimitry Andric                 bool step_past_remaining_inline = false;
2370b57cec5SDimitry Andric                 if (entry_idx > 0) {
2380b57cec5SDimitry Andric                   // We require the previous line entry and the current line
2390b57cec5SDimitry Andric                   // entry come from the same file. The other requirement is
2400b57cec5SDimitry Andric                   // that the previous line table entry be part of an inlined
2410b57cec5SDimitry Andric                   // block, we don't want to step past cases where people have
2420b57cec5SDimitry Andric                   // inlined some code fragment by using #include <source-
2430b57cec5SDimitry Andric                   // fragment.c> directly.
2440b57cec5SDimitry Andric                   LineEntry prev_line_entry;
2450b57cec5SDimitry Andric                   if (line_table->GetLineEntryAtIndex(entry_idx - 1,
2460b57cec5SDimitry Andric                                                       prev_line_entry) &&
247*a58f00eaSDimitry Andric                       *prev_line_entry.original_file_sp ==
248*a58f00eaSDimitry Andric                           *line_entry.original_file_sp) {
2490b57cec5SDimitry Andric                     SymbolContext prev_sc;
2500b57cec5SDimitry Andric                     Address prev_address =
2510b57cec5SDimitry Andric                         prev_line_entry.range.GetBaseAddress();
2520b57cec5SDimitry Andric                     prev_address.CalculateSymbolContext(&prev_sc);
2530b57cec5SDimitry Andric                     if (prev_sc.block) {
2540b57cec5SDimitry Andric                       Block *inlined_block =
2550b57cec5SDimitry Andric                           prev_sc.block->GetContainingInlinedBlock();
2560b57cec5SDimitry Andric                       if (inlined_block) {
2570b57cec5SDimitry Andric                         AddressRange inline_range;
2580b57cec5SDimitry Andric                         inlined_block->GetRangeContainingAddress(prev_address,
2590b57cec5SDimitry Andric                                                                  inline_range);
2600b57cec5SDimitry Andric                         if (!inline_range.ContainsFileAddress(cur_address)) {
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric                           step_past_remaining_inline = true;
2630b57cec5SDimitry Andric                         }
2640b57cec5SDimitry Andric                       }
2650b57cec5SDimitry Andric                     }
2660b57cec5SDimitry Andric                   }
2670b57cec5SDimitry Andric                 }
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric                 if (step_past_remaining_inline) {
2700b57cec5SDimitry Andric                   uint32_t look_ahead_step = 1;
2710b57cec5SDimitry Andric                   while (line_table->GetLineEntryAtIndex(
2720b57cec5SDimitry Andric                       entry_idx + look_ahead_step, next_line_entry)) {
2730b57cec5SDimitry Andric                     // Make sure we haven't wandered out of the function we
2740b57cec5SDimitry Andric                     // started from...
2750b57cec5SDimitry Andric                     Address next_line_address =
2760b57cec5SDimitry Andric                         next_line_entry.range.GetBaseAddress();
2770b57cec5SDimitry Andric                     Function *next_line_function =
2780b57cec5SDimitry Andric                         next_line_address.CalculateSymbolContextFunction();
2790b57cec5SDimitry Andric                     if (next_line_function != m_addr_context.function)
2800b57cec5SDimitry Andric                       break;
2810b57cec5SDimitry Andric 
282*a58f00eaSDimitry Andric                     if (*next_line_entry.original_file_sp ==
283*a58f00eaSDimitry Andric                         *m_addr_context.line_entry.original_file_sp) {
2840b57cec5SDimitry Andric                       const bool abort_other_plans = false;
2850b57cec5SDimitry Andric                       const RunMode stop_other_threads = RunMode::eAllThreads;
2865ffd83dbSDimitry Andric                       lldb::addr_t cur_pc = thread.GetStackFrameAtIndex(0)
2870b57cec5SDimitry Andric                                                 ->GetRegisterContext()
2880b57cec5SDimitry Andric                                                 ->GetPC();
2890b57cec5SDimitry Andric                       AddressRange step_range(
2900b57cec5SDimitry Andric                           cur_pc,
2910b57cec5SDimitry Andric                           next_line_address.GetLoadAddress(&GetTarget()) -
2920b57cec5SDimitry Andric                               cur_pc);
2930b57cec5SDimitry Andric 
2945ffd83dbSDimitry Andric                       new_plan_sp = thread.QueueThreadPlanForStepOverRange(
2950b57cec5SDimitry Andric                           abort_other_plans, step_range, sc, stop_other_threads,
2960b57cec5SDimitry Andric                           m_status);
2970b57cec5SDimitry Andric                       break;
2980b57cec5SDimitry Andric                     }
2990b57cec5SDimitry Andric                     look_ahead_step++;
3000b57cec5SDimitry Andric                   }
3010b57cec5SDimitry Andric                 }
3020b57cec5SDimitry Andric               }
3030b57cec5SDimitry Andric             }
3040b57cec5SDimitry Andric           }
3050b57cec5SDimitry Andric         }
3060b57cec5SDimitry Andric       }
3070b57cec5SDimitry Andric     }
3080b57cec5SDimitry Andric   }
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric   // If we get to this point, we're not going to use a previously set "next
3110b57cec5SDimitry Andric   // branch" breakpoint, so delete it:
3120b57cec5SDimitry Andric   ClearNextBranchBreakpoint();
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric   // If we haven't figured out something to do yet, then ask the ShouldStopHere
3150b57cec5SDimitry Andric   // callback:
3160b57cec5SDimitry Andric   if (!new_plan_sp) {
3170b57cec5SDimitry Andric     new_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order, m_status);
3180b57cec5SDimitry Andric   }
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric   if (!new_plan_sp)
3210b57cec5SDimitry Andric     m_no_more_plans = true;
3220b57cec5SDimitry Andric   else {
3230b57cec5SDimitry Andric     // Any new plan will be an implementation plan, so mark it private:
3240b57cec5SDimitry Andric     new_plan_sp->SetPrivate(true);
3250b57cec5SDimitry Andric     m_no_more_plans = false;
3260b57cec5SDimitry Andric   }
3270b57cec5SDimitry Andric 
3280b57cec5SDimitry Andric   if (!new_plan_sp) {
3290b57cec5SDimitry Andric     // For efficiencies sake, we know we're done here so we don't have to do
3300b57cec5SDimitry Andric     // this calculation again in MischiefManaged.
3310b57cec5SDimitry Andric     SetPlanComplete(m_status.Success());
3320b57cec5SDimitry Andric     return true;
3330b57cec5SDimitry Andric   } else
3340b57cec5SDimitry Andric     return false;
3350b57cec5SDimitry Andric }
3360b57cec5SDimitry Andric 
DoPlanExplainsStop(Event * event_ptr)3370b57cec5SDimitry Andric bool ThreadPlanStepOverRange::DoPlanExplainsStop(Event *event_ptr) {
3380b57cec5SDimitry Andric   // For crashes, breakpoint hits, signals, etc, let the base plan (or some
3390b57cec5SDimitry Andric   // plan above us) handle the stop.  That way the user can see the stop, step
3400b57cec5SDimitry Andric   // around, and then when they are done, continue and have their step
3410b57cec5SDimitry Andric   // complete.  The exception is if we've hit our "run to next branch"
3420b57cec5SDimitry Andric   // breakpoint. Note, unlike the step in range plan, we don't mark ourselves
3430b57cec5SDimitry Andric   // complete if we hit an unexplained breakpoint/crash.
3440b57cec5SDimitry Andric 
34581ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
3460b57cec5SDimitry Andric   StopInfoSP stop_info_sp = GetPrivateStopInfo();
3470b57cec5SDimitry Andric   bool return_value;
3480b57cec5SDimitry Andric 
3490b57cec5SDimitry Andric   if (stop_info_sp) {
3500b57cec5SDimitry Andric     StopReason reason = stop_info_sp->GetStopReason();
3510b57cec5SDimitry Andric 
3520b57cec5SDimitry Andric     if (reason == eStopReasonTrace) {
3530b57cec5SDimitry Andric       return_value = true;
3540b57cec5SDimitry Andric     } else if (reason == eStopReasonBreakpoint) {
3550b57cec5SDimitry Andric       return_value = NextRangeBreakpointExplainsStop(stop_info_sp);
3560b57cec5SDimitry Andric     } else {
3570b57cec5SDimitry Andric       if (log)
3580b57cec5SDimitry Andric         log->PutCString("ThreadPlanStepInRange got asked if it explains the "
3590b57cec5SDimitry Andric                         "stop for some reason other than step.");
3600b57cec5SDimitry Andric       return_value = false;
3610b57cec5SDimitry Andric     }
3620b57cec5SDimitry Andric   } else
3630b57cec5SDimitry Andric     return_value = true;
3640b57cec5SDimitry Andric 
3650b57cec5SDimitry Andric   return return_value;
3660b57cec5SDimitry Andric }
3670b57cec5SDimitry Andric 
DoWillResume(lldb::StateType resume_state,bool current_plan)3680b57cec5SDimitry Andric bool ThreadPlanStepOverRange::DoWillResume(lldb::StateType resume_state,
3690b57cec5SDimitry Andric                                            bool current_plan) {
3700b57cec5SDimitry Andric   if (resume_state != eStateSuspended && m_first_resume) {
3710b57cec5SDimitry Andric     m_first_resume = false;
3720b57cec5SDimitry Andric     if (resume_state == eStateStepping && current_plan) {
3735ffd83dbSDimitry Andric       Thread &thread = GetThread();
3740b57cec5SDimitry Andric       // See if we are about to step over an inlined call in the middle of the
3750b57cec5SDimitry Andric       // inlined stack, if so figure out its extents and reset our range to
3760b57cec5SDimitry Andric       // step over that.
3775ffd83dbSDimitry Andric       bool in_inlined_stack = thread.DecrementCurrentInlinedDepth();
3780b57cec5SDimitry Andric       if (in_inlined_stack) {
37981ad6265SDimitry Andric         Log *log = GetLog(LLDBLog::Step);
3809dba64beSDimitry Andric         LLDB_LOGF(log,
3819dba64beSDimitry Andric                   "ThreadPlanStepInRange::DoWillResume: adjusting range to "
3820b57cec5SDimitry Andric                   "the frame at inlined depth %d.",
3835ffd83dbSDimitry Andric                   thread.GetCurrentInlinedDepth());
3845ffd83dbSDimitry Andric         StackFrameSP stack_sp = thread.GetStackFrameAtIndex(0);
3850b57cec5SDimitry Andric         if (stack_sp) {
3860b57cec5SDimitry Andric           Block *frame_block = stack_sp->GetFrameBlock();
3875ffd83dbSDimitry Andric           lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC();
3880b57cec5SDimitry Andric           AddressRange my_range;
3890b57cec5SDimitry Andric           if (frame_block->GetRangeContainingLoadAddress(
3905ffd83dbSDimitry Andric                   curr_pc, m_process.GetTarget(), my_range)) {
3910b57cec5SDimitry Andric             m_address_ranges.clear();
3920b57cec5SDimitry Andric             m_address_ranges.push_back(my_range);
3930b57cec5SDimitry Andric             if (log) {
3940b57cec5SDimitry Andric               StreamString s;
3950b57cec5SDimitry Andric               const InlineFunctionInfo *inline_info =
3960b57cec5SDimitry Andric                   frame_block->GetInlinedFunctionInfo();
3970b57cec5SDimitry Andric               const char *name;
3980b57cec5SDimitry Andric               if (inline_info)
3995ffd83dbSDimitry Andric                 name = inline_info->GetName().AsCString();
4000b57cec5SDimitry Andric               else
4010b57cec5SDimitry Andric                 name = "<unknown-notinlined>";
4020b57cec5SDimitry Andric 
4030b57cec5SDimitry Andric               s.Printf(
4040b57cec5SDimitry Andric                   "Stepping over inlined function \"%s\" in inlined stack: ",
4050b57cec5SDimitry Andric                   name);
4060b57cec5SDimitry Andric               DumpRanges(&s);
4070b57cec5SDimitry Andric               log->PutString(s.GetString());
4080b57cec5SDimitry Andric             }
4090b57cec5SDimitry Andric           }
4100b57cec5SDimitry Andric         }
4110b57cec5SDimitry Andric       }
4120b57cec5SDimitry Andric     }
4130b57cec5SDimitry Andric   }
4140b57cec5SDimitry Andric 
4150b57cec5SDimitry Andric   return true;
4160b57cec5SDimitry Andric }
417