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