LLDB mainline
ThreadPlanShouldStopHere.cpp
Go to the documentation of this file.
1//===-- ThreadPlanShouldStopHere.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/Symbol.h"
14#include "lldb/Target/Thread.h"
16#include "lldb/Utility/Log.h"
17
18using namespace lldb;
19using namespace lldb_private;
20
21// ThreadPlanShouldStopHere constructor
30
38
40
42 FrameComparison operation, Status &status) {
43 bool should_stop_here = true;
44 if (m_callbacks.should_stop_here_callback) {
45 should_stop_here = m_callbacks.should_stop_here_callback(
46 m_owner, m_flags, operation, status, m_baton);
47 Log *log = GetLog(LLDBLog::Step);
48 if (log) {
49 lldb::addr_t current_addr =
50 m_owner->GetThread().GetRegisterContext()->GetPC(0);
51
52 LLDB_LOGF(log, "ShouldStopHere callback returned %u from 0x%" PRIx64 ".",
53 should_stop_here, current_addr);
54 }
55 }
56
57 return should_stop_here;
58}
59
61 ThreadPlan *current_plan, Flags &flags, FrameComparison operation,
62 Status &status, void *baton) {
63 bool should_stop_here = true;
64 StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
65 if (!frame)
66 return true;
67
68 Log *log = GetLog(LLDBLog::Step);
69
70 if ((operation == eFrameCompareOlder && flags.Test(eStepOutAvoidNoDebug)) ||
71 (operation == eFrameCompareYounger && flags.Test(eStepInAvoidNoDebug)) ||
72 (operation == eFrameCompareSameParent &&
73 flags.Test(eStepInAvoidNoDebug))) {
74 if (!frame->HasDebugInformation()) {
75 LLDB_LOGF(log, "Stepping out of frame with no debug info");
76
77 should_stop_here = false;
78 }
79 }
80
81 // Check whether the frame we are in is a language runtime thunk, only for
82 // step out:
83 if (operation == eFrameCompareOlder) {
84 if (const Symbol *symbol =
85 frame->GetSymbolContext(eSymbolContextSymbol).symbol) {
86 ProcessSP process_sp(current_plan->GetThread().GetProcess());
87 for (auto *runtime : process_sp->GetLanguageRuntimes()) {
88 if (runtime->IsSymbolARuntimeThunk(*symbol) &&
91 log, "Stepping out past a language thunk %s for: %s",
92 frame->GetFunctionName(),
93 Language::GetNameForLanguageType(runtime->GetLanguageType()));
94 should_stop_here = false;
95 break;
96 }
97 }
98 }
99 }
100 // Source line stepping plans should always avoid code with line number 0.
101 // But trampoline plans should not; it's easier to reason about if they
102 // leave that up to the source line plan that's driving them.
103 // FIXME: At present the ShouldStop and the StepFromHere calculate this
104 // independently. If this ever becomes expensive (this one isn't) we can
105 // try to have this set a state that the StepFromHere can use.
107 SymbolContext sc;
108 sc = frame->GetSymbolContext(eSymbolContextLineEntry);
109 if (sc.line_entry.line == 0)
110 should_stop_here = false;
111 }
112
113 return should_stop_here;
114}
115
117 ThreadPlan *current_plan, Flags &flags, FrameComparison operation,
118 Status &status, void *baton) {
119 const bool stop_others = false;
120 const size_t frame_index = 0;
121 ThreadPlanSP return_plan_sp;
122 // If we are stepping through code at line number 0, then we need to step
123 // over this range. Otherwise we will step out.
124 Log *log = GetLog(LLDBLog::Step);
125
126 StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
127 if (!frame)
128 return return_plan_sp;
129 SymbolContext sc;
130 sc = frame->GetSymbolContext(eSymbolContextLineEntry | eSymbolContextSymbol);
131
132 if (sc.line_entry.line == 0) {
133 AddressRange range = sc.line_entry.range;
134 bool just_step_out = false;
135 if (sc.symbol) {
136 ProcessSP process_sp(current_plan->GetThread().GetProcess());
137
138 // If this is a runtime thunk, step through it, rather than stepping out
139 // because it's marked line 0.
140 bool is_thunk = false;
141 for (auto *runtime : process_sp->GetLanguageRuntimes()) {
142 if (runtime->IsSymbolARuntimeThunk(*sc.symbol) &&
144 LLDB_LOGF(
145 log, "Stepping out past a language thunk %s for: %s",
146 frame->GetFunctionName(),
147 Language::GetNameForLanguageType(runtime->GetLanguageType()));
148 is_thunk = true;
149 break;
150 }
151 }
152
153 // If the whole function is marked line 0 just step out, that's easier &
154 // faster than continuing to step through it.
155 // FIXME: This assumes that the function is a single line range. It could
156 // be a series of contiguous line 0 ranges. Check for that too.
157 if (!is_thunk && sc.symbol->ValueIsAddress()) {
158 Address symbol_end = sc.symbol->GetAddress();
159 symbol_end.Slide(sc.symbol->GetByteSize() - 1);
160 if (range.ContainsFileAddress(sc.symbol->GetAddress()) &&
161 range.ContainsFileAddress(symbol_end)) {
162 LLDB_LOGF(log, "Stopped in a function with only line 0 lines, just "
163 "stepping out.");
164 just_step_out = true;
165 }
166 }
167 }
168 if (!just_step_out) {
169 LLDB_LOGF(log, "ThreadPlanShouldStopHere::DefaultStepFromHereCallback "
170 "Queueing StepInRange plan to step through line 0 code.");
171
172 return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepInRange(
173 false, range, sc, llvm::StringRef(), eOnlyDuringStepping, status,
175 }
176 }
177
178 if (!return_plan_sp)
179 return_plan_sp =
181 false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion,
182 frame_index, status, true);
183 return return_plan_sp;
184}
185
188 Status &status) {
189 ThreadPlanSP return_plan_sp;
190 if (m_callbacks.step_from_here_callback) {
191 return_plan_sp = m_callbacks.step_from_here_callback(
192 m_owner, flags, operation, status, m_baton);
193 }
194 return return_plan_sp;
195}
196
198 lldb::FrameComparison operation, Status &status) {
199 if (!InvokeShouldStopHereCallback(operation, status))
200 return QueueStepOutFromHerePlan(m_flags, operation, status);
201 else
202 return ThreadPlanSP();
203}
#define LLDB_LOGF(log,...)
Definition Log.h:389
A section + offset based address range class.
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
bool Slide(int64_t offset)
Definition Address.h:446
A class to manage flags.
Definition Flags.h:22
bool Test(ValueType bit) const
Test a single flag bit.
Definition Flags.h:96
static const char * GetNameForLanguageType(lldb::LanguageType language)
Returns the internal LLDB name for the specified language.
Definition Language.cpp:305
This base class provides an interface to stack frames.
Definition StackFrame.h:44
virtual const char * GetFunctionName()
Get the frame's demangled name.
virtual const SymbolContext & GetSymbolContext(lldb::SymbolContextItem resolve_scope)
Provide a SymbolContext for this StackFrame's current pc value.
virtual bool HasDebugInformation()
Determine whether this StackFrame has debug information available or not.
An error handling class.
Definition Status.h:118
Defines a symbol context baton that can be handed other debug core functions.
Symbol * symbol
The Symbol for a given query.
LineEntry line_entry
The LineEntry for a given query.
bool ValueIsAddress() const
Definition Symbol.cpp:191
lldb::addr_t GetByteSize() const
Definition Symbol.cpp:469
Address GetAddress() const
Definition Symbol.h:102
virtual lldb::ThreadPlanSP QueueStepOutFromHerePlan(Flags &flags, lldb::FrameComparison operation, Status &status)
ThreadPlanShouldStopHereCallbacks m_callbacks
void SetShouldStopHereCallbacks(const ThreadPlanShouldStopHereCallbacks *callbacks, void *baton)
static bool DefaultShouldStopHereCallback(ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation, Status &status, void *baton)
static lldb::ThreadPlanSP DefaultStepFromHereCallback(ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation, Status &status, void *baton)
bool InvokeShouldStopHereCallback(lldb::FrameComparison operation, Status &status)
lldb::ThreadPlanSP CheckShouldStopHereAndQueueStepOut(lldb::FrameComparison operation, Status &status)
Thread & GetThread()
Returns the Thread that is using this thread plan.
virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx)
Definition Thread.h:435
lldb::ProcessSP GetProcess() const
Definition Thread.h:162
virtual lldb::ThreadPlanSP QueueThreadPlanForStepOutNoShouldStop(bool abort_other_plans, SymbolContext *addr_context, bool first_insn, bool stop_other_threads, Vote report_stop_vote, Vote report_run_vote, uint32_t frame_idx, Status &status, bool continue_to_next_branch=false)
Queue the plan used to step out of the function at the current PC of a thread.
Definition Thread.cpp:1385
virtual lldb::ThreadPlanSP QueueThreadPlanForStepInRange(bool abort_other_plans, const AddressRange &range, const SymbolContext &addr_context, llvm::StringRef step_in_target, lldb::RunMode stop_other_threads, Status &status, LazyBool step_in_avoids_code_without_debug_info=eLazyBoolCalculate, LazyBool step_out_avoids_code_without_debug_info=eLazyBoolCalculate)
Queues the plan used to step through an address range, stepping into functions.
Definition Thread.cpp:1342
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
std::shared_ptr< lldb_private::ThreadPlan > ThreadPlanSP
FrameComparison
This is the return value for frame comparisons.
@ eFrameCompareSameParent
std::shared_ptr< lldb_private::Process > ProcessSP
uint64_t addr_t
Definition lldb-types.h:80
@ eOnlyDuringStepping
AddressRange range
The section offset address range for this line entry.
Definition LineEntry.h:137
uint32_t line
The source line number, or LLDB_INVALID_LINE_NUMBER if there is no line number information.
Definition LineEntry.h:151