15ffd83dbSDimitry Andric //===-- ThreadPlanStepRange.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/ThreadPlanStepRange.h"
100b57cec5SDimitry Andric #include "lldb/Breakpoint/BreakpointLocation.h"
110b57cec5SDimitry Andric #include "lldb/Breakpoint/BreakpointSite.h"
120b57cec5SDimitry Andric #include "lldb/Core/Disassembler.h"
130b57cec5SDimitry Andric #include "lldb/Symbol/Function.h"
140b57cec5SDimitry Andric #include "lldb/Symbol/Symbol.h"
150b57cec5SDimitry Andric #include "lldb/Target/ExecutionContext.h"
160b57cec5SDimitry Andric #include "lldb/Target/Process.h"
170b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
180b57cec5SDimitry Andric #include "lldb/Target/StopInfo.h"
190b57cec5SDimitry Andric #include "lldb/Target/Target.h"
200b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
210b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanRunToAddress.h"
2281ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
230b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
240b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric using namespace lldb;
270b57cec5SDimitry Andric using namespace lldb_private;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric // ThreadPlanStepRange: Step through a stack range, either stepping over or
300b57cec5SDimitry Andric // into based on the value of \a type.
310b57cec5SDimitry Andric 
ThreadPlanStepRange(ThreadPlanKind kind,const char * name,Thread & thread,const AddressRange & range,const SymbolContext & addr_context,lldb::RunMode stop_others,bool given_ranges_only)320b57cec5SDimitry Andric ThreadPlanStepRange::ThreadPlanStepRange(ThreadPlanKind kind, const char *name,
330b57cec5SDimitry Andric                                          Thread &thread,
340b57cec5SDimitry Andric                                          const AddressRange &range,
350b57cec5SDimitry Andric                                          const SymbolContext &addr_context,
360b57cec5SDimitry Andric                                          lldb::RunMode stop_others,
370b57cec5SDimitry Andric                                          bool given_ranges_only)
380b57cec5SDimitry Andric     : ThreadPlan(kind, name, thread, eVoteNoOpinion, eVoteNoOpinion),
390b57cec5SDimitry Andric       m_addr_context(addr_context), m_address_ranges(),
400b57cec5SDimitry Andric       m_stop_others(stop_others), m_stack_id(), m_parent_stack_id(),
410b57cec5SDimitry Andric       m_no_more_plans(false), m_first_run_event(true), m_use_fast_step(false),
420b57cec5SDimitry Andric       m_given_ranges_only(given_ranges_only) {
430b57cec5SDimitry Andric   m_use_fast_step = GetTarget().GetUseFastStepping();
440b57cec5SDimitry Andric   AddRange(range);
455ffd83dbSDimitry Andric   m_stack_id = thread.GetStackFrameAtIndex(0)->GetStackID();
465ffd83dbSDimitry Andric   StackFrameSP parent_stack = thread.GetStackFrameAtIndex(1);
470b57cec5SDimitry Andric   if (parent_stack)
480b57cec5SDimitry Andric     m_parent_stack_id = parent_stack->GetStackID();
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric 
~ThreadPlanStepRange()510b57cec5SDimitry Andric ThreadPlanStepRange::~ThreadPlanStepRange() { ClearNextBranchBreakpoint(); }
520b57cec5SDimitry Andric 
DidPush()530b57cec5SDimitry Andric void ThreadPlanStepRange::DidPush() {
540b57cec5SDimitry Andric   // See if we can find a "next range" breakpoint:
550b57cec5SDimitry Andric   SetNextBranchBreakpoint();
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric 
ValidatePlan(Stream * error)580b57cec5SDimitry Andric bool ThreadPlanStepRange::ValidatePlan(Stream *error) {
590b57cec5SDimitry Andric   if (m_could_not_resolve_hw_bp) {
600b57cec5SDimitry Andric     if (error)
610b57cec5SDimitry Andric       error->PutCString(
620b57cec5SDimitry Andric           "Could not create hardware breakpoint for thread plan.");
630b57cec5SDimitry Andric     return false;
640b57cec5SDimitry Andric   }
650b57cec5SDimitry Andric   return true;
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric 
ShouldReportStop(Event * event_ptr)680b57cec5SDimitry Andric Vote ThreadPlanStepRange::ShouldReportStop(Event *event_ptr) {
6981ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric   const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo;
729dba64beSDimitry Andric   LLDB_LOGF(log, "ThreadPlanStepRange::ShouldReportStop() returning vote %i\n",
730b57cec5SDimitry Andric             vote);
740b57cec5SDimitry Andric   return vote;
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric 
AddRange(const AddressRange & new_range)770b57cec5SDimitry Andric void ThreadPlanStepRange::AddRange(const AddressRange &new_range) {
780b57cec5SDimitry Andric   // For now I'm just adding the ranges.  At some point we may want to condense
790b57cec5SDimitry Andric   // the ranges if they overlap, though I don't think it is likely to be very
800b57cec5SDimitry Andric   // important.
810b57cec5SDimitry Andric   m_address_ranges.push_back(new_range);
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   // Fill the slot for this address range with an empty DisassemblerSP in the
840b57cec5SDimitry Andric   // instruction ranges. I want the indices to match, but I don't want to do
850b57cec5SDimitry Andric   // the work to disassemble this range if I don't step into it.
860b57cec5SDimitry Andric   m_instruction_ranges.push_back(DisassemblerSP());
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric 
DumpRanges(Stream * s)890b57cec5SDimitry Andric void ThreadPlanStepRange::DumpRanges(Stream *s) {
900b57cec5SDimitry Andric   size_t num_ranges = m_address_ranges.size();
910b57cec5SDimitry Andric   if (num_ranges == 1) {
925ffd83dbSDimitry Andric     m_address_ranges[0].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress);
930b57cec5SDimitry Andric   } else {
940b57cec5SDimitry Andric     for (size_t i = 0; i < num_ranges; i++) {
950b57cec5SDimitry Andric       s->Printf(" %" PRIu64 ": ", uint64_t(i));
965ffd83dbSDimitry Andric       m_address_ranges[i].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress);
970b57cec5SDimitry Andric     }
980b57cec5SDimitry Andric   }
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric 
InRange()1010b57cec5SDimitry Andric bool ThreadPlanStepRange::InRange() {
10281ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
1030b57cec5SDimitry Andric   bool ret_value = false;
1045ffd83dbSDimitry Andric   Thread &thread = GetThread();
1055ffd83dbSDimitry Andric   lldb::addr_t pc_load_addr = thread.GetRegisterContext()->GetPC();
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   size_t num_ranges = m_address_ranges.size();
1080b57cec5SDimitry Andric   for (size_t i = 0; i < num_ranges; i++) {
1095ffd83dbSDimitry Andric     ret_value =
1105ffd83dbSDimitry Andric         m_address_ranges[i].ContainsLoadAddress(pc_load_addr, &GetTarget());
1110b57cec5SDimitry Andric     if (ret_value)
1120b57cec5SDimitry Andric       break;
1130b57cec5SDimitry Andric   }
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric   if (!ret_value && !m_given_ranges_only) {
1160b57cec5SDimitry Andric     // See if we've just stepped to another part of the same line number...
1175ffd83dbSDimitry Andric     StackFrame *frame = thread.GetStackFrameAtIndex(0).get();
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric     SymbolContext new_context(
1200b57cec5SDimitry Andric         frame->GetSymbolContext(eSymbolContextEverything));
1210b57cec5SDimitry Andric     if (m_addr_context.line_entry.IsValid() &&
1220b57cec5SDimitry Andric         new_context.line_entry.IsValid()) {
123*a58f00eaSDimitry Andric       if (*m_addr_context.line_entry.original_file_sp ==
124*a58f00eaSDimitry Andric           *new_context.line_entry.original_file_sp) {
1250b57cec5SDimitry Andric         if (m_addr_context.line_entry.line == new_context.line_entry.line) {
1260b57cec5SDimitry Andric           m_addr_context = new_context;
1270b57cec5SDimitry Andric           const bool include_inlined_functions =
1280b57cec5SDimitry Andric               GetKind() == eKindStepOverRange;
1290b57cec5SDimitry Andric           AddRange(m_addr_context.line_entry.GetSameLineContiguousAddressRange(
1300b57cec5SDimitry Andric               include_inlined_functions));
1310b57cec5SDimitry Andric           ret_value = true;
1320b57cec5SDimitry Andric           if (log) {
1330b57cec5SDimitry Andric             StreamString s;
1345ffd83dbSDimitry Andric             m_addr_context.line_entry.Dump(&s, &GetTarget(), true,
1355ffd83dbSDimitry Andric                                            Address::DumpStyleLoadAddress,
1360b57cec5SDimitry Andric                                            Address::DumpStyleLoadAddress, true);
1370b57cec5SDimitry Andric 
1389dba64beSDimitry Andric             LLDB_LOGF(
1399dba64beSDimitry Andric                 log,
1400b57cec5SDimitry Andric                 "Step range plan stepped to another range of same line: %s",
1410b57cec5SDimitry Andric                 s.GetData());
1420b57cec5SDimitry Andric           }
1430b57cec5SDimitry Andric         } else if (new_context.line_entry.line == 0) {
1440b57cec5SDimitry Andric           new_context.line_entry.line = m_addr_context.line_entry.line;
1450b57cec5SDimitry Andric           m_addr_context = new_context;
1460b57cec5SDimitry Andric           const bool include_inlined_functions =
1470b57cec5SDimitry Andric               GetKind() == eKindStepOverRange;
1480b57cec5SDimitry Andric           AddRange(m_addr_context.line_entry.GetSameLineContiguousAddressRange(
1490b57cec5SDimitry Andric               include_inlined_functions));
1500b57cec5SDimitry Andric           ret_value = true;
1510b57cec5SDimitry Andric           if (log) {
1520b57cec5SDimitry Andric             StreamString s;
1535ffd83dbSDimitry Andric             m_addr_context.line_entry.Dump(&s, &GetTarget(), true,
1545ffd83dbSDimitry Andric                                            Address::DumpStyleLoadAddress,
1550b57cec5SDimitry Andric                                            Address::DumpStyleLoadAddress, true);
1560b57cec5SDimitry Andric 
1579dba64beSDimitry Andric             LLDB_LOGF(log,
1589dba64beSDimitry Andric                       "Step range plan stepped to a range at linenumber 0 "
1590b57cec5SDimitry Andric                       "stepping through that range: %s",
1600b57cec5SDimitry Andric                       s.GetData());
1610b57cec5SDimitry Andric           }
1620b57cec5SDimitry Andric         } else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(
1635ffd83dbSDimitry Andric                        &GetTarget()) != pc_load_addr) {
1640b57cec5SDimitry Andric           // Another thing that sometimes happens here is that we step out of
1650b57cec5SDimitry Andric           // one line into the MIDDLE of another line.  So far I mostly see
1660b57cec5SDimitry Andric           // this due to bugs in the debug information. But we probably don't
1670b57cec5SDimitry Andric           // want to be in the middle of a line range, so in that case reset
1680b57cec5SDimitry Andric           // the stepping range to the line we've stepped into the middle of
1690b57cec5SDimitry Andric           // and continue.
1700b57cec5SDimitry Andric           m_addr_context = new_context;
1710b57cec5SDimitry Andric           m_address_ranges.clear();
1720b57cec5SDimitry Andric           AddRange(m_addr_context.line_entry.range);
1730b57cec5SDimitry Andric           ret_value = true;
1740b57cec5SDimitry Andric           if (log) {
1750b57cec5SDimitry Andric             StreamString s;
1765ffd83dbSDimitry Andric             m_addr_context.line_entry.Dump(&s, &GetTarget(), true,
1775ffd83dbSDimitry Andric                                            Address::DumpStyleLoadAddress,
1780b57cec5SDimitry Andric                                            Address::DumpStyleLoadAddress, true);
1790b57cec5SDimitry Andric 
1809dba64beSDimitry Andric             LLDB_LOGF(log,
1819dba64beSDimitry Andric                       "Step range plan stepped to the middle of new "
1820b57cec5SDimitry Andric                       "line(%d): %s, continuing to clear this line.",
1830b57cec5SDimitry Andric                       new_context.line_entry.line, s.GetData());
1840b57cec5SDimitry Andric           }
1850b57cec5SDimitry Andric         }
1860b57cec5SDimitry Andric       }
1870b57cec5SDimitry Andric     }
1880b57cec5SDimitry Andric   }
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric   if (!ret_value && log)
1919dba64beSDimitry Andric     LLDB_LOGF(log, "Step range plan out of range to 0x%" PRIx64, pc_load_addr);
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric   return ret_value;
1940b57cec5SDimitry Andric }
1950b57cec5SDimitry Andric 
InSymbol()1960b57cec5SDimitry Andric bool ThreadPlanStepRange::InSymbol() {
1975ffd83dbSDimitry Andric   lldb::addr_t cur_pc = GetThread().GetRegisterContext()->GetPC();
1980b57cec5SDimitry Andric   if (m_addr_context.function != nullptr) {
1990b57cec5SDimitry Andric     return m_addr_context.function->GetAddressRange().ContainsLoadAddress(
2005ffd83dbSDimitry Andric         cur_pc, &GetTarget());
2010b57cec5SDimitry Andric   } else if (m_addr_context.symbol && m_addr_context.symbol->ValueIsAddress()) {
2020b57cec5SDimitry Andric     AddressRange range(m_addr_context.symbol->GetAddressRef(),
2030b57cec5SDimitry Andric                        m_addr_context.symbol->GetByteSize());
2045ffd83dbSDimitry Andric     return range.ContainsLoadAddress(cur_pc, &GetTarget());
2050b57cec5SDimitry Andric   }
2060b57cec5SDimitry Andric   return false;
2070b57cec5SDimitry Andric }
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric // FIXME: This should also handle inlining if we aren't going to do inlining in
2100b57cec5SDimitry Andric // the
2110b57cec5SDimitry Andric // main stack.
2120b57cec5SDimitry Andric //
2130b57cec5SDimitry Andric // Ideally we should remember the whole stack frame list, and then compare that
2140b57cec5SDimitry Andric // to the current list.
2150b57cec5SDimitry Andric 
CompareCurrentFrameToStartFrame()2160b57cec5SDimitry Andric lldb::FrameComparison ThreadPlanStepRange::CompareCurrentFrameToStartFrame() {
2170b57cec5SDimitry Andric   FrameComparison frame_order;
2185ffd83dbSDimitry Andric   Thread &thread = GetThread();
2195ffd83dbSDimitry Andric   StackID cur_frame_id = thread.GetStackFrameAtIndex(0)->GetStackID();
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric   if (cur_frame_id == m_stack_id) {
2220b57cec5SDimitry Andric     frame_order = eFrameCompareEqual;
2230b57cec5SDimitry Andric   } else if (cur_frame_id < m_stack_id) {
2240b57cec5SDimitry Andric     frame_order = eFrameCompareYounger;
2250b57cec5SDimitry Andric   } else {
2265ffd83dbSDimitry Andric     StackFrameSP cur_parent_frame = thread.GetStackFrameAtIndex(1);
2270b57cec5SDimitry Andric     StackID cur_parent_id;
2280b57cec5SDimitry Andric     if (cur_parent_frame)
2290b57cec5SDimitry Andric       cur_parent_id = cur_parent_frame->GetStackID();
2300b57cec5SDimitry Andric     if (m_parent_stack_id.IsValid() && cur_parent_id.IsValid() &&
2310b57cec5SDimitry Andric         m_parent_stack_id == cur_parent_id)
2320b57cec5SDimitry Andric       frame_order = eFrameCompareSameParent;
2330b57cec5SDimitry Andric     else
2340b57cec5SDimitry Andric       frame_order = eFrameCompareOlder;
2350b57cec5SDimitry Andric   }
2360b57cec5SDimitry Andric   return frame_order;
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric 
StopOthers()2390b57cec5SDimitry Andric bool ThreadPlanStepRange::StopOthers() {
240480093f4SDimitry Andric   switch (m_stop_others) {
241480093f4SDimitry Andric   case lldb::eOnlyThisThread:
242480093f4SDimitry Andric     return true;
243480093f4SDimitry Andric   case lldb::eOnlyDuringStepping:
244480093f4SDimitry Andric     // If there is a call in the range of the next branch breakpoint,
245480093f4SDimitry Andric     // then we should always run all threads, since a call can execute
246480093f4SDimitry Andric     // arbitrary code which might for instance take a lock that's held
247480093f4SDimitry Andric     // by another thread.
248480093f4SDimitry Andric     return !m_found_calls;
249480093f4SDimitry Andric   case lldb::eAllThreads:
250480093f4SDimitry Andric     return false;
251480093f4SDimitry Andric   }
252480093f4SDimitry Andric   llvm_unreachable("Unhandled run mode!");
2530b57cec5SDimitry Andric }
2540b57cec5SDimitry Andric 
GetInstructionsForAddress(lldb::addr_t addr,size_t & range_index,size_t & insn_offset)2550b57cec5SDimitry Andric InstructionList *ThreadPlanStepRange::GetInstructionsForAddress(
2560b57cec5SDimitry Andric     lldb::addr_t addr, size_t &range_index, size_t &insn_offset) {
2570b57cec5SDimitry Andric   size_t num_ranges = m_address_ranges.size();
2580b57cec5SDimitry Andric   for (size_t i = 0; i < num_ranges; i++) {
2590b57cec5SDimitry Andric     if (m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget())) {
2600b57cec5SDimitry Andric       // Some joker added a zero size range to the stepping range...
2610b57cec5SDimitry Andric       if (m_address_ranges[i].GetByteSize() == 0)
2620b57cec5SDimitry Andric         return nullptr;
2630b57cec5SDimitry Andric 
2640b57cec5SDimitry Andric       if (!m_instruction_ranges[i]) {
2650b57cec5SDimitry Andric         // Disassemble the address range given:
2660b57cec5SDimitry Andric         const char *plugin_name = nullptr;
2670b57cec5SDimitry Andric         const char *flavor = nullptr;
2680b57cec5SDimitry Andric         m_instruction_ranges[i] = Disassembler::DisassembleRange(
2695ffd83dbSDimitry Andric             GetTarget().GetArchitecture(), plugin_name, flavor, GetTarget(),
270fe6060f1SDimitry Andric             m_address_ranges[i]);
2710b57cec5SDimitry Andric       }
2720b57cec5SDimitry Andric       if (!m_instruction_ranges[i])
2730b57cec5SDimitry Andric         return nullptr;
2740b57cec5SDimitry Andric       else {
2750b57cec5SDimitry Andric         // Find where we are in the instruction list as well.  If we aren't at
2760b57cec5SDimitry Andric         // an instruction, return nullptr. In this case, we're probably lost,
2770b57cec5SDimitry Andric         // and shouldn't try to do anything fancy.
2780b57cec5SDimitry Andric 
2790b57cec5SDimitry Andric         insn_offset =
2800b57cec5SDimitry Andric             m_instruction_ranges[i]
2810b57cec5SDimitry Andric                 ->GetInstructionList()
2820b57cec5SDimitry Andric                 .GetIndexOfInstructionAtLoadAddress(addr, GetTarget());
2830b57cec5SDimitry Andric         if (insn_offset == UINT32_MAX)
2840b57cec5SDimitry Andric           return nullptr;
2850b57cec5SDimitry Andric         else {
2860b57cec5SDimitry Andric           range_index = i;
2870b57cec5SDimitry Andric           return &m_instruction_ranges[i]->GetInstructionList();
2880b57cec5SDimitry Andric         }
2890b57cec5SDimitry Andric       }
2900b57cec5SDimitry Andric     }
2910b57cec5SDimitry Andric   }
2920b57cec5SDimitry Andric   return nullptr;
2930b57cec5SDimitry Andric }
2940b57cec5SDimitry Andric 
ClearNextBranchBreakpoint()2950b57cec5SDimitry Andric void ThreadPlanStepRange::ClearNextBranchBreakpoint() {
2960b57cec5SDimitry Andric   if (m_next_branch_bp_sp) {
29781ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Step);
2989dba64beSDimitry Andric     LLDB_LOGF(log, "Removing next branch breakpoint: %d.",
2990b57cec5SDimitry Andric               m_next_branch_bp_sp->GetID());
3000b57cec5SDimitry Andric     GetTarget().RemoveBreakpointByID(m_next_branch_bp_sp->GetID());
3010b57cec5SDimitry Andric     m_next_branch_bp_sp.reset();
3020b57cec5SDimitry Andric     m_could_not_resolve_hw_bp = false;
303480093f4SDimitry Andric     m_found_calls = false;
3040b57cec5SDimitry Andric   }
3050b57cec5SDimitry Andric }
3060b57cec5SDimitry Andric 
SetNextBranchBreakpoint()3070b57cec5SDimitry Andric bool ThreadPlanStepRange::SetNextBranchBreakpoint() {
3080b57cec5SDimitry Andric   if (m_next_branch_bp_sp)
3090b57cec5SDimitry Andric     return true;
3100b57cec5SDimitry Andric 
31181ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
3120b57cec5SDimitry Andric   // Stepping through ranges using breakpoints doesn't work yet, but with this
3130b57cec5SDimitry Andric   // off we fall back to instruction single stepping.
3140b57cec5SDimitry Andric   if (!m_use_fast_step)
3150b57cec5SDimitry Andric     return false;
3160b57cec5SDimitry Andric 
317480093f4SDimitry Andric   // clear the m_found_calls, we'll rediscover it for this range.
318480093f4SDimitry Andric   m_found_calls = false;
319480093f4SDimitry Andric 
3200b57cec5SDimitry Andric   lldb::addr_t cur_addr = GetThread().GetRegisterContext()->GetPC();
3210b57cec5SDimitry Andric   // Find the current address in our address ranges, and fetch the disassembly
3220b57cec5SDimitry Andric   // if we haven't already:
3230b57cec5SDimitry Andric   size_t pc_index;
3240b57cec5SDimitry Andric   size_t range_index;
3250b57cec5SDimitry Andric   InstructionList *instructions =
3260b57cec5SDimitry Andric       GetInstructionsForAddress(cur_addr, range_index, pc_index);
3270b57cec5SDimitry Andric   if (instructions == nullptr)
3280b57cec5SDimitry Andric     return false;
3290b57cec5SDimitry Andric   else {
3300b57cec5SDimitry Andric     const bool ignore_calls = GetKind() == eKindStepOverRange;
331e8d8bef9SDimitry Andric     uint32_t branch_index = instructions->GetIndexOfNextBranchInstruction(
332e8d8bef9SDimitry Andric         pc_index, ignore_calls, &m_found_calls);
3330b57cec5SDimitry Andric     Address run_to_address;
3340b57cec5SDimitry Andric 
3350b57cec5SDimitry Andric     // If we didn't find a branch, run to the end of the range.
3360b57cec5SDimitry Andric     if (branch_index == UINT32_MAX) {
3370b57cec5SDimitry Andric       uint32_t last_index = instructions->GetSize() - 1;
3380b57cec5SDimitry Andric       if (last_index - pc_index > 1) {
3390b57cec5SDimitry Andric         InstructionSP last_inst =
3400b57cec5SDimitry Andric             instructions->GetInstructionAtIndex(last_index);
3410b57cec5SDimitry Andric         size_t last_inst_size = last_inst->GetOpcode().GetByteSize();
3420b57cec5SDimitry Andric         run_to_address = last_inst->GetAddress();
3430b57cec5SDimitry Andric         run_to_address.Slide(last_inst_size);
3440b57cec5SDimitry Andric       }
3450b57cec5SDimitry Andric     } else if (branch_index - pc_index > 1) {
3460b57cec5SDimitry Andric       run_to_address =
3470b57cec5SDimitry Andric           instructions->GetInstructionAtIndex(branch_index)->GetAddress();
3480b57cec5SDimitry Andric     }
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric     if (run_to_address.IsValid()) {
3510b57cec5SDimitry Andric       const bool is_internal = true;
3520b57cec5SDimitry Andric       m_next_branch_bp_sp =
3530b57cec5SDimitry Andric           GetTarget().CreateBreakpoint(run_to_address, is_internal, false);
3540b57cec5SDimitry Andric       if (m_next_branch_bp_sp) {
3550b57cec5SDimitry Andric 
3560b57cec5SDimitry Andric         if (m_next_branch_bp_sp->IsHardware() &&
3570b57cec5SDimitry Andric             !m_next_branch_bp_sp->HasResolvedLocations())
3580b57cec5SDimitry Andric           m_could_not_resolve_hw_bp = true;
3590b57cec5SDimitry Andric 
3600b57cec5SDimitry Andric         if (log) {
3610b57cec5SDimitry Andric           lldb::break_id_t bp_site_id = LLDB_INVALID_BREAK_ID;
3620b57cec5SDimitry Andric           BreakpointLocationSP bp_loc =
3630b57cec5SDimitry Andric               m_next_branch_bp_sp->GetLocationAtIndex(0);
3640b57cec5SDimitry Andric           if (bp_loc) {
3650b57cec5SDimitry Andric             BreakpointSiteSP bp_site = bp_loc->GetBreakpointSite();
3660b57cec5SDimitry Andric             if (bp_site) {
3670b57cec5SDimitry Andric               bp_site_id = bp_site->GetID();
3680b57cec5SDimitry Andric             }
3690b57cec5SDimitry Andric           }
3709dba64beSDimitry Andric           LLDB_LOGF(log,
3719dba64beSDimitry Andric                     "ThreadPlanStepRange::SetNextBranchBreakpoint - Setting "
3720b57cec5SDimitry Andric                     "breakpoint %d (site %d) to run to address 0x%" PRIx64,
3730b57cec5SDimitry Andric                     m_next_branch_bp_sp->GetID(), bp_site_id,
3745ffd83dbSDimitry Andric                     run_to_address.GetLoadAddress(&m_process.GetTarget()));
3750b57cec5SDimitry Andric         }
3760b57cec5SDimitry Andric 
3775ffd83dbSDimitry Andric         m_next_branch_bp_sp->SetThreadID(m_tid);
3780b57cec5SDimitry Andric         m_next_branch_bp_sp->SetBreakpointKind("next-branch-location");
3790b57cec5SDimitry Andric 
3800b57cec5SDimitry Andric         return true;
3810b57cec5SDimitry Andric       } else
3820b57cec5SDimitry Andric         return false;
3830b57cec5SDimitry Andric     }
3840b57cec5SDimitry Andric   }
3850b57cec5SDimitry Andric   return false;
3860b57cec5SDimitry Andric }
3870b57cec5SDimitry Andric 
NextRangeBreakpointExplainsStop(lldb::StopInfoSP stop_info_sp)3880b57cec5SDimitry Andric bool ThreadPlanStepRange::NextRangeBreakpointExplainsStop(
3890b57cec5SDimitry Andric     lldb::StopInfoSP stop_info_sp) {
39081ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
3910b57cec5SDimitry Andric   if (!m_next_branch_bp_sp)
3920b57cec5SDimitry Andric     return false;
3930b57cec5SDimitry Andric 
3940b57cec5SDimitry Andric   break_id_t bp_site_id = stop_info_sp->GetValue();
3950b57cec5SDimitry Andric   BreakpointSiteSP bp_site_sp =
3965ffd83dbSDimitry Andric       m_process.GetBreakpointSiteList().FindByID(bp_site_id);
3970b57cec5SDimitry Andric   if (!bp_site_sp)
3980b57cec5SDimitry Andric     return false;
3990b57cec5SDimitry Andric   else if (!bp_site_sp->IsBreakpointAtThisSite(m_next_branch_bp_sp->GetID()))
4000b57cec5SDimitry Andric     return false;
4010b57cec5SDimitry Andric   else {
4020b57cec5SDimitry Andric     // If we've hit the next branch breakpoint, then clear it.
403c9157d92SDimitry Andric     size_t num_constituents = bp_site_sp->GetNumberOfConstituents();
4040b57cec5SDimitry Andric     bool explains_stop = true;
405c9157d92SDimitry Andric     // If all the constituents are internal, then we are probably just stepping
406c9157d92SDimitry Andric     // over this range from multiple threads, or multiple frames, so we want to
4070b57cec5SDimitry Andric     // continue.  If one is not internal, then we should not explain the stop,
4080b57cec5SDimitry Andric     // and let the user breakpoint handle the stop.
409c9157d92SDimitry Andric     for (size_t i = 0; i < num_constituents; i++) {
410c9157d92SDimitry Andric       if (!bp_site_sp->GetConstituentAtIndex(i)->GetBreakpoint().IsInternal()) {
4110b57cec5SDimitry Andric         explains_stop = false;
4120b57cec5SDimitry Andric         break;
4130b57cec5SDimitry Andric       }
4140b57cec5SDimitry Andric     }
4159dba64beSDimitry Andric     LLDB_LOGF(log,
4169dba64beSDimitry Andric               "ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit "
4170b57cec5SDimitry Andric               "next range breakpoint which has %" PRIu64
418c9157d92SDimitry Andric               " constituents - explains stop: %u.",
419c9157d92SDimitry Andric               (uint64_t)num_constituents, explains_stop);
4200b57cec5SDimitry Andric     ClearNextBranchBreakpoint();
4210b57cec5SDimitry Andric     return explains_stop;
4220b57cec5SDimitry Andric   }
4230b57cec5SDimitry Andric }
4240b57cec5SDimitry Andric 
WillStop()4250b57cec5SDimitry Andric bool ThreadPlanStepRange::WillStop() { return true; }
4260b57cec5SDimitry Andric 
GetPlanRunState()4270b57cec5SDimitry Andric StateType ThreadPlanStepRange::GetPlanRunState() {
4280b57cec5SDimitry Andric   if (m_next_branch_bp_sp)
4290b57cec5SDimitry Andric     return eStateRunning;
4300b57cec5SDimitry Andric   else
4310b57cec5SDimitry Andric     return eStateStepping;
4320b57cec5SDimitry Andric }
4330b57cec5SDimitry Andric 
MischiefManaged()4340b57cec5SDimitry Andric bool ThreadPlanStepRange::MischiefManaged() {
4350b57cec5SDimitry Andric   // If we have pushed some plans between ShouldStop & MischiefManaged, then
4360b57cec5SDimitry Andric   // we're not done...
4370b57cec5SDimitry Andric   // I do this check first because we might have stepped somewhere that will
4380b57cec5SDimitry Andric   // fool InRange into
4390b57cec5SDimitry Andric   // thinking it needs to step past the end of that line.  This happens, for
4400b57cec5SDimitry Andric   // instance, when stepping over inlined code that is in the middle of the
4410b57cec5SDimitry Andric   // current line.
4420b57cec5SDimitry Andric 
4430b57cec5SDimitry Andric   if (!m_no_more_plans)
4440b57cec5SDimitry Andric     return false;
4450b57cec5SDimitry Andric 
4460b57cec5SDimitry Andric   bool done = true;
4470b57cec5SDimitry Andric   if (!IsPlanComplete()) {
4480b57cec5SDimitry Andric     if (InRange()) {
4490b57cec5SDimitry Andric       done = false;
4500b57cec5SDimitry Andric     } else {
4510b57cec5SDimitry Andric       FrameComparison frame_order = CompareCurrentFrameToStartFrame();
4520b57cec5SDimitry Andric       done = (frame_order != eFrameCompareOlder) ? m_no_more_plans : true;
4530b57cec5SDimitry Andric     }
4540b57cec5SDimitry Andric   }
4550b57cec5SDimitry Andric 
4560b57cec5SDimitry Andric   if (done) {
45781ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Step);
4589dba64beSDimitry Andric     LLDB_LOGF(log, "Completed step through range plan.");
4590b57cec5SDimitry Andric     ClearNextBranchBreakpoint();
4600b57cec5SDimitry Andric     ThreadPlan::MischiefManaged();
4610b57cec5SDimitry Andric     return true;
4620b57cec5SDimitry Andric   } else {
4630b57cec5SDimitry Andric     return false;
4640b57cec5SDimitry Andric   }
4650b57cec5SDimitry Andric }
4660b57cec5SDimitry Andric 
IsPlanStale()4670b57cec5SDimitry Andric bool ThreadPlanStepRange::IsPlanStale() {
46881ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
4690b57cec5SDimitry Andric   FrameComparison frame_order = CompareCurrentFrameToStartFrame();
4700b57cec5SDimitry Andric 
4710b57cec5SDimitry Andric   if (frame_order == eFrameCompareOlder) {
4720b57cec5SDimitry Andric     if (log) {
4739dba64beSDimitry Andric       LLDB_LOGF(log, "ThreadPlanStepRange::IsPlanStale returning true, we've "
4740b57cec5SDimitry Andric                      "stepped out.");
4750b57cec5SDimitry Andric     }
4760b57cec5SDimitry Andric     return true;
4770b57cec5SDimitry Andric   } else if (frame_order == eFrameCompareEqual && InSymbol()) {
4780b57cec5SDimitry Andric     // If we are not in a place we should step through, we've gotten stale. One
4790b57cec5SDimitry Andric     // tricky bit here is that some stubs don't push a frame, so we should.
4800b57cec5SDimitry Andric     // check that we are in the same symbol.
4810b57cec5SDimitry Andric     if (!InRange()) {
4820b57cec5SDimitry Andric       // Set plan Complete when we reach next instruction just after the range
4835ffd83dbSDimitry Andric       lldb::addr_t addr = GetThread().GetRegisterContext()->GetPC() - 1;
4840b57cec5SDimitry Andric       size_t num_ranges = m_address_ranges.size();
4850b57cec5SDimitry Andric       for (size_t i = 0; i < num_ranges; i++) {
4865ffd83dbSDimitry Andric         bool in_range =
4875ffd83dbSDimitry Andric             m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget());
4880b57cec5SDimitry Andric         if (in_range) {
4890b57cec5SDimitry Andric           SetPlanComplete();
4900b57cec5SDimitry Andric         }
4910b57cec5SDimitry Andric       }
4920b57cec5SDimitry Andric       return true;
4930b57cec5SDimitry Andric     }
4940b57cec5SDimitry Andric   }
4950b57cec5SDimitry Andric   return false;
4960b57cec5SDimitry Andric }
497