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"
220b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
230b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric using namespace lldb;
260b57cec5SDimitry Andric using namespace lldb_private;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric // ThreadPlanStepRange: Step through a stack range, either stepping over or
290b57cec5SDimitry Andric // into based on the value of \a type.
300b57cec5SDimitry Andric 
ThreadPlanStepRange(ThreadPlanKind kind,const char * name,Thread & thread,const AddressRange & range,const SymbolContext & addr_context,lldb::RunMode stop_others,bool given_ranges_only)310b57cec5SDimitry Andric ThreadPlanStepRange::ThreadPlanStepRange(ThreadPlanKind kind, const char *name,
320b57cec5SDimitry Andric                                          Thread &thread,
330b57cec5SDimitry Andric                                          const AddressRange &range,
340b57cec5SDimitry Andric                                          const SymbolContext &addr_context,
350b57cec5SDimitry Andric                                          lldb::RunMode stop_others,
360b57cec5SDimitry Andric                                          bool given_ranges_only)
370b57cec5SDimitry Andric     : ThreadPlan(kind, name, thread, eVoteNoOpinion, eVoteNoOpinion),
380b57cec5SDimitry Andric       m_addr_context(addr_context), m_address_ranges(),
390b57cec5SDimitry Andric       m_stop_others(stop_others), m_stack_id(), m_parent_stack_id(),
400b57cec5SDimitry Andric       m_no_more_plans(false), m_first_run_event(true), m_use_fast_step(false),
410b57cec5SDimitry Andric       m_given_ranges_only(given_ranges_only) {
420b57cec5SDimitry Andric   m_use_fast_step = GetTarget().GetUseFastStepping();
430b57cec5SDimitry Andric   AddRange(range);
445ffd83dbSDimitry Andric   m_stack_id = thread.GetStackFrameAtIndex(0)->GetStackID();
455ffd83dbSDimitry Andric   StackFrameSP parent_stack = thread.GetStackFrameAtIndex(1);
460b57cec5SDimitry Andric   if (parent_stack)
470b57cec5SDimitry Andric     m_parent_stack_id = parent_stack->GetStackID();
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric 
~ThreadPlanStepRange()500b57cec5SDimitry Andric ThreadPlanStepRange::~ThreadPlanStepRange() { ClearNextBranchBreakpoint(); }
510b57cec5SDimitry Andric 
DidPush()520b57cec5SDimitry Andric void ThreadPlanStepRange::DidPush() {
530b57cec5SDimitry Andric   // See if we can find a "next range" breakpoint:
540b57cec5SDimitry Andric   SetNextBranchBreakpoint();
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric 
ValidatePlan(Stream * error)570b57cec5SDimitry Andric bool ThreadPlanStepRange::ValidatePlan(Stream *error) {
580b57cec5SDimitry Andric   if (m_could_not_resolve_hw_bp) {
590b57cec5SDimitry Andric     if (error)
600b57cec5SDimitry Andric       error->PutCString(
610b57cec5SDimitry Andric           "Could not create hardware breakpoint for thread plan.");
620b57cec5SDimitry Andric     return false;
630b57cec5SDimitry Andric   }
640b57cec5SDimitry Andric   return true;
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric 
ShouldReportStop(Event * event_ptr)670b57cec5SDimitry Andric Vote ThreadPlanStepRange::ShouldReportStop(Event *event_ptr) {
680b57cec5SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric   const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo;
719dba64beSDimitry Andric   LLDB_LOGF(log, "ThreadPlanStepRange::ShouldReportStop() returning vote %i\n",
720b57cec5SDimitry Andric             vote);
730b57cec5SDimitry Andric   return vote;
740b57cec5SDimitry Andric }
750b57cec5SDimitry Andric 
AddRange(const AddressRange & new_range)760b57cec5SDimitry Andric void ThreadPlanStepRange::AddRange(const AddressRange &new_range) {
770b57cec5SDimitry Andric   // For now I'm just adding the ranges.  At some point we may want to condense
780b57cec5SDimitry Andric   // the ranges if they overlap, though I don't think it is likely to be very
790b57cec5SDimitry Andric   // important.
800b57cec5SDimitry Andric   m_address_ranges.push_back(new_range);
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   // Fill the slot for this address range with an empty DisassemblerSP in the
830b57cec5SDimitry Andric   // instruction ranges. I want the indices to match, but I don't want to do
840b57cec5SDimitry Andric   // the work to disassemble this range if I don't step into it.
850b57cec5SDimitry Andric   m_instruction_ranges.push_back(DisassemblerSP());
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric 
DumpRanges(Stream * s)880b57cec5SDimitry Andric void ThreadPlanStepRange::DumpRanges(Stream *s) {
890b57cec5SDimitry Andric   size_t num_ranges = m_address_ranges.size();
900b57cec5SDimitry Andric   if (num_ranges == 1) {
915ffd83dbSDimitry Andric     m_address_ranges[0].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress);
920b57cec5SDimitry Andric   } else {
930b57cec5SDimitry Andric     for (size_t i = 0; i < num_ranges; i++) {
940b57cec5SDimitry Andric       s->Printf(" %" PRIu64 ": ", uint64_t(i));
955ffd83dbSDimitry Andric       m_address_ranges[i].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress);
960b57cec5SDimitry Andric     }
970b57cec5SDimitry Andric   }
980b57cec5SDimitry Andric }
990b57cec5SDimitry Andric 
InRange()1000b57cec5SDimitry Andric bool ThreadPlanStepRange::InRange() {
1010b57cec5SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
1020b57cec5SDimitry Andric   bool ret_value = false;
1035ffd83dbSDimitry Andric   Thread &thread = GetThread();
1045ffd83dbSDimitry Andric   lldb::addr_t pc_load_addr = thread.GetRegisterContext()->GetPC();
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   size_t num_ranges = m_address_ranges.size();
1070b57cec5SDimitry Andric   for (size_t i = 0; i < num_ranges; i++) {
1085ffd83dbSDimitry Andric     ret_value =
1095ffd83dbSDimitry Andric         m_address_ranges[i].ContainsLoadAddress(pc_load_addr, &GetTarget());
1100b57cec5SDimitry Andric     if (ret_value)
1110b57cec5SDimitry Andric       break;
1120b57cec5SDimitry Andric   }
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   if (!ret_value && !m_given_ranges_only) {
1150b57cec5SDimitry Andric     // See if we've just stepped to another part of the same line number...
1165ffd83dbSDimitry Andric     StackFrame *frame = thread.GetStackFrameAtIndex(0).get();
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric     SymbolContext new_context(
1190b57cec5SDimitry Andric         frame->GetSymbolContext(eSymbolContextEverything));
1200b57cec5SDimitry Andric     if (m_addr_context.line_entry.IsValid() &&
1210b57cec5SDimitry Andric         new_context.line_entry.IsValid()) {
1220b57cec5SDimitry Andric       if (m_addr_context.line_entry.original_file ==
1230b57cec5SDimitry Andric           new_context.line_entry.original_file) {
1240b57cec5SDimitry Andric         if (m_addr_context.line_entry.line == new_context.line_entry.line) {
1250b57cec5SDimitry Andric           m_addr_context = new_context;
1260b57cec5SDimitry Andric           const bool include_inlined_functions =
1270b57cec5SDimitry Andric               GetKind() == eKindStepOverRange;
1280b57cec5SDimitry Andric           AddRange(m_addr_context.line_entry.GetSameLineContiguousAddressRange(
1290b57cec5SDimitry Andric               include_inlined_functions));
1300b57cec5SDimitry Andric           ret_value = true;
1310b57cec5SDimitry Andric           if (log) {
1320b57cec5SDimitry Andric             StreamString s;
1335ffd83dbSDimitry Andric             m_addr_context.line_entry.Dump(&s, &GetTarget(), true,
1345ffd83dbSDimitry Andric                                            Address::DumpStyleLoadAddress,
1350b57cec5SDimitry Andric                                            Address::DumpStyleLoadAddress, true);
1360b57cec5SDimitry Andric 
1379dba64beSDimitry Andric             LLDB_LOGF(
1389dba64beSDimitry Andric                 log,
1390b57cec5SDimitry Andric                 "Step range plan stepped to another range of same line: %s",
1400b57cec5SDimitry Andric                 s.GetData());
1410b57cec5SDimitry Andric           }
1420b57cec5SDimitry Andric         } else if (new_context.line_entry.line == 0) {
1430b57cec5SDimitry Andric           new_context.line_entry.line = m_addr_context.line_entry.line;
1440b57cec5SDimitry Andric           m_addr_context = new_context;
1450b57cec5SDimitry Andric           const bool include_inlined_functions =
1460b57cec5SDimitry Andric               GetKind() == eKindStepOverRange;
1470b57cec5SDimitry Andric           AddRange(m_addr_context.line_entry.GetSameLineContiguousAddressRange(
1480b57cec5SDimitry Andric               include_inlined_functions));
1490b57cec5SDimitry Andric           ret_value = true;
1500b57cec5SDimitry Andric           if (log) {
1510b57cec5SDimitry Andric             StreamString s;
1525ffd83dbSDimitry Andric             m_addr_context.line_entry.Dump(&s, &GetTarget(), true,
1535ffd83dbSDimitry Andric                                            Address::DumpStyleLoadAddress,
1540b57cec5SDimitry Andric                                            Address::DumpStyleLoadAddress, true);
1550b57cec5SDimitry Andric 
1569dba64beSDimitry Andric             LLDB_LOGF(log,
1579dba64beSDimitry Andric                       "Step range plan stepped to a range at linenumber 0 "
1580b57cec5SDimitry Andric                       "stepping through that range: %s",
1590b57cec5SDimitry Andric                       s.GetData());
1600b57cec5SDimitry Andric           }
1610b57cec5SDimitry Andric         } else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(
1625ffd83dbSDimitry Andric                        &GetTarget()) != pc_load_addr) {
1630b57cec5SDimitry Andric           // Another thing that sometimes happens here is that we step out of
1640b57cec5SDimitry Andric           // one line into the MIDDLE of another line.  So far I mostly see
1650b57cec5SDimitry Andric           // this due to bugs in the debug information. But we probably don't
1660b57cec5SDimitry Andric           // want to be in the middle of a line range, so in that case reset
1670b57cec5SDimitry Andric           // the stepping range to the line we've stepped into the middle of
1680b57cec5SDimitry Andric           // and continue.
1690b57cec5SDimitry Andric           m_addr_context = new_context;
1700b57cec5SDimitry Andric           m_address_ranges.clear();
1710b57cec5SDimitry Andric           AddRange(m_addr_context.line_entry.range);
1720b57cec5SDimitry Andric           ret_value = true;
1730b57cec5SDimitry Andric           if (log) {
1740b57cec5SDimitry Andric             StreamString s;
1755ffd83dbSDimitry Andric             m_addr_context.line_entry.Dump(&s, &GetTarget(), true,
1765ffd83dbSDimitry Andric                                            Address::DumpStyleLoadAddress,
1770b57cec5SDimitry Andric                                            Address::DumpStyleLoadAddress, true);
1780b57cec5SDimitry Andric 
1799dba64beSDimitry Andric             LLDB_LOGF(log,
1809dba64beSDimitry Andric                       "Step range plan stepped to the middle of new "
1810b57cec5SDimitry Andric                       "line(%d): %s, continuing to clear this line.",
1820b57cec5SDimitry Andric                       new_context.line_entry.line, s.GetData());
1830b57cec5SDimitry Andric           }
1840b57cec5SDimitry Andric         }
1850b57cec5SDimitry Andric       }
1860b57cec5SDimitry Andric     }
1870b57cec5SDimitry Andric   }
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric   if (!ret_value && log)
1909dba64beSDimitry Andric     LLDB_LOGF(log, "Step range plan out of range to 0x%" PRIx64, pc_load_addr);
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric   return ret_value;
1930b57cec5SDimitry Andric }
1940b57cec5SDimitry Andric 
InSymbol()1950b57cec5SDimitry Andric bool ThreadPlanStepRange::InSymbol() {
1965ffd83dbSDimitry Andric   lldb::addr_t cur_pc = GetThread().GetRegisterContext()->GetPC();
1970b57cec5SDimitry Andric   if (m_addr_context.function != nullptr) {
1980b57cec5SDimitry Andric     return m_addr_context.function->GetAddressRange().ContainsLoadAddress(
1995ffd83dbSDimitry Andric         cur_pc, &GetTarget());
2000b57cec5SDimitry Andric   } else if (m_addr_context.symbol && m_addr_context.symbol->ValueIsAddress()) {
2010b57cec5SDimitry Andric     AddressRange range(m_addr_context.symbol->GetAddressRef(),
2020b57cec5SDimitry Andric                        m_addr_context.symbol->GetByteSize());
2035ffd83dbSDimitry Andric     return range.ContainsLoadAddress(cur_pc, &GetTarget());
2040b57cec5SDimitry Andric   }
2050b57cec5SDimitry Andric   return false;
2060b57cec5SDimitry Andric }
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric // FIXME: This should also handle inlining if we aren't going to do inlining in
2090b57cec5SDimitry Andric // the
2100b57cec5SDimitry Andric // main stack.
2110b57cec5SDimitry Andric //
2120b57cec5SDimitry Andric // Ideally we should remember the whole stack frame list, and then compare that
2130b57cec5SDimitry Andric // to the current list.
2140b57cec5SDimitry Andric 
CompareCurrentFrameToStartFrame()2150b57cec5SDimitry Andric lldb::FrameComparison ThreadPlanStepRange::CompareCurrentFrameToStartFrame() {
2160b57cec5SDimitry Andric   FrameComparison frame_order;
2175ffd83dbSDimitry Andric   Thread &thread = GetThread();
2185ffd83dbSDimitry Andric   StackID cur_frame_id = thread.GetStackFrameAtIndex(0)->GetStackID();
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric   if (cur_frame_id == m_stack_id) {
2210b57cec5SDimitry Andric     frame_order = eFrameCompareEqual;
2220b57cec5SDimitry Andric   } else if (cur_frame_id < m_stack_id) {
2230b57cec5SDimitry Andric     frame_order = eFrameCompareYounger;
2240b57cec5SDimitry Andric   } else {
2255ffd83dbSDimitry Andric     StackFrameSP cur_parent_frame = thread.GetStackFrameAtIndex(1);
2260b57cec5SDimitry Andric     StackID cur_parent_id;
2270b57cec5SDimitry Andric     if (cur_parent_frame)
2280b57cec5SDimitry Andric       cur_parent_id = cur_parent_frame->GetStackID();
2290b57cec5SDimitry Andric     if (m_parent_stack_id.IsValid() && cur_parent_id.IsValid() &&
2300b57cec5SDimitry Andric         m_parent_stack_id == cur_parent_id)
2310b57cec5SDimitry Andric       frame_order = eFrameCompareSameParent;
2320b57cec5SDimitry Andric     else
2330b57cec5SDimitry Andric       frame_order = eFrameCompareOlder;
2340b57cec5SDimitry Andric   }
2350b57cec5SDimitry Andric   return frame_order;
2360b57cec5SDimitry Andric }
2370b57cec5SDimitry Andric 
StopOthers()2380b57cec5SDimitry Andric bool ThreadPlanStepRange::StopOthers() {
239480093f4SDimitry Andric   switch (m_stop_others) {
240480093f4SDimitry Andric   case lldb::eOnlyThisThread:
241480093f4SDimitry Andric     return true;
242480093f4SDimitry Andric   case lldb::eOnlyDuringStepping:
243480093f4SDimitry Andric     // If there is a call in the range of the next branch breakpoint,
244480093f4SDimitry Andric     // then we should always run all threads, since a call can execute
245480093f4SDimitry Andric     // arbitrary code which might for instance take a lock that's held
246480093f4SDimitry Andric     // by another thread.
247480093f4SDimitry Andric     return !m_found_calls;
248480093f4SDimitry Andric   case lldb::eAllThreads:
249480093f4SDimitry Andric     return false;
250480093f4SDimitry Andric   }
251480093f4SDimitry Andric   llvm_unreachable("Unhandled run mode!");
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric 
GetInstructionsForAddress(lldb::addr_t addr,size_t & range_index,size_t & insn_offset)2540b57cec5SDimitry Andric InstructionList *ThreadPlanStepRange::GetInstructionsForAddress(
2550b57cec5SDimitry Andric     lldb::addr_t addr, size_t &range_index, size_t &insn_offset) {
2560b57cec5SDimitry Andric   size_t num_ranges = m_address_ranges.size();
2570b57cec5SDimitry Andric   for (size_t i = 0; i < num_ranges; i++) {
2580b57cec5SDimitry Andric     if (m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget())) {
2590b57cec5SDimitry Andric       // Some joker added a zero size range to the stepping range...
2600b57cec5SDimitry Andric       if (m_address_ranges[i].GetByteSize() == 0)
2610b57cec5SDimitry Andric         return nullptr;
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric       if (!m_instruction_ranges[i]) {
2640b57cec5SDimitry Andric         // Disassemble the address range given:
2650b57cec5SDimitry Andric         const char *plugin_name = nullptr;
2660b57cec5SDimitry Andric         const char *flavor = nullptr;
2670b57cec5SDimitry Andric         m_instruction_ranges[i] = Disassembler::DisassembleRange(
2685ffd83dbSDimitry Andric             GetTarget().GetArchitecture(), plugin_name, flavor, GetTarget(),
269*5f7ddb14SDimitry Andric             m_address_ranges[i]);
2700b57cec5SDimitry Andric       }
2710b57cec5SDimitry Andric       if (!m_instruction_ranges[i])
2720b57cec5SDimitry Andric         return nullptr;
2730b57cec5SDimitry Andric       else {
2740b57cec5SDimitry Andric         // Find where we are in the instruction list as well.  If we aren't at
2750b57cec5SDimitry Andric         // an instruction, return nullptr. In this case, we're probably lost,
2760b57cec5SDimitry Andric         // and shouldn't try to do anything fancy.
2770b57cec5SDimitry Andric 
2780b57cec5SDimitry Andric         insn_offset =
2790b57cec5SDimitry Andric             m_instruction_ranges[i]
2800b57cec5SDimitry Andric                 ->GetInstructionList()
2810b57cec5SDimitry Andric                 .GetIndexOfInstructionAtLoadAddress(addr, GetTarget());
2820b57cec5SDimitry Andric         if (insn_offset == UINT32_MAX)
2830b57cec5SDimitry Andric           return nullptr;
2840b57cec5SDimitry Andric         else {
2850b57cec5SDimitry Andric           range_index = i;
2860b57cec5SDimitry Andric           return &m_instruction_ranges[i]->GetInstructionList();
2870b57cec5SDimitry Andric         }
2880b57cec5SDimitry Andric       }
2890b57cec5SDimitry Andric     }
2900b57cec5SDimitry Andric   }
2910b57cec5SDimitry Andric   return nullptr;
2920b57cec5SDimitry Andric }
2930b57cec5SDimitry Andric 
ClearNextBranchBreakpoint()2940b57cec5SDimitry Andric void ThreadPlanStepRange::ClearNextBranchBreakpoint() {
2950b57cec5SDimitry Andric   if (m_next_branch_bp_sp) {
2960b57cec5SDimitry Andric     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
2979dba64beSDimitry Andric     LLDB_LOGF(log, "Removing next branch breakpoint: %d.",
2980b57cec5SDimitry Andric               m_next_branch_bp_sp->GetID());
2990b57cec5SDimitry Andric     GetTarget().RemoveBreakpointByID(m_next_branch_bp_sp->GetID());
3000b57cec5SDimitry Andric     m_next_branch_bp_sp.reset();
3010b57cec5SDimitry Andric     m_could_not_resolve_hw_bp = false;
302480093f4SDimitry Andric     m_found_calls = false;
3030b57cec5SDimitry Andric   }
3040b57cec5SDimitry Andric }
3050b57cec5SDimitry Andric 
SetNextBranchBreakpoint()3060b57cec5SDimitry Andric bool ThreadPlanStepRange::SetNextBranchBreakpoint() {
3070b57cec5SDimitry Andric   if (m_next_branch_bp_sp)
3080b57cec5SDimitry Andric     return true;
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
3110b57cec5SDimitry Andric   // Stepping through ranges using breakpoints doesn't work yet, but with this
3120b57cec5SDimitry Andric   // off we fall back to instruction single stepping.
3130b57cec5SDimitry Andric   if (!m_use_fast_step)
3140b57cec5SDimitry Andric     return false;
3150b57cec5SDimitry Andric 
316480093f4SDimitry Andric   // clear the m_found_calls, we'll rediscover it for this range.
317480093f4SDimitry Andric   m_found_calls = false;
318480093f4SDimitry Andric 
3190b57cec5SDimitry Andric   lldb::addr_t cur_addr = GetThread().GetRegisterContext()->GetPC();
3200b57cec5SDimitry Andric   // Find the current address in our address ranges, and fetch the disassembly
3210b57cec5SDimitry Andric   // if we haven't already:
3220b57cec5SDimitry Andric   size_t pc_index;
3230b57cec5SDimitry Andric   size_t range_index;
3240b57cec5SDimitry Andric   InstructionList *instructions =
3250b57cec5SDimitry Andric       GetInstructionsForAddress(cur_addr, range_index, pc_index);
3260b57cec5SDimitry Andric   if (instructions == nullptr)
3270b57cec5SDimitry Andric     return false;
3280b57cec5SDimitry Andric   else {
3290b57cec5SDimitry Andric     const bool ignore_calls = GetKind() == eKindStepOverRange;
330af732203SDimitry Andric     uint32_t branch_index = instructions->GetIndexOfNextBranchInstruction(
331af732203SDimitry Andric         pc_index, ignore_calls, &m_found_calls);
3320b57cec5SDimitry Andric     Address run_to_address;
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric     // If we didn't find a branch, run to the end of the range.
3350b57cec5SDimitry Andric     if (branch_index == UINT32_MAX) {
3360b57cec5SDimitry Andric       uint32_t last_index = instructions->GetSize() - 1;
3370b57cec5SDimitry Andric       if (last_index - pc_index > 1) {
3380b57cec5SDimitry Andric         InstructionSP last_inst =
3390b57cec5SDimitry Andric             instructions->GetInstructionAtIndex(last_index);
3400b57cec5SDimitry Andric         size_t last_inst_size = last_inst->GetOpcode().GetByteSize();
3410b57cec5SDimitry Andric         run_to_address = last_inst->GetAddress();
3420b57cec5SDimitry Andric         run_to_address.Slide(last_inst_size);
3430b57cec5SDimitry Andric       }
3440b57cec5SDimitry Andric     } else if (branch_index - pc_index > 1) {
3450b57cec5SDimitry Andric       run_to_address =
3460b57cec5SDimitry Andric           instructions->GetInstructionAtIndex(branch_index)->GetAddress();
3470b57cec5SDimitry Andric     }
3480b57cec5SDimitry Andric 
3490b57cec5SDimitry Andric     if (run_to_address.IsValid()) {
3500b57cec5SDimitry Andric       const bool is_internal = true;
3510b57cec5SDimitry Andric       m_next_branch_bp_sp =
3520b57cec5SDimitry Andric           GetTarget().CreateBreakpoint(run_to_address, is_internal, false);
3530b57cec5SDimitry Andric       if (m_next_branch_bp_sp) {
3540b57cec5SDimitry Andric 
3550b57cec5SDimitry Andric         if (m_next_branch_bp_sp->IsHardware() &&
3560b57cec5SDimitry Andric             !m_next_branch_bp_sp->HasResolvedLocations())
3570b57cec5SDimitry Andric           m_could_not_resolve_hw_bp = true;
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric         if (log) {
3600b57cec5SDimitry Andric           lldb::break_id_t bp_site_id = LLDB_INVALID_BREAK_ID;
3610b57cec5SDimitry Andric           BreakpointLocationSP bp_loc =
3620b57cec5SDimitry Andric               m_next_branch_bp_sp->GetLocationAtIndex(0);
3630b57cec5SDimitry Andric           if (bp_loc) {
3640b57cec5SDimitry Andric             BreakpointSiteSP bp_site = bp_loc->GetBreakpointSite();
3650b57cec5SDimitry Andric             if (bp_site) {
3660b57cec5SDimitry Andric               bp_site_id = bp_site->GetID();
3670b57cec5SDimitry Andric             }
3680b57cec5SDimitry Andric           }
3699dba64beSDimitry Andric           LLDB_LOGF(log,
3709dba64beSDimitry Andric                     "ThreadPlanStepRange::SetNextBranchBreakpoint - Setting "
3710b57cec5SDimitry Andric                     "breakpoint %d (site %d) to run to address 0x%" PRIx64,
3720b57cec5SDimitry Andric                     m_next_branch_bp_sp->GetID(), bp_site_id,
3735ffd83dbSDimitry Andric                     run_to_address.GetLoadAddress(&m_process.GetTarget()));
3740b57cec5SDimitry Andric         }
3750b57cec5SDimitry Andric 
3765ffd83dbSDimitry Andric         m_next_branch_bp_sp->SetThreadID(m_tid);
3770b57cec5SDimitry Andric         m_next_branch_bp_sp->SetBreakpointKind("next-branch-location");
3780b57cec5SDimitry Andric 
3790b57cec5SDimitry Andric         return true;
3800b57cec5SDimitry Andric       } else
3810b57cec5SDimitry Andric         return false;
3820b57cec5SDimitry Andric     }
3830b57cec5SDimitry Andric   }
3840b57cec5SDimitry Andric   return false;
3850b57cec5SDimitry Andric }
3860b57cec5SDimitry Andric 
NextRangeBreakpointExplainsStop(lldb::StopInfoSP stop_info_sp)3870b57cec5SDimitry Andric bool ThreadPlanStepRange::NextRangeBreakpointExplainsStop(
3880b57cec5SDimitry Andric     lldb::StopInfoSP stop_info_sp) {
3890b57cec5SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
3900b57cec5SDimitry Andric   if (!m_next_branch_bp_sp)
3910b57cec5SDimitry Andric     return false;
3920b57cec5SDimitry Andric 
3930b57cec5SDimitry Andric   break_id_t bp_site_id = stop_info_sp->GetValue();
3940b57cec5SDimitry Andric   BreakpointSiteSP bp_site_sp =
3955ffd83dbSDimitry Andric       m_process.GetBreakpointSiteList().FindByID(bp_site_id);
3960b57cec5SDimitry Andric   if (!bp_site_sp)
3970b57cec5SDimitry Andric     return false;
3980b57cec5SDimitry Andric   else if (!bp_site_sp->IsBreakpointAtThisSite(m_next_branch_bp_sp->GetID()))
3990b57cec5SDimitry Andric     return false;
4000b57cec5SDimitry Andric   else {
4010b57cec5SDimitry Andric     // If we've hit the next branch breakpoint, then clear it.
4020b57cec5SDimitry Andric     size_t num_owners = bp_site_sp->GetNumberOfOwners();
4030b57cec5SDimitry Andric     bool explains_stop = true;
4040b57cec5SDimitry Andric     // If all the owners are internal, then we are probably just stepping over
4050b57cec5SDimitry Andric     // this range from multiple threads, or multiple frames, so we want to
4060b57cec5SDimitry Andric     // continue.  If one is not internal, then we should not explain the stop,
4070b57cec5SDimitry Andric     // and let the user breakpoint handle the stop.
4080b57cec5SDimitry Andric     for (size_t i = 0; i < num_owners; i++) {
4090b57cec5SDimitry Andric       if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal()) {
4100b57cec5SDimitry Andric         explains_stop = false;
4110b57cec5SDimitry Andric         break;
4120b57cec5SDimitry Andric       }
4130b57cec5SDimitry Andric     }
4149dba64beSDimitry Andric     LLDB_LOGF(log,
4159dba64beSDimitry Andric               "ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit "
4160b57cec5SDimitry Andric               "next range breakpoint which has %" PRIu64
4170b57cec5SDimitry Andric               " owners - explains stop: %u.",
4180b57cec5SDimitry Andric               (uint64_t)num_owners, explains_stop);
4190b57cec5SDimitry Andric     ClearNextBranchBreakpoint();
4200b57cec5SDimitry Andric     return explains_stop;
4210b57cec5SDimitry Andric   }
4220b57cec5SDimitry Andric }
4230b57cec5SDimitry Andric 
WillStop()4240b57cec5SDimitry Andric bool ThreadPlanStepRange::WillStop() { return true; }
4250b57cec5SDimitry Andric 
GetPlanRunState()4260b57cec5SDimitry Andric StateType ThreadPlanStepRange::GetPlanRunState() {
4270b57cec5SDimitry Andric   if (m_next_branch_bp_sp)
4280b57cec5SDimitry Andric     return eStateRunning;
4290b57cec5SDimitry Andric   else
4300b57cec5SDimitry Andric     return eStateStepping;
4310b57cec5SDimitry Andric }
4320b57cec5SDimitry Andric 
MischiefManaged()4330b57cec5SDimitry Andric bool ThreadPlanStepRange::MischiefManaged() {
4340b57cec5SDimitry Andric   // If we have pushed some plans between ShouldStop & MischiefManaged, then
4350b57cec5SDimitry Andric   // we're not done...
4360b57cec5SDimitry Andric   // I do this check first because we might have stepped somewhere that will
4370b57cec5SDimitry Andric   // fool InRange into
4380b57cec5SDimitry Andric   // thinking it needs to step past the end of that line.  This happens, for
4390b57cec5SDimitry Andric   // instance, when stepping over inlined code that is in the middle of the
4400b57cec5SDimitry Andric   // current line.
4410b57cec5SDimitry Andric 
4420b57cec5SDimitry Andric   if (!m_no_more_plans)
4430b57cec5SDimitry Andric     return false;
4440b57cec5SDimitry Andric 
4450b57cec5SDimitry Andric   bool done = true;
4460b57cec5SDimitry Andric   if (!IsPlanComplete()) {
4470b57cec5SDimitry Andric     if (InRange()) {
4480b57cec5SDimitry Andric       done = false;
4490b57cec5SDimitry Andric     } else {
4500b57cec5SDimitry Andric       FrameComparison frame_order = CompareCurrentFrameToStartFrame();
4510b57cec5SDimitry Andric       done = (frame_order != eFrameCompareOlder) ? m_no_more_plans : true;
4520b57cec5SDimitry Andric     }
4530b57cec5SDimitry Andric   }
4540b57cec5SDimitry Andric 
4550b57cec5SDimitry Andric   if (done) {
4560b57cec5SDimitry Andric     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
4579dba64beSDimitry Andric     LLDB_LOGF(log, "Completed step through range plan.");
4580b57cec5SDimitry Andric     ClearNextBranchBreakpoint();
4590b57cec5SDimitry Andric     ThreadPlan::MischiefManaged();
4600b57cec5SDimitry Andric     return true;
4610b57cec5SDimitry Andric   } else {
4620b57cec5SDimitry Andric     return false;
4630b57cec5SDimitry Andric   }
4640b57cec5SDimitry Andric }
4650b57cec5SDimitry Andric 
IsPlanStale()4660b57cec5SDimitry Andric bool ThreadPlanStepRange::IsPlanStale() {
4670b57cec5SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
4680b57cec5SDimitry Andric   FrameComparison frame_order = CompareCurrentFrameToStartFrame();
4690b57cec5SDimitry Andric 
4700b57cec5SDimitry Andric   if (frame_order == eFrameCompareOlder) {
4710b57cec5SDimitry Andric     if (log) {
4729dba64beSDimitry Andric       LLDB_LOGF(log, "ThreadPlanStepRange::IsPlanStale returning true, we've "
4730b57cec5SDimitry Andric                      "stepped out.");
4740b57cec5SDimitry Andric     }
4750b57cec5SDimitry Andric     return true;
4760b57cec5SDimitry Andric   } else if (frame_order == eFrameCompareEqual && InSymbol()) {
4770b57cec5SDimitry Andric     // If we are not in a place we should step through, we've gotten stale. One
4780b57cec5SDimitry Andric     // tricky bit here is that some stubs don't push a frame, so we should.
4790b57cec5SDimitry Andric     // check that we are in the same symbol.
4800b57cec5SDimitry Andric     if (!InRange()) {
4810b57cec5SDimitry Andric       // Set plan Complete when we reach next instruction just after the range
4825ffd83dbSDimitry Andric       lldb::addr_t addr = GetThread().GetRegisterContext()->GetPC() - 1;
4830b57cec5SDimitry Andric       size_t num_ranges = m_address_ranges.size();
4840b57cec5SDimitry Andric       for (size_t i = 0; i < num_ranges; i++) {
4855ffd83dbSDimitry Andric         bool in_range =
4865ffd83dbSDimitry Andric             m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget());
4870b57cec5SDimitry Andric         if (in_range) {
4880b57cec5SDimitry Andric           SetPlanComplete();
4890b57cec5SDimitry Andric         }
4900b57cec5SDimitry Andric       }
4910b57cec5SDimitry Andric       return true;
4920b57cec5SDimitry Andric     }
4930b57cec5SDimitry Andric   }
4940b57cec5SDimitry Andric   return false;
4950b57cec5SDimitry Andric }
496