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_sp
->Equal(
124 *new_context
.line_entry
.original_file_sp
,
125 SupportFile::eEqualFileSpecAndChecksumIfSet
)) {
126 if (m_addr_context
.line_entry
.line
== new_context
.line_entry
.line
) {
127 m_addr_context
= new_context
;
128 const bool include_inlined_functions
=
129 GetKind() == eKindStepOverRange
;
130 AddRange(m_addr_context
.line_entry
.GetSameLineContiguousAddressRange(
131 include_inlined_functions
));
135 m_addr_context
.line_entry
.Dump(&s
, &GetTarget(), true,
136 Address::DumpStyleLoadAddress
,
137 Address::DumpStyleLoadAddress
, true);
141 "Step range plan stepped to another range of same line: %s",
144 } else if (new_context
.line_entry
.line
== 0) {
145 new_context
.line_entry
.line
= m_addr_context
.line_entry
.line
;
146 m_addr_context
= new_context
;
147 const bool include_inlined_functions
=
148 GetKind() == eKindStepOverRange
;
149 AddRange(m_addr_context
.line_entry
.GetSameLineContiguousAddressRange(
150 include_inlined_functions
));
154 m_addr_context
.line_entry
.Dump(&s
, &GetTarget(), true,
155 Address::DumpStyleLoadAddress
,
156 Address::DumpStyleLoadAddress
, true);
159 "Step range plan stepped to a range at linenumber 0 "
160 "stepping through that range: %s",
163 } else if (new_context
.line_entry
.range
.GetBaseAddress().GetLoadAddress(
164 &GetTarget()) != pc_load_addr
) {
165 // Another thing that sometimes happens here is that we step out of
166 // one line into the MIDDLE of another line. So far I mostly see
167 // this due to bugs in the debug information. But we probably don't
168 // want to be in the middle of a line range, so in that case reset
169 // the stepping range to the line we've stepped into the middle of
171 m_addr_context
= new_context
;
172 m_address_ranges
.clear();
173 AddRange(m_addr_context
.line_entry
.range
);
177 m_addr_context
.line_entry
.Dump(&s
, &GetTarget(), true,
178 Address::DumpStyleLoadAddress
,
179 Address::DumpStyleLoadAddress
, true);
182 "Step range plan stepped to the middle of new "
183 "line(%d): %s, continuing to clear this line.",
184 new_context
.line_entry
.line
, s
.GetData());
191 if (!ret_value
&& log
)
192 LLDB_LOGF(log
, "Step range plan out of range to 0x%" PRIx64
, pc_load_addr
);
197 bool ThreadPlanStepRange::InSymbol() {
198 lldb::addr_t cur_pc
= GetThread().GetRegisterContext()->GetPC();
199 if (m_addr_context
.function
!= nullptr) {
200 return m_addr_context
.function
->GetAddressRange().ContainsLoadAddress(
201 cur_pc
, &GetTarget());
202 } else if (m_addr_context
.symbol
&& m_addr_context
.symbol
->ValueIsAddress()) {
203 AddressRange
range(m_addr_context
.symbol
->GetAddressRef(),
204 m_addr_context
.symbol
->GetByteSize());
205 return range
.ContainsLoadAddress(cur_pc
, &GetTarget());
210 // FIXME: This should also handle inlining if we aren't going to do inlining in
214 // Ideally we should remember the whole stack frame list, and then compare that
215 // to the current list.
217 lldb::FrameComparison
ThreadPlanStepRange::CompareCurrentFrameToStartFrame() {
218 FrameComparison frame_order
;
219 Thread
&thread
= GetThread();
220 StackID cur_frame_id
= thread
.GetStackFrameAtIndex(0)->GetStackID();
222 if (cur_frame_id
== m_stack_id
) {
223 frame_order
= eFrameCompareEqual
;
224 } else if (cur_frame_id
< m_stack_id
) {
225 frame_order
= eFrameCompareYounger
;
227 StackFrameSP cur_parent_frame
= thread
.GetStackFrameAtIndex(1);
228 StackID cur_parent_id
;
229 if (cur_parent_frame
)
230 cur_parent_id
= cur_parent_frame
->GetStackID();
231 if (m_parent_stack_id
.IsValid() && cur_parent_id
.IsValid() &&
232 m_parent_stack_id
== cur_parent_id
)
233 frame_order
= eFrameCompareSameParent
;
235 frame_order
= eFrameCompareOlder
;
240 bool ThreadPlanStepRange::StopOthers() {
241 switch (m_stop_others
) {
242 case lldb::eOnlyThisThread
:
244 case lldb::eOnlyDuringStepping
:
245 // If there is a call in the range of the next branch breakpoint,
246 // then we should always run all threads, since a call can execute
247 // arbitrary code which might for instance take a lock that's held
248 // by another thread.
249 return !m_found_calls
;
250 case lldb::eAllThreads
:
253 llvm_unreachable("Unhandled run mode!");
256 InstructionList
*ThreadPlanStepRange::GetInstructionsForAddress(
257 lldb::addr_t addr
, size_t &range_index
, size_t &insn_offset
) {
258 size_t num_ranges
= m_address_ranges
.size();
259 for (size_t i
= 0; i
< num_ranges
; i
++) {
260 if (m_address_ranges
[i
].ContainsLoadAddress(addr
, &GetTarget())) {
261 // Some joker added a zero size range to the stepping range...
262 if (m_address_ranges
[i
].GetByteSize() == 0)
265 if (!m_instruction_ranges
[i
]) {
266 // Disassemble the address range given:
267 const char *plugin_name
= nullptr;
268 const char *flavor
= nullptr;
269 const char *cpu
= nullptr;
270 const char *features
= nullptr;
271 m_instruction_ranges
[i
] = Disassembler::DisassembleRange(
272 GetTarget().GetArchitecture(), plugin_name
, flavor
, cpu
, features
,
273 GetTarget(), m_address_ranges
[i
]);
275 if (!m_instruction_ranges
[i
])
278 // Find where we are in the instruction list as well. If we aren't at
279 // an instruction, return nullptr. In this case, we're probably lost,
280 // and shouldn't try to do anything fancy.
283 m_instruction_ranges
[i
]
284 ->GetInstructionList()
285 .GetIndexOfInstructionAtLoadAddress(addr
, GetTarget());
286 if (insn_offset
== UINT32_MAX
)
290 return &m_instruction_ranges
[i
]->GetInstructionList();
298 bool ThreadPlanStepRange::IsNextBranchBreakpointStop(StopInfoSP stop_info_sp
) {
299 if (!m_next_branch_bp_sp
)
302 break_id_t bp_site_id
= stop_info_sp
->GetValue();
303 BreakpointSiteSP bp_site_sp
=
304 m_process
.GetBreakpointSiteList().FindByID(bp_site_id
);
307 else if (!bp_site_sp
->IsBreakpointAtThisSite(m_next_branch_bp_sp
->GetID()))
312 void ThreadPlanStepRange::ClearNextBranchBreakpoint() {
313 if (m_next_branch_bp_sp
) {
314 Log
*log
= GetLog(LLDBLog::Step
);
315 LLDB_LOGF(log
, "Removing next branch breakpoint: %d.",
316 m_next_branch_bp_sp
->GetID());
317 GetTarget().RemoveBreakpointByID(m_next_branch_bp_sp
->GetID());
318 m_next_branch_bp_sp
.reset();
319 m_could_not_resolve_hw_bp
= false;
320 m_found_calls
= false;
324 void ThreadPlanStepRange::ClearNextBranchBreakpointExplainedStop() {
325 if (IsNextBranchBreakpointStop(GetPrivateStopInfo()))
326 ClearNextBranchBreakpoint();
329 bool ThreadPlanStepRange::SetNextBranchBreakpoint() {
330 if (m_next_branch_bp_sp
)
333 Log
*log
= GetLog(LLDBLog::Step
);
334 // Stepping through ranges using breakpoints doesn't work yet, but with this
335 // off we fall back to instruction single stepping.
336 if (!m_use_fast_step
)
339 // clear the m_found_calls, we'll rediscover it for this range.
340 m_found_calls
= false;
342 lldb::addr_t cur_addr
= GetThread().GetRegisterContext()->GetPC();
343 // Find the current address in our address ranges, and fetch the disassembly
344 // if we haven't already:
347 InstructionList
*instructions
=
348 GetInstructionsForAddress(cur_addr
, range_index
, pc_index
);
349 if (instructions
== nullptr)
352 const bool ignore_calls
= GetKind() == eKindStepOverRange
;
353 uint32_t branch_index
= instructions
->GetIndexOfNextBranchInstruction(
354 pc_index
, ignore_calls
, &m_found_calls
);
355 Address run_to_address
;
357 // If we didn't find a branch, run to the end of the range.
358 if (branch_index
== UINT32_MAX
) {
359 uint32_t last_index
= instructions
->GetSize() - 1;
360 if (last_index
- pc_index
> 1) {
361 InstructionSP last_inst
=
362 instructions
->GetInstructionAtIndex(last_index
);
363 size_t last_inst_size
= last_inst
->GetOpcode().GetByteSize();
364 run_to_address
= last_inst
->GetAddress();
365 run_to_address
.Slide(last_inst_size
);
367 } else if (branch_index
- pc_index
> 1) {
369 instructions
->GetInstructionAtIndex(branch_index
)->GetAddress();
371 if (branch_index
== pc_index
)
372 LLDB_LOGF(log
, "ThreadPlanStepRange::SetNextBranchBreakpoint - skipping "
373 "because current is branch instruction");
374 if (run_to_address
.IsValid()) {
375 const bool is_internal
= true;
376 m_next_branch_bp_sp
=
377 GetTarget().CreateBreakpoint(run_to_address
, is_internal
, false);
378 if (m_next_branch_bp_sp
) {
380 if (m_next_branch_bp_sp
->IsHardware() &&
381 !m_next_branch_bp_sp
->HasResolvedLocations())
382 m_could_not_resolve_hw_bp
= true;
384 BreakpointLocationSP bp_loc
=
385 m_next_branch_bp_sp
->GetLocationAtIndex(0);
387 lldb::break_id_t bp_site_id
= LLDB_INVALID_BREAK_ID
;
389 BreakpointSiteSP bp_site
= bp_loc
->GetBreakpointSite();
391 bp_site_id
= bp_site
->GetID();
395 "ThreadPlanStepRange::SetNextBranchBreakpoint - Setting "
396 "breakpoint %d (site %d) to run to address 0x%" PRIx64
,
397 m_next_branch_bp_sp
->GetID(), bp_site_id
,
398 run_to_address
.GetLoadAddress(&m_process
.GetTarget()));
400 // The "next branch breakpoint might land on a virtual inlined call
401 // stack. If that's true, we should always stop at the top of the
402 // inlined call stack. Only virtual steps should walk deeper into the
403 // inlined call stack.
404 Block
*block
= run_to_address
.CalculateSymbolContextBlock();
405 if (bp_loc
&& block
) {
406 LineEntry top_most_line_entry
;
407 lldb::addr_t run_to_addr
= run_to_address
.GetFileAddress();
408 for (Block
*inlined_parent
= block
->GetContainingInlinedBlock();
410 inlined_parent
= inlined_parent
->GetInlinedParent()) {
412 if (!inlined_parent
->GetRangeContainingAddress(run_to_address
,
415 Address range_start_address
= range
.GetBaseAddress();
416 // Only compare addresses here, we may have different symbol
417 // contexts (for virtual inlined stacks), but we just want to know
418 // that they are all at the same address.
419 if (range_start_address
.GetFileAddress() != run_to_addr
)
421 const InlineFunctionInfo
*inline_info
=
422 inlined_parent
->GetInlinedFunctionInfo();
425 const Declaration
&call_site
= inline_info
->GetCallSite();
426 top_most_line_entry
.line
= call_site
.GetLine();
427 top_most_line_entry
.column
= call_site
.GetColumn();
428 FileSpec call_site_file_spec
= call_site
.GetFile();
429 top_most_line_entry
.original_file_sp
.reset(
430 new SupportFile(call_site_file_spec
));
431 top_most_line_entry
.range
= range
;
432 top_most_line_entry
.file_sp
.reset();
433 top_most_line_entry
.ApplyFileMappings(
434 GetThread().CalculateTarget());
435 if (!top_most_line_entry
.file_sp
)
436 top_most_line_entry
.file_sp
=
437 top_most_line_entry
.original_file_sp
;
439 if (top_most_line_entry
.IsValid()) {
440 LLDB_LOG(log
, "Setting preferred line entry: {0}:{1}",
441 top_most_line_entry
.GetFile(), top_most_line_entry
.line
);
442 bp_loc
->SetPreferredLineEntry(top_most_line_entry
);
445 m_next_branch_bp_sp
->SetThreadID(m_tid
);
446 m_next_branch_bp_sp
->SetBreakpointKind("next-branch-location");
452 LLDB_LOGF(log
, "ThreadPlanStepRange::SetNextBranchBreakpoint - skipping "
453 "invalid run_to_address");
458 bool ThreadPlanStepRange::NextRangeBreakpointExplainsStop(
459 lldb::StopInfoSP stop_info_sp
) {
460 if (!IsNextBranchBreakpointStop(stop_info_sp
))
463 break_id_t bp_site_id
= stop_info_sp
->GetValue();
464 BreakpointSiteSP bp_site_sp
=
465 m_process
.GetBreakpointSiteList().FindByID(bp_site_id
);
469 // If we've hit the next branch breakpoint, then clear it.
470 size_t num_constituents
= bp_site_sp
->GetNumberOfConstituents();
471 bool explains_stop
= true;
472 // If all the constituents are internal, then we are probably just stepping
473 // over this range from multiple threads, or multiple frames, so we want to
474 // continue. If one is not internal, then we should not explain the stop,
475 // and let the user breakpoint handle the stop.
476 for (size_t i
= 0; i
< num_constituents
; i
++) {
477 if (!bp_site_sp
->GetConstituentAtIndex(i
)->GetBreakpoint().IsInternal()) {
478 explains_stop
= false;
482 Log
*log
= GetLog(LLDBLog::Step
);
484 "ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit "
485 "next range breakpoint which has %" PRIu64
486 " constituents - explains stop: %u.",
487 (uint64_t)num_constituents
, explains_stop
);
488 return explains_stop
;
491 bool ThreadPlanStepRange::WillStop() { return true; }
493 StateType
ThreadPlanStepRange::GetPlanRunState() {
494 if (m_next_branch_bp_sp
)
495 return eStateRunning
;
497 return eStateStepping
;
500 bool ThreadPlanStepRange::MischiefManaged() {
501 // If we have pushed some plans between ShouldStop & MischiefManaged, then
503 // I do this check first because we might have stepped somewhere that will
505 // thinking it needs to step past the end of that line. This happens, for
506 // instance, when stepping over inlined code that is in the middle of the
509 if (!m_no_more_plans
)
513 if (!IsPlanComplete()) {
517 FrameComparison frame_order
= CompareCurrentFrameToStartFrame();
518 done
= (frame_order
!= eFrameCompareOlder
) ? m_no_more_plans
: true;
523 Log
*log
= GetLog(LLDBLog::Step
);
524 LLDB_LOGF(log
, "Completed step through range plan.");
525 ClearNextBranchBreakpoint();
526 ThreadPlan::MischiefManaged();
533 bool ThreadPlanStepRange::IsPlanStale() {
534 Log
*log
= GetLog(LLDBLog::Step
);
535 FrameComparison frame_order
= CompareCurrentFrameToStartFrame();
537 if (frame_order
== eFrameCompareOlder
) {
539 LLDB_LOGF(log
, "ThreadPlanStepRange::IsPlanStale returning true, we've "
543 } else if (frame_order
== eFrameCompareEqual
&& InSymbol()) {
544 // If we are not in a place we should step through, we've gotten stale. One
545 // tricky bit here is that some stubs don't push a frame, so we should.
546 // check that we are in the same symbol.
548 // Set plan Complete when we reach next instruction just after the range
549 lldb::addr_t addr
= GetThread().GetRegisterContext()->GetPC() - 1;
550 size_t num_ranges
= m_address_ranges
.size();
551 for (size_t i
= 0; i
< num_ranges
; i
++) {
553 m_address_ranges
[i
].ContainsLoadAddress(addr
, &GetTarget());