LLDB mainline
ThreadPlanStepOverRange.cpp
Go to the documentation of this file.
1//===-- ThreadPlanStepOverRange.cpp ---------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
10#include "lldb/Symbol/Block.h"
15#include "lldb/Target/Process.h"
17#include "lldb/Target/Target.h"
18#include "lldb/Target/Thread.h"
23#include "lldb/Utility/Log.h"
24#include "lldb/Utility/Stream.h"
25
26using namespace lldb_private;
27using namespace lldb;
28
31
32// ThreadPlanStepOverRange: Step through a stack range, either stepping over or
33// into based on the value of \a type.
34
36 Thread &thread, const AddressRange &range,
37 const SymbolContext &addr_context, lldb::RunMode stop_others,
38 LazyBool step_out_avoids_code_without_debug_info)
40 "Step range stepping over", thread, range,
41 addr_context, stop_others),
43 m_first_resume(true), m_run_mode(stop_others) {
45 SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
46}
47
49
52 auto PrintFailureIfAny = [&]() {
53 if (m_status.Success())
54 return;
55 s->Printf(" failed (%s)", m_status.AsCString());
56 };
57
58 if (level == lldb::eDescriptionLevelBrief) {
59 s->PutCString("step over");
60 PrintFailureIfAny();
61 return;
62 }
63
64 s->PutCString("Stepping over");
65 bool printed_line_info = false;
66 if (m_addr_context.line_entry.IsValid()) {
67 s->PutCString(" line ");
68 m_addr_context.line_entry.DumpStopContext(s, false);
69 printed_line_info = true;
70 }
71
72 if (!printed_line_info || level == eDescriptionLevelVerbose) {
73 s->PutCString(" using ranges: ");
74 DumpRanges(s);
75 }
76
77 PrintFailureIfAny();
78
79 s->PutChar('.');
80}
81
83 LazyBool step_out_avoids_code_without_debug_info) {
84 bool avoid_nodebug = true;
85 switch (step_out_avoids_code_without_debug_info) {
86 case eLazyBoolYes:
87 avoid_nodebug = true;
88 break;
89 case eLazyBoolNo:
90 avoid_nodebug = false;
91 break;
93 avoid_nodebug = GetThread().GetStepOutAvoidsNoDebug();
94 break;
95 }
96 if (avoid_nodebug)
98 else
100 // Step Over plans should always avoid no-debug on step in. Seems like you
101 // shouldn't have to say this, but a tail call looks more like a step in that
102 // a step out, so we want to catch this case.
104}
105
107 const SymbolContext &context) {
108 if (Language *language = Language::FindPlugin(context.GetLanguage()))
109 if (std::optional<bool> maybe_equivalent =
110 language->AreEqualForFrameComparison(context, m_addr_context))
111 return *maybe_equivalent;
112 // Match as much as is specified in the m_addr_context: This is a fairly
113 // loose sanity check. Note, sometimes the target doesn't get filled in so I
114 // left out the target check. And sometimes the module comes in as the .o
115 // file from the inlined range, so I left that out too...
116 if (m_addr_context.comp_unit) {
117 if (m_addr_context.comp_unit != context.comp_unit)
118 return false;
119 if (m_addr_context.function) {
120 if (m_addr_context.function != context.function)
121 return false;
122 // It is okay to return to a different block of a straight function, we
123 // only have to be more careful if returning from one inlined block to
124 // another.
125 if (m_addr_context.block->GetInlinedFunctionInfo() == nullptr &&
126 context.block->GetInlinedFunctionInfo() == nullptr)
127 return true;
128 return m_addr_context.block == context.block;
129 }
130 }
131 // Fall back to symbol if we have no decision from comp_unit/function/block.
132 return m_addr_context.symbol && m_addr_context.symbol == context.symbol;
133}
134
136 if (!stop_others)
138}
139
141 Log *log = GetLog(LLDBLog::Step);
142 Thread &thread = GetThread();
143
144 if (log) {
145 StreamString s;
146 DumpAddress(s.AsRawOstream(), thread.GetRegisterContext()->GetPC(),
147 GetTarget().GetArchitecture().GetAddressByteSize());
148 LLDB_LOGF(log, "ThreadPlanStepOverRange reached %s.", s.GetData());
149 }
151
152 // If we're out of the range but in the same frame or in our caller's frame
153 // then we should stop. When stepping out we only stop others if we are
154 // forcing running one thread.
155 bool stop_others = (m_stop_others == lldb::eOnlyThisThread);
156 ThreadPlanSP new_plan_sp;
158 LLDB_LOGF(log, "ThreadPlanStepOverRange compare frame result: %d.",
159 frame_order);
160
161 if (frame_order == eFrameCompareOlder) {
162 // If we're in an older frame then we should stop.
163 //
164 // A caveat to this is if we think the frame is older but we're actually in
165 // a trampoline.
166 // I'm going to make the assumption that you wouldn't RETURN to a
167 // trampoline. So if we are in a trampoline we think the frame is older
168 // because the trampoline confused the backtracer. As below, we step
169 // through first, and then try to figure out how to get back out again.
170
171 new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false,
172 stop_others, m_status);
173
174 if (new_plan_sp && log)
175 LLDB_LOGF(log,
176 "Thought I stepped out, but in fact arrived at a trampoline.");
177 } else if (frame_order == eFrameCompareYounger) {
178 // Make sure we really are in a new frame. Do that by unwinding and seeing
179 // if the start function really is our start function...
180 for (uint32_t i = 1;; ++i) {
181 StackFrameSP older_frame_sp = thread.GetStackFrameAtIndex(i);
182 if (!older_frame_sp) {
183 // We can't unwind the next frame we should just get out of here &
184 // stop...
185 break;
186 }
187
188 const SymbolContext &older_context =
189 older_frame_sp->GetSymbolContext(eSymbolContextEverything);
190 if (IsEquivalentContext(older_context)) {
191 // If we have the next-branch-breakpoint in the range, we can just
192 // rely on that breakpoint to trigger once we return to the range.
194 return false;
195 new_plan_sp = thread.QueueThreadPlanForStepOutNoShouldStop(
196 false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
197 m_status, true);
198 break;
199 } else {
200 new_plan_sp = thread.QueueThreadPlanForStepThrough(
201 m_stack_id, false, stop_others, m_status);
202 // If we found a way through, then we should stop recursing.
203 if (new_plan_sp)
204 break;
205 }
206 }
207 } else {
208 // If we're still in the range, keep going.
209 if (InRange()) {
211 return false;
212 }
213
214 if (!InSymbol()) {
215 // This one is a little tricky. Sometimes we may be in a stub or
216 // something similar, in which case we need to get out of there. But if
217 // we are in a stub then it's likely going to be hard to get out from
218 // here. It is probably easiest to step into the stub, and then it will
219 // be straight-forward to step out.
220 new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false,
221 stop_others, m_status);
222 } else {
223 // The current clang (at least through 424) doesn't always get the
224 // address range for the DW_TAG_inlined_subroutines right, so that when
225 // you leave the inlined range the line table says you are still in the
226 // source file of the inlining function. This is bad, because now you
227 // are missing the stack frame for the function containing the inlining,
228 // and if you sensibly do "finish" to get out of this function you will
229 // instead exit the containing function. To work around this, we check
230 // whether we are still in the source file we started in, and if not
231 // assume it is an error, and push a plan to get us out of this line and
232 // back to the containing file.
233
234 if (m_addr_context.line_entry.IsValid()) {
235 SymbolContext sc;
236 StackFrameSP frame_sp = thread.GetStackFrameAtIndex(0);
237 sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
238 if (sc.line_entry.IsValid()) {
239 if (!sc.line_entry.original_file_sp->Equal(
240 *m_addr_context.line_entry.original_file_sp,
242 sc.comp_unit == m_addr_context.comp_unit &&
243 sc.function == m_addr_context.function) {
244 // Okay, find the next occurrence of this file in the line table:
245 LineTable *line_table = m_addr_context.comp_unit->GetLineTable();
246 if (line_table) {
247 Address cur_address = frame_sp->GetFrameCodeAddress();
248 uint32_t entry_idx;
249 LineEntry line_entry;
250 if (line_table->FindLineEntryByAddress(cur_address, line_entry,
251 &entry_idx)) {
252 LineEntry next_line_entry;
253 bool step_past_remaining_inline = false;
254 if (entry_idx > 0) {
255 // We require the previous line entry and the current line
256 // entry come from the same file. The other requirement is
257 // that the previous line table entry be part of an inlined
258 // block, we don't want to step past cases where people have
259 // inlined some code fragment by using #include <source-
260 // fragment.c> directly.
261 LineEntry prev_line_entry;
262 if (line_table->GetLineEntryAtIndex(entry_idx - 1,
263 prev_line_entry) &&
264 prev_line_entry.original_file_sp->Equal(
265 *line_entry.original_file_sp,
267 SymbolContext prev_sc;
268 Address prev_address =
269 prev_line_entry.range.GetBaseAddress();
270 prev_address.CalculateSymbolContext(&prev_sc);
271 if (prev_sc.block) {
272 Block *inlined_block =
274 if (inlined_block) {
275 AddressRange inline_range;
276 inlined_block->GetRangeContainingAddress(prev_address,
277 inline_range);
278 if (!inline_range.ContainsFileAddress(cur_address)) {
279
280 step_past_remaining_inline = true;
281 }
282 }
283 }
284 }
285 }
286
287 if (step_past_remaining_inline) {
288 uint32_t look_ahead_step = 1;
289 while (line_table->GetLineEntryAtIndex(
290 entry_idx + look_ahead_step, next_line_entry)) {
291 // Make sure we haven't wandered out of the function we
292 // started from...
293 Address next_line_address =
294 next_line_entry.range.GetBaseAddress();
295 Function *next_line_function =
296 next_line_address.CalculateSymbolContextFunction();
297 if (next_line_function != m_addr_context.function)
298 break;
299
300 if (next_line_entry.original_file_sp->Equal(
301 *m_addr_context.line_entry.original_file_sp,
303 const bool abort_other_plans = false;
304 const RunMode stop_other_threads = RunMode::eAllThreads;
305 lldb::addr_t cur_pc = thread.GetStackFrameAtIndex(0)
306 ->GetRegisterContext()
307 ->GetPC();
308 AddressRange step_range(
309 cur_pc,
310 next_line_address.GetLoadAddress(&GetTarget()) -
311 cur_pc);
312
313 new_plan_sp = thread.QueueThreadPlanForStepOverRange(
314 abort_other_plans, step_range, sc, stop_other_threads,
315 m_status);
316 break;
317 }
318 look_ahead_step++;
319 }
320 }
321 }
322 }
323 }
324 }
325 }
326 }
327 }
328
329 // If we get to this point, we're not going to use a previously set "next
330 // branch" breakpoint, so delete it:
332
333 // If we haven't figured out something to do yet, then ask the ShouldStopHere
334 // callback:
335 if (!new_plan_sp) {
336 new_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order, m_status);
337 }
338
339 if (!new_plan_sp)
340 m_no_more_plans = true;
341 else {
342 // Any new plan will be an implementation plan, so mark it private:
343 new_plan_sp->SetPrivate(true);
344 m_no_more_plans = false;
345 }
346
347 if (!new_plan_sp) {
348 // For efficiencies sake, we know we're done here so we don't have to do
349 // this calculation again in MischiefManaged.
350 SetPlanComplete(m_status.Success());
351 return true;
352 } else
353 return false;
354}
355
361
363 // For crashes, breakpoint hits, signals, etc, let the base plan (or some
364 // plan above us) handle the stop. That way the user can see the stop, step
365 // around, and then when they are done, continue and have their step
366 // complete. The exception is if we've hit our "run to next branch"
367 // breakpoint. Note, unlike the step in range plan, we don't mark ourselves
368 // complete if we hit an unexplained breakpoint/crash.
369
370 Log *log = GetLog(LLDBLog::Step);
371 StopInfoSP stop_info_sp = GetPrivateStopInfo();
372 bool return_value;
373
374 if (stop_info_sp) {
375 StopReason reason = stop_info_sp->GetStopReason();
376
377 if (reason == eStopReasonTrace) {
378 return_value = true;
379 } else if (reason == eStopReasonBreakpoint) {
380 return_value = NextRangeBreakpointExplainsStop(stop_info_sp);
381 } else {
382 if (log)
383 log->PutCString("ThreadPlanStepOverRange got asked if it explains the "
384 "stop for some reason other than step.");
385 return_value = false;
386 }
387 } else
388 return_value = true;
389
390 return return_value;
391}
392
394 bool current_plan) {
395 if (resume_state != eStateSuspended && m_first_resume) {
396 m_first_resume = false;
397 if (resume_state == eStateStepping && current_plan) {
398 Thread &thread = GetThread();
399 // See if we are about to step over an inlined call in the middle of the
400 // inlined stack, if so figure out its extents and reset our range to
401 // step over that.
402 bool in_inlined_stack = thread.DecrementCurrentInlinedDepth();
403 if (in_inlined_stack) {
404 Log *log = GetLog(LLDBLog::Step);
405 LLDB_LOGF(log,
406 "ThreadPlanStepOverRange::DoWillResume: adjusting range to "
407 "the frame at inlined depth %d.",
408 thread.GetCurrentInlinedDepth());
409 StackFrameSP stack_sp = thread.GetStackFrameAtIndex(0);
410 if (stack_sp) {
411 Block *frame_block = stack_sp->GetFrameBlock();
412 lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC();
413 AddressRange my_range;
414 if (frame_block->GetRangeContainingLoadAddress(
415 curr_pc, m_process.GetTarget(), my_range)) {
416 m_address_ranges.clear();
417 m_address_ranges.push_back(my_range);
418 if (log) {
419 StreamString s;
420 const InlineFunctionInfo *inline_info =
421 frame_block->GetInlinedFunctionInfo();
422 const char *name;
423 if (inline_info)
424 name = inline_info->GetName().AsCString("");
425 else
426 name = "<unknown-notinlined>";
427
428 s.Printf(
429 "Stepping over inlined function \"%s\" in inlined stack: ",
430 name);
431 DumpRanges(&s);
432 log->PutString(s.GetString());
433 }
434 }
435 }
436 }
437 }
438 }
441 return true;
442}
#define LLDB_LOGF(log,...)
Definition Log.h:389
A section + offset based address range class.
Address & GetBaseAddress()
Get accessor for the base address of the range.
bool ContainsFileAddress(const Address &so_addr) const
Check if a section offset address is contained in this range.
A section + offset based address class.
Definition Address.h:62
lldb::addr_t GetLoadAddress(Target *target) const
Get the load address.
Definition Address.cpp:301
uint32_t CalculateSymbolContext(SymbolContext *sc, lldb::SymbolContextItem resolve_scope=lldb::eSymbolContextEverything) const
Reconstruct a symbol context from an address.
Definition Address.cpp:819
Function * CalculateSymbolContextFunction() const
Definition Address.cpp:859
A class that describes a single lexical block.
Definition Block.h:41
Block * GetContainingInlinedBlock()
Get the inlined block that contains this block.
Definition Block.cpp:206
const InlineFunctionInfo * GetInlinedFunctionInfo() const
Get const accessor for any inlined function information.
Definition Block.h:268
bool GetRangeContainingAddress(const Address &addr, AddressRange &range)
Definition Block.cpp:248
bool GetRangeContainingLoadAddress(lldb::addr_t load_addr, Target &target, AddressRange &range)
Definition Block.cpp:266
const char * AsCString(const char *value_if_empty) const
Get the string value as a C string.
ValueType Clear(ValueType mask=~static_cast< ValueType >(0))
Clear one or more flags.
Definition Flags.h:61
ValueType Set(ValueType mask)
Set one or more flags by logical OR'ing mask with the current flags.
Definition Flags.h:73
A class that describes a function.
Definition Function.h:377
A class that describes information for an inlined function.
Definition Function.h:119
ConstString GetName() const
Definition Function.cpp:93
static Language * FindPlugin(lldb::LanguageType language)
Definition Language.cpp:84
A line table class.
Definition LineTable.h:25
bool FindLineEntryByAddress(const Address &so_addr, LineEntry &line_entry, uint32_t *index_ptr=nullptr)
Find a line entry that contains the section offset address so_addr.
bool GetLineEntryAtIndex(uint32_t idx, LineEntry &line_entry)
Get the line entry from the line table at index idx.
void PutCString(const char *cstr)
Definition Log.cpp:162
void PutString(llvm::StringRef str)
Definition Log.cpp:164
const char * GetData() const
llvm::StringRef GetString() const
A stream class that can stream formatted output to a file.
Definition Stream.h:28
llvm::raw_ostream & AsRawOstream()
Returns a raw_ostream that forwards the data to this Stream object.
Definition Stream.h:405
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition Stream.cpp:63
size_t PutChar(char ch)
Definition Stream.cpp:131
Defines a symbol context baton that can be handed other debug core functions.
lldb::LanguageType GetLanguage() const
Function * function
The Function for a given query.
Block * block
The Block for a given query.
CompileUnit * comp_unit
The CompileUnit for a given query.
Symbol * symbol
The Symbol for a given query.
LineEntry line_entry
The LineEntry for a given query.
lldb::ThreadPlanSP CheckShouldStopHereAndQueueStepOut(lldb::FrameComparison operation, Status &status)
bool DoPlanExplainsStop(Event *event_ptr) override
void GetDescription(Stream *s, lldb::DescriptionLevel level) override
Print a description of this thread to the stream s.
ThreadPlanStepOverRange(Thread &thread, const AddressRange &range, const SymbolContext &addr_context, lldb::RunMode stop_others, LazyBool step_out_avoids_no_debug)
void SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info)
bool IsEquivalentContext(const SymbolContext &context)
bool DoWillResume(lldb::StateType resume_state, bool current_plan) override
bool NextRangeBreakpointExplainsStop(lldb::StopInfoSP stop_info_sp)
lldb::FrameComparison CompareCurrentFrameToStartFrame()
ThreadPlanStepRange(ThreadPlanKind kind, const char *name, Thread &thread, const AddressRange &range, const SymbolContext &addr_context, lldb::RunMode stop_others, bool given_ranges_only=false)
std::vector< AddressRange > m_address_ranges
void SetPlanComplete(bool success=true)
Thread & GetThread()
Returns the Thread that is using this thread plan.
lldb::StopInfoSP GetPrivateStopInfo()
Definition ThreadPlan.h:544
bool GetStepOutAvoidsNoDebug() const
Definition Thread.cpp:141
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:338
void DumpAddress(llvm::raw_ostream &s, uint64_t addr, uint32_t addr_size, const char *prefix=nullptr, const char *suffix=nullptr)
Output an address value to this stream.
Definition Stream.cpp:108
std::shared_ptr< lldb_private::ThreadPlan > ThreadPlanSP
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
DescriptionLevel
Description levels for "void GetDescription(Stream *, DescriptionLevel)" calls.
@ eDescriptionLevelBrief
@ eDescriptionLevelVerbose
FrameComparison
This is the return value for frame comparisons.
StateType
Process and Thread States.
@ eStateSuspended
Process or thread is in a suspended state as far as the debugger is concerned while other processes o...
@ eStateStepping
Process or thread is in the process of stepping and can not be examined.
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
uint64_t addr_t
Definition lldb-types.h:80
StopReason
Thread stop reasons.
@ eStopReasonBreakpoint
RunMode
Thread Run Modes.
A line table entry class.
Definition LineEntry.h:21
bool IsValid() const
Check if a line entry object is valid.
Definition LineEntry.cpp:35
AddressRange range
The section offset address range for this line entry.
Definition LineEntry.h:137
SupportFileNSP original_file_sp
The original source file, from debug info.
Definition LineEntry.h:147