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