1 //===-- ThreadPlanStepThrough.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/ThreadPlanStepThrough.h"
10 #include "lldb/Breakpoint/Breakpoint.h"
11 #include "lldb/Target/DynamicLoader.h"
12 #include "lldb/Target/LanguageRuntime.h"
13 #include "lldb/Target/Process.h"
14 #include "lldb/Target/RegisterContext.h"
15 #include "lldb/Target/Target.h"
16 #include "lldb/Utility/LLDBLog.h"
17 #include "lldb/Utility/Log.h"
18 #include "lldb/Utility/Stream.h"
21 using namespace lldb_private
;
23 // ThreadPlanStepThrough: If the current instruction is a trampoline, step
24 // through it If it is the beginning of the prologue of a function, step
25 // through that as well.
27 ThreadPlanStepThrough::ThreadPlanStepThrough(Thread
&thread
,
30 : ThreadPlan(ThreadPlan::eKindStepThrough
,
31 "Step through trampolines and prologues", thread
,
32 eVoteNoOpinion
, eVoteNoOpinion
),
33 m_start_address(0), m_backstop_bkpt_id(LLDB_INVALID_BREAK_ID
),
34 m_backstop_addr(LLDB_INVALID_ADDRESS
), m_return_stack_id(m_stack_id
),
35 m_stop_others(stop_others
) {
36 LookForPlanToStepThroughFromCurrentPC();
38 // If we don't get a valid step through plan, don't bother to set up a
41 m_start_address
= GetThread().GetRegisterContext()->GetPC(0);
43 // We are going to return back to the concrete frame 1, we might pass by
44 // some inlined code that we're in the middle of by doing this, but it's
45 // easier than trying to figure out where the inlined code might return to.
47 StackFrameSP return_frame_sp
= thread
.GetFrameWithStackID(m_stack_id
);
49 if (return_frame_sp
) {
50 m_backstop_addr
= return_frame_sp
->GetFrameCodeAddress().GetLoadAddress(
51 thread
.CalculateTarget().get());
52 Breakpoint
*return_bp
=
54 .CreateBreakpoint(m_backstop_addr
, true, false)
57 if (return_bp
!= nullptr) {
58 if (return_bp
->IsHardware() && !return_bp
->HasResolvedLocations())
59 m_could_not_resolve_hw_bp
= true;
60 return_bp
->SetThreadID(m_tid
);
61 m_backstop_bkpt_id
= return_bp
->GetID();
62 return_bp
->SetBreakpointKind("step-through-backstop");
64 Log
*log
= GetLog(LLDBLog::Step
);
66 LLDB_LOGF(log
, "Setting backstop breakpoint %d at address: 0x%" PRIx64
,
67 m_backstop_bkpt_id
, m_backstop_addr
);
73 ThreadPlanStepThrough::~ThreadPlanStepThrough() { ClearBackstopBreakpoint(); }
75 void ThreadPlanStepThrough::DidPush() {
77 PushPlan(m_sub_plan_sp
);
80 void ThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC() {
81 Thread
&thread
= GetThread();
82 DynamicLoader
*loader
= thread
.GetProcess()->GetDynamicLoader();
84 m_sub_plan_sp
= loader
->GetStepThroughTrampolinePlan(thread
, m_stop_others
);
86 // If the DynamicLoader was unable to provide us with a ThreadPlan, then we
87 // try the LanguageRuntimes.
89 for (LanguageRuntime
*runtime
: m_process
.GetLanguageRuntimes()) {
91 runtime
->GetStepThroughTrampolinePlan(thread
, m_stop_others
);
98 Log
*log
= GetLog(LLDBLog::Step
);
100 lldb::addr_t current_address
= GetThread().GetRegisterContext()->GetPC(0);
103 m_sub_plan_sp
->GetDescription(&s
, lldb::eDescriptionLevelFull
);
104 LLDB_LOGF(log
, "Found step through plan from 0x%" PRIx64
": %s",
105 current_address
, s
.GetData());
108 "Couldn't find step through plan from address 0x%" PRIx64
".",
114 void ThreadPlanStepThrough::GetDescription(Stream
*s
,
115 lldb::DescriptionLevel level
) {
116 if (level
== lldb::eDescriptionLevelBrief
)
117 s
->Printf("Step through");
119 s
->PutCString("Stepping through trampoline code from: ");
120 DumpAddress(s
->AsRawOstream(), m_start_address
, sizeof(addr_t
));
121 if (m_backstop_bkpt_id
!= LLDB_INVALID_BREAK_ID
) {
122 s
->Printf(" with backstop breakpoint ID: %d at address: ",
124 DumpAddress(s
->AsRawOstream(), m_backstop_addr
, sizeof(addr_t
));
126 s
->PutCString(" unable to set a backstop breakpoint.");
130 bool ThreadPlanStepThrough::ValidatePlan(Stream
*error
) {
131 if (m_could_not_resolve_hw_bp
) {
134 "Could not create hardware breakpoint for thread plan.");
138 if (m_backstop_bkpt_id
== LLDB_INVALID_BREAK_ID
) {
140 error
->PutCString("Could not create backstop breakpoint.");
144 if (!m_sub_plan_sp
.get()) {
146 error
->PutCString("Does not have a subplan.");
153 bool ThreadPlanStepThrough::DoPlanExplainsStop(Event
*event_ptr
) {
154 // If we have a sub-plan, it will have been asked first if we explain the
155 // stop, and we won't get asked. The only time we would be the one directly
156 // asked this question is if we hit our backstop breakpoint.
158 return HitOurBackstopBreakpoint();
161 bool ThreadPlanStepThrough::ShouldStop(Event
*event_ptr
) {
162 // If we've already marked ourselves done, then we're done...
163 if (IsPlanComplete())
166 // First, did we hit the backstop breakpoint?
167 if (HitOurBackstopBreakpoint()) {
168 SetPlanComplete(true);
172 // If we don't have a sub-plan, then we're also done (can't see how we would
173 // ever get here without a plan, but just in case.
175 if (!m_sub_plan_sp
) {
180 // If the current sub plan is not done, we don't want to stop. Actually, we
181 // probably won't ever get here in this state, since we generally won't get
182 // asked any questions if out current sub-plan is not done...
183 if (!m_sub_plan_sp
->IsPlanComplete())
186 // If our current sub plan failed, then let's just run to our backstop. If
187 // we can't do that then just stop.
188 if (!m_sub_plan_sp
->PlanSucceeded()) {
189 if (m_backstop_bkpt_id
!= LLDB_INVALID_BREAK_ID
) {
190 m_sub_plan_sp
.reset();
193 SetPlanComplete(false);
198 // Next see if there is a specific step through plan at our current pc (these
199 // might chain, for instance stepping through a dylib trampoline to the objc
200 // dispatch function...)
201 LookForPlanToStepThroughFromCurrentPC();
203 PushPlan(m_sub_plan_sp
);
211 bool ThreadPlanStepThrough::StopOthers() { return m_stop_others
; }
213 StateType
ThreadPlanStepThrough::GetPlanRunState() { return eStateRunning
; }
215 bool ThreadPlanStepThrough::DoWillResume(StateType resume_state
,
220 bool ThreadPlanStepThrough::WillStop() { return true; }
222 void ThreadPlanStepThrough::ClearBackstopBreakpoint() {
223 if (m_backstop_bkpt_id
!= LLDB_INVALID_BREAK_ID
) {
224 m_process
.GetTarget().RemoveBreakpointByID(m_backstop_bkpt_id
);
225 m_backstop_bkpt_id
= LLDB_INVALID_BREAK_ID
;
226 m_could_not_resolve_hw_bp
= false;
230 bool ThreadPlanStepThrough::MischiefManaged() {
231 Log
*log
= GetLog(LLDBLog::Step
);
233 if (!IsPlanComplete()) {
236 LLDB_LOGF(log
, "Completed step through step plan.");
238 ClearBackstopBreakpoint();
239 ThreadPlan::MischiefManaged();
244 bool ThreadPlanStepThrough::HitOurBackstopBreakpoint() {
245 Thread
&thread
= GetThread();
246 StopInfoSP
stop_info_sp(thread
.GetStopInfo());
247 if (stop_info_sp
&& stop_info_sp
->GetStopReason() == eStopReasonBreakpoint
) {
248 break_id_t stop_value
= (break_id_t
)stop_info_sp
->GetValue();
249 BreakpointSiteSP cur_site_sp
=
250 m_process
.GetBreakpointSiteList().FindByID(stop_value
);
252 cur_site_sp
->IsBreakpointAtThisSite(m_backstop_bkpt_id
)) {
253 StackID cur_frame_zero_id
= thread
.GetStackFrameAtIndex(0)->GetStackID();
255 if (cur_frame_zero_id
== m_return_stack_id
) {
256 Log
*log
= GetLog(LLDBLog::Step
);
258 log
->PutCString("ThreadPlanStepThrough hit backstop breakpoint.");