1cfca06d7SDimitry Andric //===-- ThreadPlanStepRange.cpp -------------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste
9e81d9d49SDimitry Andric #include "lldb/Target/ThreadPlanStepRange.h"
10f034231aSEd Maste #include "lldb/Breakpoint/BreakpointLocation.h"
11f034231aSEd Maste #include "lldb/Breakpoint/BreakpointSite.h"
12f034231aSEd Maste #include "lldb/Core/Disassembler.h"
13f034231aSEd Maste #include "lldb/Symbol/Function.h"
14f034231aSEd Maste #include "lldb/Symbol/Symbol.h"
15f034231aSEd Maste #include "lldb/Target/ExecutionContext.h"
16f034231aSEd Maste #include "lldb/Target/Process.h"
17f034231aSEd Maste #include "lldb/Target/RegisterContext.h"
18f034231aSEd Maste #include "lldb/Target/StopInfo.h"
19f034231aSEd Maste #include "lldb/Target/Target.h"
20f034231aSEd Maste #include "lldb/Target/Thread.h"
21f034231aSEd Maste #include "lldb/Target/ThreadPlanRunToAddress.h"
22145449b1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
2374a628f7SDimitry Andric #include "lldb/Utility/Log.h"
2474a628f7SDimitry Andric #include "lldb/Utility/Stream.h"
25f034231aSEd Maste
26f034231aSEd Maste using namespace lldb;
27f034231aSEd Maste using namespace lldb_private;
28f034231aSEd Maste
29f73363f1SDimitry Andric // ThreadPlanStepRange: Step through a stack range, either stepping over or
30f73363f1SDimitry Andric // into based on the value of \a type.
31f034231aSEd Maste
ThreadPlanStepRange(ThreadPlanKind kind,const char * name,Thread & thread,const AddressRange & range,const SymbolContext & addr_context,lldb::RunMode stop_others,bool given_ranges_only)3214f1b3e8SDimitry Andric ThreadPlanStepRange::ThreadPlanStepRange(ThreadPlanKind kind, const char *name,
33f034231aSEd Maste Thread &thread,
34f034231aSEd Maste const AddressRange &range,
35f034231aSEd Maste const SymbolContext &addr_context,
36205afe67SEd Maste lldb::RunMode stop_others,
3714f1b3e8SDimitry Andric bool given_ranges_only)
3814f1b3e8SDimitry Andric : ThreadPlan(kind, name, thread, eVoteNoOpinion, eVoteNoOpinion),
3914f1b3e8SDimitry Andric m_addr_context(addr_context), m_address_ranges(),
4014f1b3e8SDimitry Andric m_stop_others(stop_others), m_stack_id(), m_parent_stack_id(),
4114f1b3e8SDimitry Andric m_no_more_plans(false), m_first_run_event(true), m_use_fast_step(false),
4214f1b3e8SDimitry Andric m_given_ranges_only(given_ranges_only) {
43f034231aSEd Maste m_use_fast_step = GetTarget().GetUseFastStepping();
44f034231aSEd Maste AddRange(range);
45cfca06d7SDimitry Andric m_stack_id = thread.GetStackFrameAtIndex(0)->GetStackID();
46cfca06d7SDimitry Andric StackFrameSP parent_stack = thread.GetStackFrameAtIndex(1);
470cac4ca3SEd Maste if (parent_stack)
480cac4ca3SEd Maste m_parent_stack_id = parent_stack->GetStackID();
49f034231aSEd Maste }
50f034231aSEd Maste
~ThreadPlanStepRange()5114f1b3e8SDimitry Andric ThreadPlanStepRange::~ThreadPlanStepRange() { ClearNextBranchBreakpoint(); }
52f034231aSEd Maste
DidPush()5314f1b3e8SDimitry Andric void ThreadPlanStepRange::DidPush() {
54f034231aSEd Maste // See if we can find a "next range" breakpoint:
55f034231aSEd Maste SetNextBranchBreakpoint();
56f034231aSEd Maste }
57f034231aSEd Maste
ValidatePlan(Stream * error)5894994d37SDimitry Andric bool ThreadPlanStepRange::ValidatePlan(Stream *error) {
5994994d37SDimitry Andric if (m_could_not_resolve_hw_bp) {
6094994d37SDimitry Andric if (error)
6194994d37SDimitry Andric error->PutCString(
6294994d37SDimitry Andric "Could not create hardware breakpoint for thread plan.");
6394994d37SDimitry Andric return false;
6494994d37SDimitry Andric }
6594994d37SDimitry Andric return true;
6694994d37SDimitry Andric }
67f034231aSEd Maste
ShouldReportStop(Event * event_ptr)6814f1b3e8SDimitry Andric Vote ThreadPlanStepRange::ShouldReportStop(Event *event_ptr) {
69145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Step);
70f034231aSEd Maste
71f034231aSEd Maste const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo;
72ead24645SDimitry Andric LLDB_LOGF(log, "ThreadPlanStepRange::ShouldReportStop() returning vote %i\n",
7314f1b3e8SDimitry Andric vote);
74f034231aSEd Maste return vote;
75f034231aSEd Maste }
76f034231aSEd Maste
AddRange(const AddressRange & new_range)7714f1b3e8SDimitry Andric void ThreadPlanStepRange::AddRange(const AddressRange &new_range) {
78f73363f1SDimitry Andric // For now I'm just adding the ranges. At some point we may want to condense
79f73363f1SDimitry Andric // the ranges if they overlap, though I don't think it is likely to be very
80f73363f1SDimitry Andric // important.
81f034231aSEd Maste m_address_ranges.push_back(new_range);
82f034231aSEd Maste
8314f1b3e8SDimitry Andric // Fill the slot for this address range with an empty DisassemblerSP in the
84f73363f1SDimitry Andric // instruction ranges. I want the indices to match, but I don't want to do
85f73363f1SDimitry Andric // the work to disassemble this range if I don't step into it.
86f034231aSEd Maste m_instruction_ranges.push_back(DisassemblerSP());
87f034231aSEd Maste }
88f034231aSEd Maste
DumpRanges(Stream * s)8914f1b3e8SDimitry Andric void ThreadPlanStepRange::DumpRanges(Stream *s) {
90f034231aSEd Maste size_t num_ranges = m_address_ranges.size();
9114f1b3e8SDimitry Andric if (num_ranges == 1) {
92cfca06d7SDimitry Andric m_address_ranges[0].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress);
9314f1b3e8SDimitry Andric } else {
9414f1b3e8SDimitry Andric for (size_t i = 0; i < num_ranges; i++) {
95e81d9d49SDimitry Andric s->Printf(" %" PRIu64 ": ", uint64_t(i));
96cfca06d7SDimitry Andric m_address_ranges[i].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress);
97f034231aSEd Maste }
98f034231aSEd Maste }
99f034231aSEd Maste }
100f034231aSEd Maste
InRange()10114f1b3e8SDimitry Andric bool ThreadPlanStepRange::InRange() {
102145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Step);
103f034231aSEd Maste bool ret_value = false;
104cfca06d7SDimitry Andric Thread &thread = GetThread();
105cfca06d7SDimitry Andric lldb::addr_t pc_load_addr = thread.GetRegisterContext()->GetPC();
106f034231aSEd Maste
107f034231aSEd Maste size_t num_ranges = m_address_ranges.size();
10814f1b3e8SDimitry Andric for (size_t i = 0; i < num_ranges; i++) {
109cfca06d7SDimitry Andric ret_value =
110cfca06d7SDimitry Andric m_address_ranges[i].ContainsLoadAddress(pc_load_addr, &GetTarget());
111f034231aSEd Maste if (ret_value)
112f034231aSEd Maste break;
113f034231aSEd Maste }
114f034231aSEd Maste
11514f1b3e8SDimitry Andric if (!ret_value && !m_given_ranges_only) {
116f034231aSEd Maste // See if we've just stepped to another part of the same line number...
117cfca06d7SDimitry Andric StackFrame *frame = thread.GetStackFrameAtIndex(0).get();
118f034231aSEd Maste
11914f1b3e8SDimitry Andric SymbolContext new_context(
12014f1b3e8SDimitry Andric frame->GetSymbolContext(eSymbolContextEverything));
12114f1b3e8SDimitry Andric if (m_addr_context.line_entry.IsValid() &&
12214f1b3e8SDimitry Andric new_context.line_entry.IsValid()) {
123ac9a064cSDimitry Andric if (m_addr_context.line_entry.original_file_sp->Equal(
124ac9a064cSDimitry Andric *new_context.line_entry.original_file_sp,
125ac9a064cSDimitry Andric SupportFile::eEqualFileSpecAndChecksumIfSet)) {
12614f1b3e8SDimitry Andric if (m_addr_context.line_entry.line == new_context.line_entry.line) {
127f034231aSEd Maste m_addr_context = new_context;
1285f29bb8aSDimitry Andric const bool include_inlined_functions =
1295f29bb8aSDimitry Andric GetKind() == eKindStepOverRange;
1305f29bb8aSDimitry Andric AddRange(m_addr_context.line_entry.GetSameLineContiguousAddressRange(
1315f29bb8aSDimitry Andric include_inlined_functions));
132f034231aSEd Maste ret_value = true;
13314f1b3e8SDimitry Andric if (log) {
134f034231aSEd Maste StreamString s;
135cfca06d7SDimitry Andric m_addr_context.line_entry.Dump(&s, &GetTarget(), true,
136cfca06d7SDimitry Andric Address::DumpStyleLoadAddress,
13714f1b3e8SDimitry Andric Address::DumpStyleLoadAddress, true);
138f034231aSEd Maste
139ead24645SDimitry Andric LLDB_LOGF(
140ead24645SDimitry Andric log,
14114f1b3e8SDimitry Andric "Step range plan stepped to another range of same line: %s",
14214f1b3e8SDimitry Andric s.GetData());
143f034231aSEd Maste }
14414f1b3e8SDimitry Andric } else if (new_context.line_entry.line == 0) {
145f21a844fSEd Maste new_context.line_entry.line = m_addr_context.line_entry.line;
146f21a844fSEd Maste m_addr_context = new_context;
1475f29bb8aSDimitry Andric const bool include_inlined_functions =
1485f29bb8aSDimitry Andric GetKind() == eKindStepOverRange;
1495f29bb8aSDimitry Andric AddRange(m_addr_context.line_entry.GetSameLineContiguousAddressRange(
1505f29bb8aSDimitry Andric include_inlined_functions));
151f21a844fSEd Maste ret_value = true;
15214f1b3e8SDimitry Andric if (log) {
153f21a844fSEd Maste StreamString s;
154cfca06d7SDimitry Andric m_addr_context.line_entry.Dump(&s, &GetTarget(), true,
155cfca06d7SDimitry Andric Address::DumpStyleLoadAddress,
15614f1b3e8SDimitry Andric Address::DumpStyleLoadAddress, true);
157f21a844fSEd Maste
158ead24645SDimitry Andric LLDB_LOGF(log,
159ead24645SDimitry Andric "Step range plan stepped to a range at linenumber 0 "
16014f1b3e8SDimitry Andric "stepping through that range: %s",
16114f1b3e8SDimitry Andric s.GetData());
162f21a844fSEd Maste }
16314f1b3e8SDimitry Andric } else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(
164cfca06d7SDimitry Andric &GetTarget()) != pc_load_addr) {
16514f1b3e8SDimitry Andric // Another thing that sometimes happens here is that we step out of
166f73363f1SDimitry Andric // one line into the MIDDLE of another line. So far I mostly see
167f73363f1SDimitry Andric // this due to bugs in the debug information. But we probably don't
168f73363f1SDimitry Andric // want to be in the middle of a line range, so in that case reset
169f73363f1SDimitry Andric // the stepping range to the line we've stepped into the middle of
170f73363f1SDimitry Andric // and continue.
171f034231aSEd Maste m_addr_context = new_context;
172f034231aSEd Maste m_address_ranges.clear();
173f034231aSEd Maste AddRange(m_addr_context.line_entry.range);
174f034231aSEd Maste ret_value = true;
17514f1b3e8SDimitry Andric if (log) {
176f034231aSEd Maste StreamString s;
177cfca06d7SDimitry Andric m_addr_context.line_entry.Dump(&s, &GetTarget(), true,
178cfca06d7SDimitry Andric Address::DumpStyleLoadAddress,
17914f1b3e8SDimitry Andric Address::DumpStyleLoadAddress, true);
180f034231aSEd Maste
181ead24645SDimitry Andric LLDB_LOGF(log,
182ead24645SDimitry Andric "Step range plan stepped to the middle of new "
18314f1b3e8SDimitry Andric "line(%d): %s, continuing to clear this line.",
18414f1b3e8SDimitry Andric new_context.line_entry.line, s.GetData());
185f034231aSEd Maste }
186f034231aSEd Maste }
187f034231aSEd Maste }
188f034231aSEd Maste }
189f034231aSEd Maste }
190f034231aSEd Maste
191f034231aSEd Maste if (!ret_value && log)
192ead24645SDimitry Andric LLDB_LOGF(log, "Step range plan out of range to 0x%" PRIx64, pc_load_addr);
193f034231aSEd Maste
194f034231aSEd Maste return ret_value;
195f034231aSEd Maste }
196f034231aSEd Maste
InSymbol()19714f1b3e8SDimitry Andric bool ThreadPlanStepRange::InSymbol() {
198cfca06d7SDimitry Andric lldb::addr_t cur_pc = GetThread().GetRegisterContext()->GetPC();
19914f1b3e8SDimitry Andric if (m_addr_context.function != nullptr) {
20014f1b3e8SDimitry Andric return m_addr_context.function->GetAddressRange().ContainsLoadAddress(
201cfca06d7SDimitry Andric cur_pc, &GetTarget());
20214f1b3e8SDimitry Andric } else if (m_addr_context.symbol && m_addr_context.symbol->ValueIsAddress()) {
20314f1b3e8SDimitry Andric AddressRange range(m_addr_context.symbol->GetAddressRef(),
20414f1b3e8SDimitry Andric m_addr_context.symbol->GetByteSize());
205cfca06d7SDimitry Andric return range.ContainsLoadAddress(cur_pc, &GetTarget());
206f034231aSEd Maste }
207f034231aSEd Maste return false;
208f034231aSEd Maste }
209f034231aSEd Maste
21014f1b3e8SDimitry Andric // FIXME: This should also handle inlining if we aren't going to do inlining in
21114f1b3e8SDimitry Andric // the
212f034231aSEd Maste // main stack.
213f034231aSEd Maste //
214f034231aSEd Maste // Ideally we should remember the whole stack frame list, and then compare that
215f034231aSEd Maste // to the current list.
216f034231aSEd Maste
CompareCurrentFrameToStartFrame()21714f1b3e8SDimitry Andric lldb::FrameComparison ThreadPlanStepRange::CompareCurrentFrameToStartFrame() {
218f034231aSEd Maste FrameComparison frame_order;
219cfca06d7SDimitry Andric Thread &thread = GetThread();
220cfca06d7SDimitry Andric StackID cur_frame_id = thread.GetStackFrameAtIndex(0)->GetStackID();
221f034231aSEd Maste
22214f1b3e8SDimitry Andric if (cur_frame_id == m_stack_id) {
223f034231aSEd Maste frame_order = eFrameCompareEqual;
22414f1b3e8SDimitry Andric } else if (cur_frame_id < m_stack_id) {
225f034231aSEd Maste frame_order = eFrameCompareYounger;
22614f1b3e8SDimitry Andric } else {
227cfca06d7SDimitry Andric StackFrameSP cur_parent_frame = thread.GetStackFrameAtIndex(1);
2280cac4ca3SEd Maste StackID cur_parent_id;
2290cac4ca3SEd Maste if (cur_parent_frame)
2300cac4ca3SEd Maste cur_parent_id = cur_parent_frame->GetStackID();
23114f1b3e8SDimitry Andric if (m_parent_stack_id.IsValid() && cur_parent_id.IsValid() &&
23214f1b3e8SDimitry Andric m_parent_stack_id == cur_parent_id)
2330cac4ca3SEd Maste frame_order = eFrameCompareSameParent;
2340cac4ca3SEd Maste else
235f034231aSEd Maste frame_order = eFrameCompareOlder;
236f034231aSEd Maste }
237f034231aSEd Maste return frame_order;
238f034231aSEd Maste }
239f034231aSEd Maste
StopOthers()24014f1b3e8SDimitry Andric bool ThreadPlanStepRange::StopOthers() {
241706b4fc4SDimitry Andric switch (m_stop_others) {
242706b4fc4SDimitry Andric case lldb::eOnlyThisThread:
243706b4fc4SDimitry Andric return true;
244706b4fc4SDimitry Andric case lldb::eOnlyDuringStepping:
245706b4fc4SDimitry Andric // If there is a call in the range of the next branch breakpoint,
246706b4fc4SDimitry Andric // then we should always run all threads, since a call can execute
247706b4fc4SDimitry Andric // arbitrary code which might for instance take a lock that's held
248706b4fc4SDimitry Andric // by another thread.
249706b4fc4SDimitry Andric return !m_found_calls;
250706b4fc4SDimitry Andric case lldb::eAllThreads:
251706b4fc4SDimitry Andric return false;
252706b4fc4SDimitry Andric }
253706b4fc4SDimitry Andric llvm_unreachable("Unhandled run mode!");
254f034231aSEd Maste }
255f034231aSEd Maste
GetInstructionsForAddress(lldb::addr_t addr,size_t & range_index,size_t & insn_offset)25614f1b3e8SDimitry Andric InstructionList *ThreadPlanStepRange::GetInstructionsForAddress(
25714f1b3e8SDimitry Andric lldb::addr_t addr, size_t &range_index, size_t &insn_offset) {
258f034231aSEd Maste size_t num_ranges = m_address_ranges.size();
25914f1b3e8SDimitry Andric for (size_t i = 0; i < num_ranges; i++) {
26014f1b3e8SDimitry Andric if (m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget())) {
261f034231aSEd Maste // Some joker added a zero size range to the stepping range...
262f034231aSEd Maste if (m_address_ranges[i].GetByteSize() == 0)
263e81d9d49SDimitry Andric return nullptr;
264f034231aSEd Maste
26514f1b3e8SDimitry Andric if (!m_instruction_ranges[i]) {
266f034231aSEd Maste // Disassemble the address range given:
267e81d9d49SDimitry Andric const char *plugin_name = nullptr;
268e81d9d49SDimitry Andric const char *flavor = nullptr;
26914f1b3e8SDimitry Andric m_instruction_ranges[i] = Disassembler::DisassembleRange(
270cfca06d7SDimitry Andric GetTarget().GetArchitecture(), plugin_name, flavor, GetTarget(),
271344a3780SDimitry Andric m_address_ranges[i]);
272f034231aSEd Maste }
273f034231aSEd Maste if (!m_instruction_ranges[i])
274e81d9d49SDimitry Andric return nullptr;
27514f1b3e8SDimitry Andric else {
27614f1b3e8SDimitry Andric // Find where we are in the instruction list as well. If we aren't at
277f73363f1SDimitry Andric // an instruction, return nullptr. In this case, we're probably lost,
278f73363f1SDimitry Andric // and shouldn't try to do anything fancy.
279f034231aSEd Maste
28014f1b3e8SDimitry Andric insn_offset =
28114f1b3e8SDimitry Andric m_instruction_ranges[i]
28214f1b3e8SDimitry Andric ->GetInstructionList()
28314f1b3e8SDimitry Andric .GetIndexOfInstructionAtLoadAddress(addr, GetTarget());
284f034231aSEd Maste if (insn_offset == UINT32_MAX)
285e81d9d49SDimitry Andric return nullptr;
28614f1b3e8SDimitry Andric else {
287f034231aSEd Maste range_index = i;
288f034231aSEd Maste return &m_instruction_ranges[i]->GetInstructionList();
289f034231aSEd Maste }
290f034231aSEd Maste }
291f034231aSEd Maste }
292f034231aSEd Maste }
293e81d9d49SDimitry Andric return nullptr;
294f034231aSEd Maste }
295f034231aSEd Maste
ClearNextBranchBreakpoint()29614f1b3e8SDimitry Andric void ThreadPlanStepRange::ClearNextBranchBreakpoint() {
29714f1b3e8SDimitry Andric if (m_next_branch_bp_sp) {
298145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Step);
299ead24645SDimitry Andric LLDB_LOGF(log, "Removing next branch breakpoint: %d.",
30014f1b3e8SDimitry Andric m_next_branch_bp_sp->GetID());
301f034231aSEd Maste GetTarget().RemoveBreakpointByID(m_next_branch_bp_sp->GetID());
302f034231aSEd Maste m_next_branch_bp_sp.reset();
30394994d37SDimitry Andric m_could_not_resolve_hw_bp = false;
304706b4fc4SDimitry Andric m_found_calls = false;
305f034231aSEd Maste }
306f034231aSEd Maste }
307f034231aSEd Maste
SetNextBranchBreakpoint()30814f1b3e8SDimitry Andric bool ThreadPlanStepRange::SetNextBranchBreakpoint() {
309f034231aSEd Maste if (m_next_branch_bp_sp)
310f034231aSEd Maste return true;
311f034231aSEd Maste
312145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Step);
31314f1b3e8SDimitry Andric // Stepping through ranges using breakpoints doesn't work yet, but with this
314f73363f1SDimitry Andric // off we fall back to instruction single stepping.
315f034231aSEd Maste if (!m_use_fast_step)
316f034231aSEd Maste return false;
317f034231aSEd Maste
318706b4fc4SDimitry Andric // clear the m_found_calls, we'll rediscover it for this range.
319706b4fc4SDimitry Andric m_found_calls = false;
320706b4fc4SDimitry Andric
321f034231aSEd Maste lldb::addr_t cur_addr = GetThread().GetRegisterContext()->GetPC();
32214f1b3e8SDimitry Andric // Find the current address in our address ranges, and fetch the disassembly
32314f1b3e8SDimitry Andric // if we haven't already:
324f034231aSEd Maste size_t pc_index;
325f034231aSEd Maste size_t range_index;
32614f1b3e8SDimitry Andric InstructionList *instructions =
32714f1b3e8SDimitry Andric GetInstructionsForAddress(cur_addr, range_index, pc_index);
328e81d9d49SDimitry Andric if (instructions == nullptr)
329f034231aSEd Maste return false;
33014f1b3e8SDimitry Andric else {
3315f29bb8aSDimitry Andric const bool ignore_calls = GetKind() == eKindStepOverRange;
332b60736ecSDimitry Andric uint32_t branch_index = instructions->GetIndexOfNextBranchInstruction(
333b60736ecSDimitry Andric pc_index, ignore_calls, &m_found_calls);
334f034231aSEd Maste Address run_to_address;
335f034231aSEd Maste
336f034231aSEd Maste // If we didn't find a branch, run to the end of the range.
33714f1b3e8SDimitry Andric if (branch_index == UINT32_MAX) {
338e81d9d49SDimitry Andric uint32_t last_index = instructions->GetSize() - 1;
33914f1b3e8SDimitry Andric if (last_index - pc_index > 1) {
34014f1b3e8SDimitry Andric InstructionSP last_inst =
34114f1b3e8SDimitry Andric instructions->GetInstructionAtIndex(last_index);
342e81d9d49SDimitry Andric size_t last_inst_size = last_inst->GetOpcode().GetByteSize();
343e81d9d49SDimitry Andric run_to_address = last_inst->GetAddress();
344e81d9d49SDimitry Andric run_to_address.Slide(last_inst_size);
345e81d9d49SDimitry Andric }
34614f1b3e8SDimitry Andric } else if (branch_index - pc_index > 1) {
34714f1b3e8SDimitry Andric run_to_address =
34814f1b3e8SDimitry Andric instructions->GetInstructionAtIndex(branch_index)->GetAddress();
349f034231aSEd Maste }
350f034231aSEd Maste
35114f1b3e8SDimitry Andric if (run_to_address.IsValid()) {
352f034231aSEd Maste const bool is_internal = true;
35314f1b3e8SDimitry Andric m_next_branch_bp_sp =
35414f1b3e8SDimitry Andric GetTarget().CreateBreakpoint(run_to_address, is_internal, false);
35514f1b3e8SDimitry Andric if (m_next_branch_bp_sp) {
35694994d37SDimitry Andric
35794994d37SDimitry Andric if (m_next_branch_bp_sp->IsHardware() &&
35894994d37SDimitry Andric !m_next_branch_bp_sp->HasResolvedLocations())
35994994d37SDimitry Andric m_could_not_resolve_hw_bp = true;
36094994d37SDimitry Andric
36114f1b3e8SDimitry Andric if (log) {
362f034231aSEd Maste lldb::break_id_t bp_site_id = LLDB_INVALID_BREAK_ID;
36314f1b3e8SDimitry Andric BreakpointLocationSP bp_loc =
36414f1b3e8SDimitry Andric m_next_branch_bp_sp->GetLocationAtIndex(0);
36514f1b3e8SDimitry Andric if (bp_loc) {
366f034231aSEd Maste BreakpointSiteSP bp_site = bp_loc->GetBreakpointSite();
36714f1b3e8SDimitry Andric if (bp_site) {
368f034231aSEd Maste bp_site_id = bp_site->GetID();
369f034231aSEd Maste }
370f034231aSEd Maste }
371ead24645SDimitry Andric LLDB_LOGF(log,
372ead24645SDimitry Andric "ThreadPlanStepRange::SetNextBranchBreakpoint - Setting "
37314f1b3e8SDimitry Andric "breakpoint %d (site %d) to run to address 0x%" PRIx64,
37414f1b3e8SDimitry Andric m_next_branch_bp_sp->GetID(), bp_site_id,
375cfca06d7SDimitry Andric run_to_address.GetLoadAddress(&m_process.GetTarget()));
376f034231aSEd Maste }
37794994d37SDimitry Andric
378cfca06d7SDimitry Andric m_next_branch_bp_sp->SetThreadID(m_tid);
379f034231aSEd Maste m_next_branch_bp_sp->SetBreakpointKind("next-branch-location");
38094994d37SDimitry Andric
381f034231aSEd Maste return true;
38214f1b3e8SDimitry Andric } else
383f034231aSEd Maste return false;
384f034231aSEd Maste }
385f034231aSEd Maste }
386f034231aSEd Maste return false;
387f034231aSEd Maste }
388f034231aSEd Maste
NextRangeBreakpointExplainsStop(lldb::StopInfoSP stop_info_sp)38914f1b3e8SDimitry Andric bool ThreadPlanStepRange::NextRangeBreakpointExplainsStop(
39014f1b3e8SDimitry Andric lldb::StopInfoSP stop_info_sp) {
391145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Step);
392f034231aSEd Maste if (!m_next_branch_bp_sp)
393f034231aSEd Maste return false;
394f034231aSEd Maste
395f034231aSEd Maste break_id_t bp_site_id = stop_info_sp->GetValue();
39614f1b3e8SDimitry Andric BreakpointSiteSP bp_site_sp =
397cfca06d7SDimitry Andric m_process.GetBreakpointSiteList().FindByID(bp_site_id);
398f034231aSEd Maste if (!bp_site_sp)
399f034231aSEd Maste return false;
400f034231aSEd Maste else if (!bp_site_sp->IsBreakpointAtThisSite(m_next_branch_bp_sp->GetID()))
401f034231aSEd Maste return false;
40214f1b3e8SDimitry Andric else {
403f034231aSEd Maste // If we've hit the next branch breakpoint, then clear it.
404b1c73532SDimitry Andric size_t num_constituents = bp_site_sp->GetNumberOfConstituents();
405f034231aSEd Maste bool explains_stop = true;
406b1c73532SDimitry Andric // If all the constituents are internal, then we are probably just stepping
407b1c73532SDimitry Andric // over this range from multiple threads, or multiple frames, so we want to
408f73363f1SDimitry Andric // continue. If one is not internal, then we should not explain the stop,
409f034231aSEd Maste // and let the user breakpoint handle the stop.
410b1c73532SDimitry Andric for (size_t i = 0; i < num_constituents; i++) {
411b1c73532SDimitry Andric if (!bp_site_sp->GetConstituentAtIndex(i)->GetBreakpoint().IsInternal()) {
412f034231aSEd Maste explains_stop = false;
413f034231aSEd Maste break;
414f034231aSEd Maste }
415f034231aSEd Maste }
416ead24645SDimitry Andric LLDB_LOGF(log,
417ead24645SDimitry Andric "ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit "
41814f1b3e8SDimitry Andric "next range breakpoint which has %" PRIu64
419b1c73532SDimitry Andric " constituents - explains stop: %u.",
420b1c73532SDimitry Andric (uint64_t)num_constituents, explains_stop);
421f034231aSEd Maste ClearNextBranchBreakpoint();
422f034231aSEd Maste return explains_stop;
423f034231aSEd Maste }
424f034231aSEd Maste }
425f034231aSEd Maste
WillStop()42614f1b3e8SDimitry Andric bool ThreadPlanStepRange::WillStop() { return true; }
427f034231aSEd Maste
GetPlanRunState()42814f1b3e8SDimitry Andric StateType ThreadPlanStepRange::GetPlanRunState() {
429f034231aSEd Maste if (m_next_branch_bp_sp)
430f034231aSEd Maste return eStateRunning;
431f034231aSEd Maste else
432f034231aSEd Maste return eStateStepping;
433f034231aSEd Maste }
434f034231aSEd Maste
MischiefManaged()43514f1b3e8SDimitry Andric bool ThreadPlanStepRange::MischiefManaged() {
43614f1b3e8SDimitry Andric // If we have pushed some plans between ShouldStop & MischiefManaged, then
43714f1b3e8SDimitry Andric // we're not done...
43814f1b3e8SDimitry Andric // I do this check first because we might have stepped somewhere that will
43914f1b3e8SDimitry Andric // fool InRange into
44014f1b3e8SDimitry Andric // thinking it needs to step past the end of that line. This happens, for
441f73363f1SDimitry Andric // instance, when stepping over inlined code that is in the middle of the
442f73363f1SDimitry Andric // current line.
443f034231aSEd Maste
444f034231aSEd Maste if (!m_no_more_plans)
445f034231aSEd Maste return false;
446f034231aSEd Maste
447f034231aSEd Maste bool done = true;
44814f1b3e8SDimitry Andric if (!IsPlanComplete()) {
44914f1b3e8SDimitry Andric if (InRange()) {
450f034231aSEd Maste done = false;
45114f1b3e8SDimitry Andric } else {
452f034231aSEd Maste FrameComparison frame_order = CompareCurrentFrameToStartFrame();
453e81d9d49SDimitry Andric done = (frame_order != eFrameCompareOlder) ? m_no_more_plans : true;
454f034231aSEd Maste }
455f034231aSEd Maste }
456f034231aSEd Maste
45714f1b3e8SDimitry Andric if (done) {
458145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Step);
459ead24645SDimitry Andric LLDB_LOGF(log, "Completed step through range plan.");
460f034231aSEd Maste ClearNextBranchBreakpoint();
461f034231aSEd Maste ThreadPlan::MischiefManaged();
462f034231aSEd Maste return true;
46314f1b3e8SDimitry Andric } else {
464f034231aSEd Maste return false;
465f034231aSEd Maste }
466f034231aSEd Maste }
467f034231aSEd Maste
IsPlanStale()46814f1b3e8SDimitry Andric bool ThreadPlanStepRange::IsPlanStale() {
469145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Step);
470f034231aSEd Maste FrameComparison frame_order = CompareCurrentFrameToStartFrame();
471f034231aSEd Maste
47214f1b3e8SDimitry Andric if (frame_order == eFrameCompareOlder) {
47314f1b3e8SDimitry Andric if (log) {
474ead24645SDimitry Andric LLDB_LOGF(log, "ThreadPlanStepRange::IsPlanStale returning true, we've "
47514f1b3e8SDimitry Andric "stepped out.");
476f034231aSEd Maste }
477f034231aSEd Maste return true;
47814f1b3e8SDimitry Andric } else if (frame_order == eFrameCompareEqual && InSymbol()) {
479f73363f1SDimitry Andric // If we are not in a place we should step through, we've gotten stale. One
480f73363f1SDimitry Andric // tricky bit here is that some stubs don't push a frame, so we should.
481f034231aSEd Maste // check that we are in the same symbol.
48214f1b3e8SDimitry Andric if (!InRange()) {
48374a628f7SDimitry Andric // Set plan Complete when we reach next instruction just after the range
484cfca06d7SDimitry Andric lldb::addr_t addr = GetThread().GetRegisterContext()->GetPC() - 1;
48574a628f7SDimitry Andric size_t num_ranges = m_address_ranges.size();
48674a628f7SDimitry Andric for (size_t i = 0; i < num_ranges; i++) {
487cfca06d7SDimitry Andric bool in_range =
488cfca06d7SDimitry Andric m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget());
48974a628f7SDimitry Andric if (in_range) {
49074a628f7SDimitry Andric SetPlanComplete();
49174a628f7SDimitry Andric }
49274a628f7SDimitry Andric }
493f034231aSEd Maste return true;
494f034231aSEd Maste }
495f034231aSEd Maste }
496f034231aSEd Maste return false;
497f034231aSEd Maste }
498