1 //===-- ThreadPlanStepUntil.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/ThreadPlanStepUntil.h"
11 #include "lldb/Breakpoint/Breakpoint.h"
12 #include "lldb/Symbol/SymbolContextScope.h"
13 #include "lldb/Target/Process.h"
14 #include "lldb/Target/RegisterContext.h"
15 #include "lldb/Target/StopInfo.h"
16 #include "lldb/Target/Target.h"
17 #include "lldb/Utility/LLDBLog.h"
18 #include "lldb/Utility/Log.h"
21 using namespace lldb_private
;
23 // ThreadPlanStepUntil: Run until we reach a given line number or step out of
26 ThreadPlanStepUntil::ThreadPlanStepUntil(Thread
&thread
,
27 lldb::addr_t
*address_list
,
28 size_t num_addresses
, bool stop_others
,
30 : ThreadPlan(ThreadPlan::eKindStepUntil
, "Step until", thread
,
31 eVoteNoOpinion
, eVoteNoOpinion
),
32 m_step_from_insn(LLDB_INVALID_ADDRESS
),
33 m_return_bp_id(LLDB_INVALID_BREAK_ID
),
34 m_return_addr(LLDB_INVALID_ADDRESS
), m_stepped_out(false),
35 m_should_stop(false), m_ran_analyze(false), m_explains_stop(false),
36 m_until_points(), m_stop_others(stop_others
) {
37 // Stash away our "until" addresses:
38 TargetSP
target_sp(thread
.CalculateTarget());
40 StackFrameSP
frame_sp(thread
.GetStackFrameAtIndex(frame_idx
));
42 m_step_from_insn
= frame_sp
->GetStackID().GetPC();
44 // Find the return address and set a breakpoint there:
45 // FIXME - can we do this more securely if we know first_insn?
47 StackFrameSP
return_frame_sp(thread
.GetStackFrameAtIndex(frame_idx
+ 1));
48 if (return_frame_sp
) {
49 // TODO: add inline functionality
50 m_return_addr
= return_frame_sp
->GetStackID().GetPC();
51 Breakpoint
*return_bp
=
52 target_sp
->CreateBreakpoint(m_return_addr
, true, false).get();
54 if (return_bp
!= nullptr) {
55 if (return_bp
->IsHardware() && !return_bp
->HasResolvedLocations())
56 m_could_not_resolve_hw_bp
= true;
57 return_bp
->SetThreadID(m_tid
);
58 m_return_bp_id
= return_bp
->GetID();
59 return_bp
->SetBreakpointKind("until-return-backstop");
63 m_stack_id
= frame_sp
->GetStackID();
65 // Now set breakpoints on all our return addresses:
66 for (size_t i
= 0; i
< num_addresses
; i
++) {
67 Breakpoint
*until_bp
=
68 target_sp
->CreateBreakpoint(address_list
[i
], true, false).get();
69 if (until_bp
!= nullptr) {
70 until_bp
->SetThreadID(m_tid
);
71 m_until_points
[address_list
[i
]] = until_bp
->GetID();
72 until_bp
->SetBreakpointKind("until-target");
74 m_until_points
[address_list
[i
]] = LLDB_INVALID_BREAK_ID
;
80 ThreadPlanStepUntil::~ThreadPlanStepUntil() { Clear(); }
82 void ThreadPlanStepUntil::Clear() {
83 Target
&target
= GetTarget();
84 if (m_return_bp_id
!= LLDB_INVALID_BREAK_ID
) {
85 target
.RemoveBreakpointByID(m_return_bp_id
);
86 m_return_bp_id
= LLDB_INVALID_BREAK_ID
;
89 until_collection::iterator pos
, end
= m_until_points
.end();
90 for (pos
= m_until_points
.begin(); pos
!= end
; pos
++) {
91 target
.RemoveBreakpointByID((*pos
).second
);
93 m_until_points
.clear();
94 m_could_not_resolve_hw_bp
= false;
97 void ThreadPlanStepUntil::GetDescription(Stream
*s
,
98 lldb::DescriptionLevel level
) {
99 if (level
== lldb::eDescriptionLevelBrief
) {
100 s
->Printf("step until");
102 s
->Printf(" - stepped out");
104 if (m_until_points
.size() == 1)
105 s
->Printf("Stepping from address 0x%" PRIx64
" until we reach 0x%" PRIx64
106 " using breakpoint %d",
107 (uint64_t)m_step_from_insn
,
108 (uint64_t)(*m_until_points
.begin()).first
,
109 (*m_until_points
.begin()).second
);
111 until_collection::iterator pos
, end
= m_until_points
.end();
112 s
->Printf("Stepping from address 0x%" PRIx64
" until we reach one of:",
113 (uint64_t)m_step_from_insn
);
114 for (pos
= m_until_points
.begin(); pos
!= end
; pos
++) {
115 s
->Printf("\n\t0x%" PRIx64
" (bp: %d)", (uint64_t)(*pos
).first
,
119 s
->Printf(" stepped out address is 0x%" PRIx64
".",
120 (uint64_t)m_return_addr
);
124 bool ThreadPlanStepUntil::ValidatePlan(Stream
*error
) {
125 if (m_could_not_resolve_hw_bp
) {
128 "Could not create hardware breakpoint for thread plan.");
130 } else if (m_return_bp_id
== LLDB_INVALID_BREAK_ID
) {
132 error
->PutCString("Could not create return breakpoint.");
135 until_collection::iterator pos
, end
= m_until_points
.end();
136 for (pos
= m_until_points
.begin(); pos
!= end
; pos
++) {
137 if (!LLDB_BREAK_ID_IS_VALID((*pos
).second
))
144 void ThreadPlanStepUntil::AnalyzeStop() {
148 StopInfoSP stop_info_sp
= GetPrivateStopInfo();
149 m_should_stop
= true;
150 m_explains_stop
= false;
153 StopReason reason
= stop_info_sp
->GetStopReason();
155 if (reason
== eStopReasonBreakpoint
) {
156 // If this is OUR breakpoint, we're fine, otherwise we don't know why
158 BreakpointSiteSP this_site
=
159 m_process
.GetBreakpointSiteList().FindByID(stop_info_sp
->GetValue());
161 m_explains_stop
= false;
165 if (this_site
->IsBreakpointAtThisSite(m_return_bp_id
)) {
166 // If we are at our "step out" breakpoint, and the stack depth has
167 // shrunk, then this is indeed our stop. If the stack depth has grown,
168 // then we've hit our step out breakpoint recursively. If we are the
169 // only breakpoint at that location, then we do explain the stop, and
170 // we'll just continue. If there was another breakpoint here, then we
171 // don't explain the stop, but we won't mark ourselves Completed,
172 // because maybe that breakpoint will continue, and then we'll finish
175 StackID cur_frame_zero_id
;
177 done
= (m_stack_id
< cur_frame_zero_id
);
180 m_stepped_out
= true;
183 m_should_stop
= false;
185 if (this_site
->GetNumberOfOwners() == 1)
186 m_explains_stop
= true;
188 m_explains_stop
= false;
191 // Check if we've hit one of our "until" breakpoints.
192 until_collection::iterator pos
, end
= m_until_points
.end();
193 for (pos
= m_until_points
.begin(); pos
!= end
; pos
++) {
194 if (this_site
->IsBreakpointAtThisSite((*pos
).second
)) {
195 // If we're at the right stack depth, then we're done.
196 Thread
&thread
= GetThread();
198 StackID frame_zero_id
=
199 thread
.GetStackFrameAtIndex(0)->GetStackID();
201 if (frame_zero_id
== m_stack_id
)
203 else if (frame_zero_id
< m_stack_id
)
206 StackFrameSP older_frame_sp
= thread
.GetStackFrameAtIndex(1);
208 // But if we can't even unwind one frame we should just get out
210 if (older_frame_sp
) {
211 const SymbolContext
&older_context
=
212 older_frame_sp
->GetSymbolContext(eSymbolContextEverything
);
213 SymbolContext stack_context
;
214 m_stack_id
.GetSymbolContextScope()->CalculateSymbolContext(
217 done
= (older_context
== stack_context
);
225 m_should_stop
= false;
227 // Otherwise we've hit this breakpoint recursively. If we're the
228 // only breakpoint here, then we do explain the stop, and we'll
229 // continue. If not then we should let higher plans handle this
231 if (this_site
->GetNumberOfOwners() == 1)
232 m_explains_stop
= true;
234 m_should_stop
= true;
235 m_explains_stop
= false;
241 // If we get here we haven't hit any of our breakpoints, so let the
242 // higher plans take care of the stop.
243 m_explains_stop
= false;
245 } else if (IsUsuallyUnexplainedStopReason(reason
)) {
246 m_explains_stop
= false;
248 m_explains_stop
= true;
253 bool ThreadPlanStepUntil::DoPlanExplainsStop(Event
*event_ptr
) {
254 // We don't explain signals or breakpoints (breakpoints that handle stepping
255 // in or out will be handled by a child plan.
257 return m_explains_stop
;
260 bool ThreadPlanStepUntil::ShouldStop(Event
*event_ptr
) {
261 // If we've told our self in ExplainsStop that we plan to continue, then do
262 // so here. Otherwise, as long as this thread has stopped for a reason, we
265 StopInfoSP stop_info_sp
= GetPrivateStopInfo();
266 if (!stop_info_sp
|| stop_info_sp
->GetStopReason() == eStopReasonNone
)
270 return m_should_stop
;
273 bool ThreadPlanStepUntil::StopOthers() { return m_stop_others
; }
275 StateType
ThreadPlanStepUntil::GetPlanRunState() { return eStateRunning
; }
277 bool ThreadPlanStepUntil::DoWillResume(StateType resume_state
,
280 Target
&target
= GetTarget();
281 Breakpoint
*return_bp
= target
.GetBreakpointByID(m_return_bp_id
).get();
282 if (return_bp
!= nullptr)
283 return_bp
->SetEnabled(true);
285 until_collection::iterator pos
, end
= m_until_points
.end();
286 for (pos
= m_until_points
.begin(); pos
!= end
; pos
++) {
287 Breakpoint
*until_bp
= target
.GetBreakpointByID((*pos
).second
).get();
288 if (until_bp
!= nullptr)
289 until_bp
->SetEnabled(true);
293 m_should_stop
= true;
294 m_ran_analyze
= false;
295 m_explains_stop
= false;
299 bool ThreadPlanStepUntil::WillStop() {
300 Target
&target
= GetTarget();
301 Breakpoint
*return_bp
= target
.GetBreakpointByID(m_return_bp_id
).get();
302 if (return_bp
!= nullptr)
303 return_bp
->SetEnabled(false);
305 until_collection::iterator pos
, end
= m_until_points
.end();
306 for (pos
= m_until_points
.begin(); pos
!= end
; pos
++) {
307 Breakpoint
*until_bp
= target
.GetBreakpointByID((*pos
).second
).get();
308 if (until_bp
!= nullptr)
309 until_bp
->SetEnabled(false);
314 bool ThreadPlanStepUntil::MischiefManaged() {
315 // I'm letting "PlanExplainsStop" do all the work, and just reporting that
318 if (IsPlanComplete()) {
319 Log
*log
= GetLog(LLDBLog::Step
);
320 LLDB_LOGF(log
, "Completed step until plan.");
326 ThreadPlan::MischiefManaged();