xref: /freebsd-src/contrib/llvm-project/lldb/source/Target/ThreadPlanStepOverRange.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
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 
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 
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 
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 
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*0fca6ea1SDimitry Andric           if (!sc.line_entry.original_file_sp->Equal(
224*0fca6ea1SDimitry Andric                   *m_addr_context.line_entry.original_file_sp,
225*0fca6ea1SDimitry Andric                   SupportFile::eEqualFileSpecAndChecksumIfSet) &&
2260b57cec5SDimitry Andric               sc.comp_unit == m_addr_context.comp_unit &&
2270b57cec5SDimitry Andric               sc.function == m_addr_context.function) {
2280b57cec5SDimitry Andric             // Okay, find the next occurrence of this file in the line table:
2290b57cec5SDimitry Andric             LineTable *line_table = m_addr_context.comp_unit->GetLineTable();
2300b57cec5SDimitry Andric             if (line_table) {
2310b57cec5SDimitry Andric               Address cur_address = frame_sp->GetFrameCodeAddress();
2320b57cec5SDimitry Andric               uint32_t entry_idx;
2330b57cec5SDimitry Andric               LineEntry line_entry;
2340b57cec5SDimitry Andric               if (line_table->FindLineEntryByAddress(cur_address, line_entry,
2350b57cec5SDimitry Andric                                                      &entry_idx)) {
2360b57cec5SDimitry Andric                 LineEntry next_line_entry;
2370b57cec5SDimitry Andric                 bool step_past_remaining_inline = false;
2380b57cec5SDimitry Andric                 if (entry_idx > 0) {
2390b57cec5SDimitry Andric                   // We require the previous line entry and the current line
2400b57cec5SDimitry Andric                   // entry come from the same file. The other requirement is
2410b57cec5SDimitry Andric                   // that the previous line table entry be part of an inlined
2420b57cec5SDimitry Andric                   // block, we don't want to step past cases where people have
2430b57cec5SDimitry Andric                   // inlined some code fragment by using #include <source-
2440b57cec5SDimitry Andric                   // fragment.c> directly.
2450b57cec5SDimitry Andric                   LineEntry prev_line_entry;
2460b57cec5SDimitry Andric                   if (line_table->GetLineEntryAtIndex(entry_idx - 1,
2470b57cec5SDimitry Andric                                                       prev_line_entry) &&
248*0fca6ea1SDimitry Andric                       prev_line_entry.original_file_sp->Equal(
249*0fca6ea1SDimitry Andric                           *line_entry.original_file_sp,
250*0fca6ea1SDimitry Andric                           SupportFile::eEqualFileSpecAndChecksumIfSet)) {
2510b57cec5SDimitry Andric                     SymbolContext prev_sc;
2520b57cec5SDimitry Andric                     Address prev_address =
2530b57cec5SDimitry Andric                         prev_line_entry.range.GetBaseAddress();
2540b57cec5SDimitry Andric                     prev_address.CalculateSymbolContext(&prev_sc);
2550b57cec5SDimitry Andric                     if (prev_sc.block) {
2560b57cec5SDimitry Andric                       Block *inlined_block =
2570b57cec5SDimitry Andric                           prev_sc.block->GetContainingInlinedBlock();
2580b57cec5SDimitry Andric                       if (inlined_block) {
2590b57cec5SDimitry Andric                         AddressRange inline_range;
2600b57cec5SDimitry Andric                         inlined_block->GetRangeContainingAddress(prev_address,
2610b57cec5SDimitry Andric                                                                  inline_range);
2620b57cec5SDimitry Andric                         if (!inline_range.ContainsFileAddress(cur_address)) {
2630b57cec5SDimitry Andric 
2640b57cec5SDimitry Andric                           step_past_remaining_inline = true;
2650b57cec5SDimitry Andric                         }
2660b57cec5SDimitry Andric                       }
2670b57cec5SDimitry Andric                     }
2680b57cec5SDimitry Andric                   }
2690b57cec5SDimitry Andric                 }
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric                 if (step_past_remaining_inline) {
2720b57cec5SDimitry Andric                   uint32_t look_ahead_step = 1;
2730b57cec5SDimitry Andric                   while (line_table->GetLineEntryAtIndex(
2740b57cec5SDimitry Andric                       entry_idx + look_ahead_step, next_line_entry)) {
2750b57cec5SDimitry Andric                     // Make sure we haven't wandered out of the function we
2760b57cec5SDimitry Andric                     // started from...
2770b57cec5SDimitry Andric                     Address next_line_address =
2780b57cec5SDimitry Andric                         next_line_entry.range.GetBaseAddress();
2790b57cec5SDimitry Andric                     Function *next_line_function =
2800b57cec5SDimitry Andric                         next_line_address.CalculateSymbolContextFunction();
2810b57cec5SDimitry Andric                     if (next_line_function != m_addr_context.function)
2820b57cec5SDimitry Andric                       break;
2830b57cec5SDimitry Andric 
284*0fca6ea1SDimitry Andric                     if (next_line_entry.original_file_sp->Equal(
285*0fca6ea1SDimitry Andric                             *m_addr_context.line_entry.original_file_sp,
286*0fca6ea1SDimitry Andric                             SupportFile::eEqualFileSpecAndChecksumIfSet)) {
2870b57cec5SDimitry Andric                       const bool abort_other_plans = false;
2880b57cec5SDimitry Andric                       const RunMode stop_other_threads = RunMode::eAllThreads;
2895ffd83dbSDimitry Andric                       lldb::addr_t cur_pc = thread.GetStackFrameAtIndex(0)
2900b57cec5SDimitry Andric                                                 ->GetRegisterContext()
2910b57cec5SDimitry Andric                                                 ->GetPC();
2920b57cec5SDimitry Andric                       AddressRange step_range(
2930b57cec5SDimitry Andric                           cur_pc,
2940b57cec5SDimitry Andric                           next_line_address.GetLoadAddress(&GetTarget()) -
2950b57cec5SDimitry Andric                               cur_pc);
2960b57cec5SDimitry Andric 
2975ffd83dbSDimitry Andric                       new_plan_sp = thread.QueueThreadPlanForStepOverRange(
2980b57cec5SDimitry Andric                           abort_other_plans, step_range, sc, stop_other_threads,
2990b57cec5SDimitry Andric                           m_status);
3000b57cec5SDimitry Andric                       break;
3010b57cec5SDimitry Andric                     }
3020b57cec5SDimitry Andric                     look_ahead_step++;
3030b57cec5SDimitry Andric                   }
3040b57cec5SDimitry Andric                 }
3050b57cec5SDimitry Andric               }
3060b57cec5SDimitry Andric             }
3070b57cec5SDimitry Andric           }
3080b57cec5SDimitry Andric         }
3090b57cec5SDimitry Andric       }
3100b57cec5SDimitry Andric     }
3110b57cec5SDimitry Andric   }
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric   // If we get to this point, we're not going to use a previously set "next
3140b57cec5SDimitry Andric   // branch" breakpoint, so delete it:
3150b57cec5SDimitry Andric   ClearNextBranchBreakpoint();
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric   // If we haven't figured out something to do yet, then ask the ShouldStopHere
3180b57cec5SDimitry Andric   // callback:
3190b57cec5SDimitry Andric   if (!new_plan_sp) {
3200b57cec5SDimitry Andric     new_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order, m_status);
3210b57cec5SDimitry Andric   }
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric   if (!new_plan_sp)
3240b57cec5SDimitry Andric     m_no_more_plans = true;
3250b57cec5SDimitry Andric   else {
3260b57cec5SDimitry Andric     // Any new plan will be an implementation plan, so mark it private:
3270b57cec5SDimitry Andric     new_plan_sp->SetPrivate(true);
3280b57cec5SDimitry Andric     m_no_more_plans = false;
3290b57cec5SDimitry Andric   }
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric   if (!new_plan_sp) {
3320b57cec5SDimitry Andric     // For efficiencies sake, we know we're done here so we don't have to do
3330b57cec5SDimitry Andric     // this calculation again in MischiefManaged.
3340b57cec5SDimitry Andric     SetPlanComplete(m_status.Success());
3350b57cec5SDimitry Andric     return true;
3360b57cec5SDimitry Andric   } else
3370b57cec5SDimitry Andric     return false;
3380b57cec5SDimitry Andric }
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric bool ThreadPlanStepOverRange::DoPlanExplainsStop(Event *event_ptr) {
3410b57cec5SDimitry Andric   // For crashes, breakpoint hits, signals, etc, let the base plan (or some
3420b57cec5SDimitry Andric   // plan above us) handle the stop.  That way the user can see the stop, step
3430b57cec5SDimitry Andric   // around, and then when they are done, continue and have their step
3440b57cec5SDimitry Andric   // complete.  The exception is if we've hit our "run to next branch"
3450b57cec5SDimitry Andric   // breakpoint. Note, unlike the step in range plan, we don't mark ourselves
3460b57cec5SDimitry Andric   // complete if we hit an unexplained breakpoint/crash.
3470b57cec5SDimitry Andric 
34881ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
3490b57cec5SDimitry Andric   StopInfoSP stop_info_sp = GetPrivateStopInfo();
3500b57cec5SDimitry Andric   bool return_value;
3510b57cec5SDimitry Andric 
3520b57cec5SDimitry Andric   if (stop_info_sp) {
3530b57cec5SDimitry Andric     StopReason reason = stop_info_sp->GetStopReason();
3540b57cec5SDimitry Andric 
3550b57cec5SDimitry Andric     if (reason == eStopReasonTrace) {
3560b57cec5SDimitry Andric       return_value = true;
3570b57cec5SDimitry Andric     } else if (reason == eStopReasonBreakpoint) {
3580b57cec5SDimitry Andric       return_value = NextRangeBreakpointExplainsStop(stop_info_sp);
3590b57cec5SDimitry Andric     } else {
3600b57cec5SDimitry Andric       if (log)
361*0fca6ea1SDimitry Andric         log->PutCString("ThreadPlanStepOverRange got asked if it explains the "
3620b57cec5SDimitry Andric                         "stop for some reason other than step.");
3630b57cec5SDimitry Andric       return_value = false;
3640b57cec5SDimitry Andric     }
3650b57cec5SDimitry Andric   } else
3660b57cec5SDimitry Andric     return_value = true;
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric   return return_value;
3690b57cec5SDimitry Andric }
3700b57cec5SDimitry Andric 
3710b57cec5SDimitry Andric bool ThreadPlanStepOverRange::DoWillResume(lldb::StateType resume_state,
3720b57cec5SDimitry Andric                                            bool current_plan) {
3730b57cec5SDimitry Andric   if (resume_state != eStateSuspended && m_first_resume) {
3740b57cec5SDimitry Andric     m_first_resume = false;
3750b57cec5SDimitry Andric     if (resume_state == eStateStepping && current_plan) {
3765ffd83dbSDimitry Andric       Thread &thread = GetThread();
3770b57cec5SDimitry Andric       // See if we are about to step over an inlined call in the middle of the
3780b57cec5SDimitry Andric       // inlined stack, if so figure out its extents and reset our range to
3790b57cec5SDimitry Andric       // step over that.
3805ffd83dbSDimitry Andric       bool in_inlined_stack = thread.DecrementCurrentInlinedDepth();
3810b57cec5SDimitry Andric       if (in_inlined_stack) {
38281ad6265SDimitry Andric         Log *log = GetLog(LLDBLog::Step);
3839dba64beSDimitry Andric         LLDB_LOGF(log,
3849dba64beSDimitry Andric                   "ThreadPlanStepInRange::DoWillResume: adjusting range to "
3850b57cec5SDimitry Andric                   "the frame at inlined depth %d.",
3865ffd83dbSDimitry Andric                   thread.GetCurrentInlinedDepth());
3875ffd83dbSDimitry Andric         StackFrameSP stack_sp = thread.GetStackFrameAtIndex(0);
3880b57cec5SDimitry Andric         if (stack_sp) {
3890b57cec5SDimitry Andric           Block *frame_block = stack_sp->GetFrameBlock();
3905ffd83dbSDimitry Andric           lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC();
3910b57cec5SDimitry Andric           AddressRange my_range;
3920b57cec5SDimitry Andric           if (frame_block->GetRangeContainingLoadAddress(
3935ffd83dbSDimitry Andric                   curr_pc, m_process.GetTarget(), my_range)) {
3940b57cec5SDimitry Andric             m_address_ranges.clear();
3950b57cec5SDimitry Andric             m_address_ranges.push_back(my_range);
3960b57cec5SDimitry Andric             if (log) {
3970b57cec5SDimitry Andric               StreamString s;
3980b57cec5SDimitry Andric               const InlineFunctionInfo *inline_info =
3990b57cec5SDimitry Andric                   frame_block->GetInlinedFunctionInfo();
4000b57cec5SDimitry Andric               const char *name;
4010b57cec5SDimitry Andric               if (inline_info)
4025ffd83dbSDimitry Andric                 name = inline_info->GetName().AsCString();
4030b57cec5SDimitry Andric               else
4040b57cec5SDimitry Andric                 name = "<unknown-notinlined>";
4050b57cec5SDimitry Andric 
4060b57cec5SDimitry Andric               s.Printf(
4070b57cec5SDimitry Andric                   "Stepping over inlined function \"%s\" in inlined stack: ",
4080b57cec5SDimitry Andric                   name);
4090b57cec5SDimitry Andric               DumpRanges(&s);
4100b57cec5SDimitry Andric               log->PutString(s.GetString());
4110b57cec5SDimitry Andric             }
4120b57cec5SDimitry Andric           }
4130b57cec5SDimitry Andric         }
4140b57cec5SDimitry Andric       }
4150b57cec5SDimitry Andric     }
4160b57cec5SDimitry Andric   }
4170b57cec5SDimitry Andric 
4180b57cec5SDimitry Andric   return true;
4190b57cec5SDimitry Andric }
420