LLDB mainline
ThreadPlanStepUntil.cpp
Go to the documentation of this file.
1//===-- ThreadPlanStepUntil.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
13#include "lldb/Target/Process.h"
16#include "lldb/Target/Target.h"
18#include "lldb/Utility/Log.h"
19
20using namespace lldb;
21using namespace lldb_private;
22
23// ThreadPlanStepUntil: Run until we reach a given line number or step out of
24// the current frame
25
27 llvm::ArrayRef<addr_t> address_list,
28 bool stop_others, uint32_t frame_idx)
29 : ThreadPlan(ThreadPlan::eKindStepUntil, "Step until", thread,
31 m_step_from_insn(LLDB_INVALID_ADDRESS),
32 m_return_bp_id(LLDB_INVALID_BREAK_ID),
33 m_return_addr(LLDB_INVALID_ADDRESS), m_stepped_out(false),
34 m_should_stop(false), m_ran_analyze(false), m_explains_stop(false),
35 m_until_points(), m_stop_others(stop_others) {
36 StackFrameSP frame_sp(thread.GetStackFrameAtIndex(frame_idx));
37 if (!frame_sp)
38 return;
39
40 m_step_from_insn = frame_sp->GetStackID().GetPC();
41 Target &target = GetTarget();
42
43 // Find the return address and set a breakpoint there:
44 // FIXME - can we do this more securely if we know first_insn?
45
46 StackFrameSP return_frame_sp(thread.GetStackFrameAtIndex(frame_idx + 1));
47 if (return_frame_sp) {
48 // TODO: add inline functionality
49 m_return_addr = return_frame_sp->GetStackID().GetPC();
50 Breakpoint *return_bp =
51 target.CreateBreakpoint(m_return_addr, true, false).get();
52
53 if (return_bp != nullptr) {
54 if (return_bp->IsHardware() && !return_bp->HasResolvedLocations())
55 m_could_not_resolve_hw_bp = true;
56 return_bp->SetThreadID(m_tid);
57 m_return_bp_id = return_bp->GetID();
58 return_bp->SetBreakpointKind("until-return-backstop");
59 }
60 }
61
62 m_stack_id = frame_sp->GetStackID();
63
64 for (addr_t address : address_list) {
65 Breakpoint *until_bp = target.CreateBreakpoint(address, true, false).get();
66 if (until_bp != nullptr) {
67 until_bp->SetThreadID(m_tid);
68 m_until_points[address] = until_bp->GetID();
69 until_bp->SetBreakpointKind("until-target");
70 } else {
71 m_until_points[address] = LLDB_INVALID_BREAK_ID;
72 }
73 }
74}
75
77
79 Target &target = GetTarget();
83 }
84
85 for (const auto &[address, break_id] : m_until_points)
86 target.RemoveBreakpointByID(break_id);
87 m_until_points.clear();
89}
90
93 if (level == lldb::eDescriptionLevelBrief) {
94 s->PutCString("step until");
95 if (m_stepped_out)
96 s->PutCString(" - stepped out");
97 return;
98 }
99
100 if (m_until_points.size() == 1) {
101 s->Printf("Stepping from address 0x%" PRIx64 " until we reach 0x%" PRIx64
102 " using breakpoint %d",
103 (uint64_t)m_step_from_insn,
104 (uint64_t)(*m_until_points.begin()).first,
105 (*m_until_points.begin()).second);
106 } else {
107 s->Printf("Stepping from address 0x%" PRIx64 " until we reach one of:",
108 (uint64_t)m_step_from_insn);
109 for (const auto &[address, break_id] : m_until_points)
110 s->Printf("\n\t0x%" PRIx64 " (bp: %d)", (uint64_t)address, break_id);
111 }
112 s->Printf(" stepped out address is 0x%" PRIx64 ".", (uint64_t)m_return_addr);
113}
114
117 if (error)
118 error->PutCString(
119 "Could not create hardware breakpoint for thread plan.");
120 return false;
121 }
123 if (error)
124 error->PutCString("Could not create return breakpoint.");
125 return false;
126 }
127 for (const auto &[address, break_id] : m_until_points)
128 if (!LLDB_BREAK_ID_IS_VALID(break_id))
129 return false;
130 return true;
131}
132
134 if (m_ran_analyze)
135 return;
136
137 StopInfoSP stop_info_sp = GetPrivateStopInfo();
138 m_should_stop = true;
139 m_explains_stop = false;
140
141 if (stop_info_sp) {
142 StopReason reason = stop_info_sp->GetStopReason();
143
144 if (reason == eStopReasonBreakpoint) {
145 // If this is OUR breakpoint, we're fine, otherwise we don't know why
146 // this happened...
147 BreakpointSiteSP this_site =
148 m_process.GetBreakpointSiteList().FindByID(stop_info_sp->GetValue());
149 if (!this_site) {
150 m_explains_stop = false;
151 return;
152 }
153
154 if (this_site->IsBreakpointAtThisSite(m_return_bp_id)) {
155 // If we are at our "step out" breakpoint, and the stack depth has
156 // shrunk, then this is indeed our stop. If the stack depth has grown,
157 // then we've hit our step out breakpoint recursively. If we are the
158 // only breakpoint at that location, then we do explain the stop, and
159 // we'll just continue. If there was another breakpoint here, then we
160 // don't explain the stop, but we won't mark ourselves Completed,
161 // because maybe that breakpoint will continue, and then we'll finish
162 // the "until".
163 bool done;
164 StackID cur_frame_zero_id;
165
166 done = (m_stack_id.IsYoungerThan(cur_frame_zero_id));
167
168 if (done) {
169 m_stepped_out = true;
171 } else
172 m_should_stop = false;
173
174 if (this_site->GetNumberOfConstituents() == 1)
175 m_explains_stop = true;
176 else
177 m_explains_stop = false;
178 return;
179 } else {
180 // Check if we've hit one of our "until" breakpoints.
181 until_collection::iterator pos, end = m_until_points.end();
182 for (pos = m_until_points.begin(); pos != end; pos++) {
183 if (this_site->IsBreakpointAtThisSite((*pos).second)) {
184 // If we're at the right stack depth, then we're done.
185 Thread &thread = GetThread();
186 bool done;
187 StackID frame_zero_id =
188 thread.GetStackFrameAtIndex(0)->GetStackID();
189
190 if (frame_zero_id == m_stack_id)
191 done = true;
192 else if (frame_zero_id.IsYoungerThan(m_stack_id))
193 done = false;
194 else {
195 StackFrameSP older_frame_sp = thread.GetStackFrameAtIndex(1);
196
197 // But if we can't even unwind one frame we should just get out
198 // of here & stop...
199 if (older_frame_sp) {
200 const SymbolContext &older_context =
201 older_frame_sp->GetSymbolContext(eSymbolContextEverything);
202 SymbolContext stack_context;
203 m_stack_id.GetSymbolContextScope()->CalculateSymbolContext(
204 &stack_context);
205
206 done = (older_context == stack_context);
207 } else
208 done = false;
209 }
210
211 if (done)
213 else
214 m_should_stop = false;
215
216 // Otherwise we've hit this breakpoint recursively. If we're the
217 // only breakpoint here, then we do explain the stop, and we'll
218 // continue. If not then we should let higher plans handle this
219 // stop.
220 if (this_site->GetNumberOfConstituents() == 1)
221 m_explains_stop = true;
222 else {
223 m_should_stop = true;
224 m_explains_stop = false;
225 }
226 return;
227 }
228 }
229 }
230 // If we get here we haven't hit any of our breakpoints, so let the
231 // higher plans take care of the stop.
232 m_explains_stop = false;
233 return;
234 } else if (IsUsuallyUnexplainedStopReason(reason)) {
235 m_explains_stop = false;
236 } else {
237 m_explains_stop = true;
238 }
239 }
240}
241
243 // We don't explain signals or breakpoints (breakpoints that handle stepping
244 // in or out will be handled by a child plan.
245 AnalyzeStop();
246 return m_explains_stop;
247}
248
250 // If we've told our self in ExplainsStop that we plan to continue, then do
251 // so here. Otherwise, as long as this thread has stopped for a reason, we
252 // will stop.
253
254 StopInfoSP stop_info_sp = GetPrivateStopInfo();
255 if (!stop_info_sp || stop_info_sp->GetStopReason() == eStopReasonNone)
256 return false;
257
258 AnalyzeStop();
259 return m_should_stop;
260}
261
263
265
267 Target &target = GetTarget();
268 for (const auto &[address, break_id] : m_until_points)
269 if (BreakpointSP until_bp_sp = target.GetBreakpointByID(break_id))
270 until_bp_sp->SetEnabled(enabled);
271}
272
274 bool current_plan) {
275 if (current_plan) {
276 Target &target = GetTarget();
277 Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
278 if (return_bp != nullptr)
279 return_bp->SetEnabled(true);
281 }
282
283 m_should_stop = true;
284 m_ran_analyze = false;
285 m_explains_stop = false;
286 return true;
287}
288
290 Target &target = GetTarget();
291 Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
292 if (return_bp != nullptr)
293 return_bp->SetEnabled(false);
295 return true;
296}
297
299 if (!IsPlanComplete())
300 return false;
301
302 LLDB_LOGF(GetLog(LLDBLog::Step), "Completed step until plan.");
303 Clear();
305 return true;
306}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOGF(log,...)
Definition Log.h:389
General Outline: A breakpoint has four main parts, a filter, a resolver, the list of breakpoint locat...
Definition Breakpoint.h:83
void SetBreakpointKind(const char *kind)
Set the "kind" description for a breakpoint.
Definition Breakpoint.h:485
bool HasResolvedLocations() const
Return whether this breakpoint has any resolved locations.
void SetThreadID(lldb::tid_t thread_id)
Set the valid thread to be checked when the breakpoint is hit.
void SetEnabled(bool enable) override
If enable is true, enable the breakpoint, if false disable it.
bool IsYoungerThan(const StackID &other) const
Returns true if this StackID corresponds to a frame younger (i.e.
Definition StackID.cpp:72
lldb::break_id_t GetID() const
Definition Stoppoint.cpp:22
A stream class that can stream formatted output to a file.
Definition Stream.h:28
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
Defines a symbol context baton that can be handed other debug core functions.
lldb::BreakpointSP GetBreakpointByID(lldb::break_id_t break_id)
Definition Target.cpp:439
bool RemoveBreakpointByID(lldb::break_id_t break_id)
Definition Target.cpp:1212
lldb::BreakpointSP CreateBreakpoint(const FileSpecList *containingModules, const FileSpec &file, uint32_t line_no, uint32_t column, lldb::addr_t offset, LazyBool check_inlines, LazyBool skip_prologue, bool internal, bool request_hardware, LazyBool move_to_nearest_code)
Definition Target.cpp:510
bool DoWillResume(lldb::StateType resume_state, bool current_plan) override
void GetDescription(Stream *s, lldb::DescriptionLevel level) override
Print a description of this thread to the stream s.
bool DoPlanExplainsStop(Event *event_ptr) override
ThreadPlanStepUntil(Thread &thread, llvm::ArrayRef< lldb::addr_t > address_list, bool stop_others, uint32_t frame_idx=0)
bool ValidatePlan(Stream *error) override
Returns whether this plan could be successfully created.
lldb::StateType GetPlanRunState() override
bool ShouldStop(Event *event_ptr) override
bool IsUsuallyUnexplainedStopReason(lldb::StopReason)
void SetPlanComplete(bool success=true)
Thread & GetThread()
Returns the Thread that is using this thread plan.
virtual bool MischiefManaged()
lldb::StopInfoSP GetPrivateStopInfo()
Definition ThreadPlan.h:548
#define LLDB_INVALID_BREAK_ID
#define LLDB_BREAK_ID_IS_VALID(bid)
#define LLDB_INVALID_ADDRESS
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::StackFrame > StackFrameSP
std::shared_ptr< lldb_private::BreakpointSite > BreakpointSiteSP
DescriptionLevel
Description levels for "void GetDescription(Stream *, DescriptionLevel)" calls.
@ eDescriptionLevelBrief
StateType
Process and Thread States.
@ eStateRunning
Process or thread is running and can't be examined.
std::shared_ptr< lldb_private::Breakpoint > BreakpointSP
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
uint64_t addr_t
Definition lldb-types.h:80
StopReason
Thread stop reasons.
@ eStopReasonBreakpoint