1 //===-- ThreadPlanStepRange.cpp -------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Target/ThreadPlanStepRange.h"
10 #include "lldb/Breakpoint/BreakpointLocation.h"
11 #include "lldb/Breakpoint/BreakpointSite.h"
12 #include "lldb/Core/Disassembler.h"
13 #include "lldb/Symbol/Function.h"
14 #include "lldb/Symbol/Symbol.h"
15 #include "lldb/Target/ExecutionContext.h"
16 #include "lldb/Target/Process.h"
17 #include "lldb/Target/RegisterContext.h"
18 #include "lldb/Target/StopInfo.h"
19 #include "lldb/Target/Target.h"
20 #include "lldb/Target/Thread.h"
21 #include "lldb/Target/ThreadPlanRunToAddress.h"
22 #include "lldb/Utility/LLDBLog.h"
23 #include "lldb/Utility/Log.h"
24 #include "lldb/Utility/Stream.h"
27 using namespace lldb_private
;
29 // ThreadPlanStepRange: Step through a stack range, either stepping over or
30 // into based on the value of \a type.
32 ThreadPlanStepRange::ThreadPlanStepRange(ThreadPlanKind kind
, const char *name
,
34 const AddressRange
&range
,
35 const SymbolContext
&addr_context
,
36 lldb::RunMode stop_others
,
37 bool given_ranges_only
)
38 : ThreadPlan(kind
, name
, thread
, eVoteNoOpinion
, eVoteNoOpinion
),
39 m_addr_context(addr_context
), m_address_ranges(),
40 m_stop_others(stop_others
), m_stack_id(), m_parent_stack_id(),
41 m_no_more_plans(false), m_first_run_event(true), m_use_fast_step(false),
42 m_given_ranges_only(given_ranges_only
) {
43 m_use_fast_step
= GetTarget().GetUseFastStepping();
45 m_stack_id
= thread
.GetStackFrameAtIndex(0)->GetStackID();
46 StackFrameSP parent_stack
= thread
.GetStackFrameAtIndex(1);
48 m_parent_stack_id
= parent_stack
->GetStackID();
51 ThreadPlanStepRange::~ThreadPlanStepRange() { ClearNextBranchBreakpoint(); }
53 void ThreadPlanStepRange::DidPush() {
54 // See if we can find a "next range" breakpoint:
55 SetNextBranchBreakpoint();
58 bool ThreadPlanStepRange::ValidatePlan(Stream
*error
) {
59 if (m_could_not_resolve_hw_bp
) {
62 "Could not create hardware breakpoint for thread plan.");
68 Vote
ThreadPlanStepRange::ShouldReportStop(Event
*event_ptr
) {
69 Log
*log
= GetLog(LLDBLog::Step
);
71 const Vote vote
= IsPlanComplete() ? eVoteYes
: eVoteNo
;
72 LLDB_LOGF(log
, "ThreadPlanStepRange::ShouldReportStop() returning vote %i\n",
77 void ThreadPlanStepRange::AddRange(const AddressRange
&new_range
) {
78 // For now I'm just adding the ranges. At some point we may want to condense
79 // the ranges if they overlap, though I don't think it is likely to be very
81 m_address_ranges
.push_back(new_range
);
83 // Fill the slot for this address range with an empty DisassemblerSP in the
84 // instruction ranges. I want the indices to match, but I don't want to do
85 // the work to disassemble this range if I don't step into it.
86 m_instruction_ranges
.push_back(DisassemblerSP());
89 void ThreadPlanStepRange::DumpRanges(Stream
*s
) {
90 size_t num_ranges
= m_address_ranges
.size();
91 if (num_ranges
== 1) {
92 m_address_ranges
[0].Dump(s
, &GetTarget(), Address::DumpStyleLoadAddress
);
94 for (size_t i
= 0; i
< num_ranges
; i
++) {
95 s
->Printf(" %" PRIu64
": ", uint64_t(i
));
96 m_address_ranges
[i
].Dump(s
, &GetTarget(), Address::DumpStyleLoadAddress
);
101 bool ThreadPlanStepRange::InRange() {
102 Log
*log
= GetLog(LLDBLog::Step
);
103 bool ret_value
= false;
104 Thread
&thread
= GetThread();
105 lldb::addr_t pc_load_addr
= thread
.GetRegisterContext()->GetPC();
107 size_t num_ranges
= m_address_ranges
.size();
108 for (size_t i
= 0; i
< num_ranges
; i
++) {
110 m_address_ranges
[i
].ContainsLoadAddress(pc_load_addr
, &GetTarget());
115 if (!ret_value
&& !m_given_ranges_only
) {
116 // See if we've just stepped to another part of the same line number...
117 StackFrame
*frame
= thread
.GetStackFrameAtIndex(0).get();
119 SymbolContext
new_context(
120 frame
->GetSymbolContext(eSymbolContextEverything
));
121 if (m_addr_context
.line_entry
.IsValid() &&
122 new_context
.line_entry
.IsValid()) {
123 if (m_addr_context
.line_entry
.original_file
==
124 new_context
.line_entry
.original_file
) {
125 if (m_addr_context
.line_entry
.line
== new_context
.line_entry
.line
) {
126 m_addr_context
= new_context
;
127 const bool include_inlined_functions
=
128 GetKind() == eKindStepOverRange
;
129 AddRange(m_addr_context
.line_entry
.GetSameLineContiguousAddressRange(
130 include_inlined_functions
));
134 m_addr_context
.line_entry
.Dump(&s
, &GetTarget(), true,
135 Address::DumpStyleLoadAddress
,
136 Address::DumpStyleLoadAddress
, true);
140 "Step range plan stepped to another range of same line: %s",
143 } else if (new_context
.line_entry
.line
== 0) {
144 new_context
.line_entry
.line
= m_addr_context
.line_entry
.line
;
145 m_addr_context
= new_context
;
146 const bool include_inlined_functions
=
147 GetKind() == eKindStepOverRange
;
148 AddRange(m_addr_context
.line_entry
.GetSameLineContiguousAddressRange(
149 include_inlined_functions
));
153 m_addr_context
.line_entry
.Dump(&s
, &GetTarget(), true,
154 Address::DumpStyleLoadAddress
,
155 Address::DumpStyleLoadAddress
, true);
158 "Step range plan stepped to a range at linenumber 0 "
159 "stepping through that range: %s",
162 } else if (new_context
.line_entry
.range
.GetBaseAddress().GetLoadAddress(
163 &GetTarget()) != pc_load_addr
) {
164 // Another thing that sometimes happens here is that we step out of
165 // one line into the MIDDLE of another line. So far I mostly see
166 // this due to bugs in the debug information. But we probably don't
167 // want to be in the middle of a line range, so in that case reset
168 // the stepping range to the line we've stepped into the middle of
170 m_addr_context
= new_context
;
171 m_address_ranges
.clear();
172 AddRange(m_addr_context
.line_entry
.range
);
176 m_addr_context
.line_entry
.Dump(&s
, &GetTarget(), true,
177 Address::DumpStyleLoadAddress
,
178 Address::DumpStyleLoadAddress
, true);
181 "Step range plan stepped to the middle of new "
182 "line(%d): %s, continuing to clear this line.",
183 new_context
.line_entry
.line
, s
.GetData());
190 if (!ret_value
&& log
)
191 LLDB_LOGF(log
, "Step range plan out of range to 0x%" PRIx64
, pc_load_addr
);
196 bool ThreadPlanStepRange::InSymbol() {
197 lldb::addr_t cur_pc
= GetThread().GetRegisterContext()->GetPC();
198 if (m_addr_context
.function
!= nullptr) {
199 return m_addr_context
.function
->GetAddressRange().ContainsLoadAddress(
200 cur_pc
, &GetTarget());
201 } else if (m_addr_context
.symbol
&& m_addr_context
.symbol
->ValueIsAddress()) {
202 AddressRange
range(m_addr_context
.symbol
->GetAddressRef(),
203 m_addr_context
.symbol
->GetByteSize());
204 return range
.ContainsLoadAddress(cur_pc
, &GetTarget());
209 // FIXME: This should also handle inlining if we aren't going to do inlining in
213 // Ideally we should remember the whole stack frame list, and then compare that
214 // to the current list.
216 lldb::FrameComparison
ThreadPlanStepRange::CompareCurrentFrameToStartFrame() {
217 FrameComparison frame_order
;
218 Thread
&thread
= GetThread();
219 StackID cur_frame_id
= thread
.GetStackFrameAtIndex(0)->GetStackID();
221 if (cur_frame_id
== m_stack_id
) {
222 frame_order
= eFrameCompareEqual
;
223 } else if (cur_frame_id
< m_stack_id
) {
224 frame_order
= eFrameCompareYounger
;
226 StackFrameSP cur_parent_frame
= thread
.GetStackFrameAtIndex(1);
227 StackID cur_parent_id
;
228 if (cur_parent_frame
)
229 cur_parent_id
= cur_parent_frame
->GetStackID();
230 if (m_parent_stack_id
.IsValid() && cur_parent_id
.IsValid() &&
231 m_parent_stack_id
== cur_parent_id
)
232 frame_order
= eFrameCompareSameParent
;
234 frame_order
= eFrameCompareOlder
;
239 bool ThreadPlanStepRange::StopOthers() {
240 switch (m_stop_others
) {
241 case lldb::eOnlyThisThread
:
243 case lldb::eOnlyDuringStepping
:
244 // If there is a call in the range of the next branch breakpoint,
245 // then we should always run all threads, since a call can execute
246 // arbitrary code which might for instance take a lock that's held
247 // by another thread.
248 return !m_found_calls
;
249 case lldb::eAllThreads
:
252 llvm_unreachable("Unhandled run mode!");
255 InstructionList
*ThreadPlanStepRange::GetInstructionsForAddress(
256 lldb::addr_t addr
, size_t &range_index
, size_t &insn_offset
) {
257 size_t num_ranges
= m_address_ranges
.size();
258 for (size_t i
= 0; i
< num_ranges
; i
++) {
259 if (m_address_ranges
[i
].ContainsLoadAddress(addr
, &GetTarget())) {
260 // Some joker added a zero size range to the stepping range...
261 if (m_address_ranges
[i
].GetByteSize() == 0)
264 if (!m_instruction_ranges
[i
]) {
265 // Disassemble the address range given:
266 const char *plugin_name
= nullptr;
267 const char *flavor
= nullptr;
268 m_instruction_ranges
[i
] = Disassembler::DisassembleRange(
269 GetTarget().GetArchitecture(), plugin_name
, flavor
, GetTarget(),
270 m_address_ranges
[i
]);
272 if (!m_instruction_ranges
[i
])
275 // Find where we are in the instruction list as well. If we aren't at
276 // an instruction, return nullptr. In this case, we're probably lost,
277 // and shouldn't try to do anything fancy.
280 m_instruction_ranges
[i
]
281 ->GetInstructionList()
282 .GetIndexOfInstructionAtLoadAddress(addr
, GetTarget());
283 if (insn_offset
== UINT32_MAX
)
287 return &m_instruction_ranges
[i
]->GetInstructionList();
295 void ThreadPlanStepRange::ClearNextBranchBreakpoint() {
296 if (m_next_branch_bp_sp
) {
297 Log
*log
= GetLog(LLDBLog::Step
);
298 LLDB_LOGF(log
, "Removing next branch breakpoint: %d.",
299 m_next_branch_bp_sp
->GetID());
300 GetTarget().RemoveBreakpointByID(m_next_branch_bp_sp
->GetID());
301 m_next_branch_bp_sp
.reset();
302 m_could_not_resolve_hw_bp
= false;
303 m_found_calls
= false;
307 bool ThreadPlanStepRange::SetNextBranchBreakpoint() {
308 if (m_next_branch_bp_sp
)
311 Log
*log
= GetLog(LLDBLog::Step
);
312 // Stepping through ranges using breakpoints doesn't work yet, but with this
313 // off we fall back to instruction single stepping.
314 if (!m_use_fast_step
)
317 // clear the m_found_calls, we'll rediscover it for this range.
318 m_found_calls
= false;
320 lldb::addr_t cur_addr
= GetThread().GetRegisterContext()->GetPC();
321 // Find the current address in our address ranges, and fetch the disassembly
322 // if we haven't already:
325 InstructionList
*instructions
=
326 GetInstructionsForAddress(cur_addr
, range_index
, pc_index
);
327 if (instructions
== nullptr)
330 const bool ignore_calls
= GetKind() == eKindStepOverRange
;
331 uint32_t branch_index
= instructions
->GetIndexOfNextBranchInstruction(
332 pc_index
, ignore_calls
, &m_found_calls
);
333 Address run_to_address
;
335 // If we didn't find a branch, run to the end of the range.
336 if (branch_index
== UINT32_MAX
) {
337 uint32_t last_index
= instructions
->GetSize() - 1;
338 if (last_index
- pc_index
> 1) {
339 InstructionSP last_inst
=
340 instructions
->GetInstructionAtIndex(last_index
);
341 size_t last_inst_size
= last_inst
->GetOpcode().GetByteSize();
342 run_to_address
= last_inst
->GetAddress();
343 run_to_address
.Slide(last_inst_size
);
345 } else if (branch_index
- pc_index
> 1) {
347 instructions
->GetInstructionAtIndex(branch_index
)->GetAddress();
350 if (run_to_address
.IsValid()) {
351 const bool is_internal
= true;
352 m_next_branch_bp_sp
=
353 GetTarget().CreateBreakpoint(run_to_address
, is_internal
, false);
354 if (m_next_branch_bp_sp
) {
356 if (m_next_branch_bp_sp
->IsHardware() &&
357 !m_next_branch_bp_sp
->HasResolvedLocations())
358 m_could_not_resolve_hw_bp
= true;
361 lldb::break_id_t bp_site_id
= LLDB_INVALID_BREAK_ID
;
362 BreakpointLocationSP bp_loc
=
363 m_next_branch_bp_sp
->GetLocationAtIndex(0);
365 BreakpointSiteSP bp_site
= bp_loc
->GetBreakpointSite();
367 bp_site_id
= bp_site
->GetID();
371 "ThreadPlanStepRange::SetNextBranchBreakpoint - Setting "
372 "breakpoint %d (site %d) to run to address 0x%" PRIx64
,
373 m_next_branch_bp_sp
->GetID(), bp_site_id
,
374 run_to_address
.GetLoadAddress(&m_process
.GetTarget()));
377 m_next_branch_bp_sp
->SetThreadID(m_tid
);
378 m_next_branch_bp_sp
->SetBreakpointKind("next-branch-location");
388 bool ThreadPlanStepRange::NextRangeBreakpointExplainsStop(
389 lldb::StopInfoSP stop_info_sp
) {
390 Log
*log
= GetLog(LLDBLog::Step
);
391 if (!m_next_branch_bp_sp
)
394 break_id_t bp_site_id
= stop_info_sp
->GetValue();
395 BreakpointSiteSP bp_site_sp
=
396 m_process
.GetBreakpointSiteList().FindByID(bp_site_id
);
399 else if (!bp_site_sp
->IsBreakpointAtThisSite(m_next_branch_bp_sp
->GetID()))
402 // If we've hit the next branch breakpoint, then clear it.
403 size_t num_owners
= bp_site_sp
->GetNumberOfOwners();
404 bool explains_stop
= true;
405 // If all the owners are internal, then we are probably just stepping over
406 // this range from multiple threads, or multiple frames, so we want to
407 // continue. If one is not internal, then we should not explain the stop,
408 // and let the user breakpoint handle the stop.
409 for (size_t i
= 0; i
< num_owners
; i
++) {
410 if (!bp_site_sp
->GetOwnerAtIndex(i
)->GetBreakpoint().IsInternal()) {
411 explains_stop
= false;
416 "ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit "
417 "next range breakpoint which has %" PRIu64
418 " owners - explains stop: %u.",
419 (uint64_t)num_owners
, explains_stop
);
420 ClearNextBranchBreakpoint();
421 return explains_stop
;
425 bool ThreadPlanStepRange::WillStop() { return true; }
427 StateType
ThreadPlanStepRange::GetPlanRunState() {
428 if (m_next_branch_bp_sp
)
429 return eStateRunning
;
431 return eStateStepping
;
434 bool ThreadPlanStepRange::MischiefManaged() {
435 // If we have pushed some plans between ShouldStop & MischiefManaged, then
437 // I do this check first because we might have stepped somewhere that will
439 // thinking it needs to step past the end of that line. This happens, for
440 // instance, when stepping over inlined code that is in the middle of the
443 if (!m_no_more_plans
)
447 if (!IsPlanComplete()) {
451 FrameComparison frame_order
= CompareCurrentFrameToStartFrame();
452 done
= (frame_order
!= eFrameCompareOlder
) ? m_no_more_plans
: true;
457 Log
*log
= GetLog(LLDBLog::Step
);
458 LLDB_LOGF(log
, "Completed step through range plan.");
459 ClearNextBranchBreakpoint();
460 ThreadPlan::MischiefManaged();
467 bool ThreadPlanStepRange::IsPlanStale() {
468 Log
*log
= GetLog(LLDBLog::Step
);
469 FrameComparison frame_order
= CompareCurrentFrameToStartFrame();
471 if (frame_order
== eFrameCompareOlder
) {
473 LLDB_LOGF(log
, "ThreadPlanStepRange::IsPlanStale returning true, we've "
477 } else if (frame_order
== eFrameCompareEqual
&& InSymbol()) {
478 // If we are not in a place we should step through, we've gotten stale. One
479 // tricky bit here is that some stubs don't push a frame, so we should.
480 // check that we are in the same symbol.
482 // Set plan Complete when we reach next instruction just after the range
483 lldb::addr_t addr
= GetThread().GetRegisterContext()->GetPC() - 1;
484 size_t num_ranges
= m_address_ranges
.size();
485 for (size_t i
= 0; i
< num_ranges
; i
++) {
487 m_address_ranges
[i
].ContainsLoadAddress(addr
, &GetTarget());