blob: b790db57851e4feac0278fda3e5777e63af7c253 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- ThreadPlanStepInstruction.cpp ---------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Chris Lattner30fdc8d2010-06-08 16:52:24 +00006//
7//===----------------------------------------------------------------------===//
8
Eugene Zelenkoe65b2cf2015-12-15 01:33:19 +00009#include "lldb/Target/ThreadPlanStepInstruction.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000010#include "lldb/Target/Process.h"
Greg Claytonf4b47e12010-08-04 01:40:35 +000011#include "lldb/Target/RegisterContext.h"
12#include "lldb/Target/RegisterContext.h"
13#include "lldb/Target/StopInfo.h"
14#include "lldb/Target/Target.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000015#include "lldb/Utility/Log.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000016#include "lldb/Utility/Stream.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000017
18using namespace lldb;
19using namespace lldb_private;
20
21//----------------------------------------------------------------------
22// ThreadPlanStepInstruction: Step over the current instruction
23//----------------------------------------------------------------------
24
Kate Stoneb9c1b512016-09-06 20:57:50 +000025ThreadPlanStepInstruction::ThreadPlanStepInstruction(Thread &thread,
26 bool step_over,
27 bool stop_other_threads,
28 Vote stop_vote,
29 Vote run_vote)
30 : ThreadPlan(ThreadPlan::eKindStepInstruction,
31 "Step over single instruction", thread, stop_vote, run_vote),
32 m_instruction_addr(0), m_stop_other_threads(stop_other_threads),
33 m_step_over(step_over) {
34 m_takes_iteration_count = true;
35 SetUpState();
Chris Lattner30fdc8d2010-06-08 16:52:24 +000036}
37
Eugene Zelenkoe65b2cf2015-12-15 01:33:19 +000038ThreadPlanStepInstruction::~ThreadPlanStepInstruction() = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000039
Kate Stoneb9c1b512016-09-06 20:57:50 +000040void ThreadPlanStepInstruction::SetUpState() {
41 m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0);
42 StackFrameSP start_frame_sp(m_thread.GetStackFrameAtIndex(0));
43 m_stack_id = start_frame_sp->GetStackID();
44
45 m_start_has_symbol =
46 start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != nullptr;
47
48 StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1);
49 if (parent_frame_sp)
50 m_parent_frame_id = parent_frame_sp->GetStackID();
Jim Ingham7a88ec92014-07-08 19:28:57 +000051}
52
Kate Stoneb9c1b512016-09-06 20:57:50 +000053void ThreadPlanStepInstruction::GetDescription(Stream *s,
54 lldb::DescriptionLevel level) {
Jonas Devliegheree103ae92018-11-15 01:18:15 +000055 auto PrintFailureIfAny = [&]() {
56 if (m_status.Success())
57 return;
58 s->Printf(" failed (%s)", m_status.AsCString());
59 };
60
Kate Stoneb9c1b512016-09-06 20:57:50 +000061 if (level == lldb::eDescriptionLevelBrief) {
Chris Lattner30fdc8d2010-06-08 16:52:24 +000062 if (m_step_over)
Kate Stoneb9c1b512016-09-06 20:57:50 +000063 s->Printf("instruction step over");
Chris Lattner30fdc8d2010-06-08 16:52:24 +000064 else
Kate Stoneb9c1b512016-09-06 20:57:50 +000065 s->Printf("instruction step into");
Jonas Devliegheree103ae92018-11-15 01:18:15 +000066
67 PrintFailureIfAny();
Kate Stoneb9c1b512016-09-06 20:57:50 +000068 } else {
69 s->Printf("Stepping one instruction past ");
70 s->Address(m_instruction_addr, sizeof(addr_t));
71 if (!m_start_has_symbol)
72 s->Printf(" which has no symbol");
73
74 if (m_step_over)
75 s->Printf(" stepping over calls");
76 else
77 s->Printf(" stepping into calls");
Jonas Devliegheree103ae92018-11-15 01:18:15 +000078
79 PrintFailureIfAny();
Kate Stoneb9c1b512016-09-06 20:57:50 +000080 }
81}
82
83bool ThreadPlanStepInstruction::ValidatePlan(Stream *error) {
Adrian Prantl05097242018-04-30 16:49:04 +000084 // Since we read the instruction we're stepping over from the thread, this
85 // plan will always work.
Kate Stoneb9c1b512016-09-06 20:57:50 +000086 return true;
87}
88
89bool ThreadPlanStepInstruction::DoPlanExplainsStop(Event *event_ptr) {
90 StopInfoSP stop_info_sp = GetPrivateStopInfo();
91 if (stop_info_sp) {
92 StopReason reason = stop_info_sp->GetStopReason();
93 return (reason == eStopReasonTrace || reason == eStopReasonNone);
94 }
95 return false;
96}
97
98bool ThreadPlanStepInstruction::IsPlanStale() {
99 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
100 StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
101 if (cur_frame_id == m_stack_id) {
Boris Ulasevich86aaa8a2017-02-15 11:42:47 +0000102 // Set plan Complete when we reach next instruction
103 uint64_t pc = m_thread.GetRegisterContext()->GetPC(0);
104 uint32_t max_opcode_size = m_thread.CalculateTarget()
105 ->GetArchitecture().GetMaximumOpcodeByteSize();
106 bool next_instruction_reached = (pc > m_instruction_addr) &&
107 (pc <= m_instruction_addr + max_opcode_size);
108 if (next_instruction_reached) {
109 SetPlanComplete();
110 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000111 return (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr);
112 } else if (cur_frame_id < m_stack_id) {
113 // If the current frame is younger than the start frame and we are stepping
Adrian Prantl05097242018-04-30 16:49:04 +0000114 // over, then we need to continue, but if we are doing just one step, we're
115 // done.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000116 return !m_step_over;
117 } else {
118 if (log) {
119 log->Printf("ThreadPlanStepInstruction::IsPlanStale - Current frame is "
120 "older than start frame, plan is stale.");
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000121 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000122 return true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000123 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000124}
125
Kate Stoneb9c1b512016-09-06 20:57:50 +0000126bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) {
127 if (m_step_over) {
128 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
129
130 StackFrameSP cur_frame_sp = m_thread.GetStackFrameAtIndex(0);
131 if (!cur_frame_sp) {
132 if (log)
133 log->Printf(
134 "ThreadPlanStepInstruction couldn't get the 0th frame, stopping.");
135 SetPlanComplete();
136 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000137 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000138
139 StackID cur_frame_zero_id = cur_frame_sp->GetStackID();
140
141 if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id) {
142 if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr) {
143 if (--m_iteration_count <= 0) {
144 SetPlanComplete();
145 return true;
146 } else {
147 // We are still stepping, reset the start pc, and in case we've
Adrian Prantl05097242018-04-30 16:49:04 +0000148 // stepped out, reset the current stack id.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000149 SetUpState();
150 return false;
151 }
152 } else
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000153 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154 } else {
155 // We've stepped in, step back out again:
156 StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
157 if (return_frame) {
158 if (return_frame->GetStackID() != m_parent_frame_id ||
159 m_start_has_symbol) {
160 // next-instruction shouldn't step out of inlined functions. But we
Adrian Prantl05097242018-04-30 16:49:04 +0000161 // may have stepped into a real function that starts with an inlined
162 // function, and we do want to step out of that...
Kate Stoneb9c1b512016-09-06 20:57:50 +0000163
164 if (cur_frame_sp->IsInlined()) {
165 StackFrameSP parent_frame_sp =
166 m_thread.GetFrameWithStackID(m_stack_id);
167
168 if (parent_frame_sp &&
169 parent_frame_sp->GetConcreteFrameIndex() ==
170 cur_frame_sp->GetConcreteFrameIndex()) {
171 SetPlanComplete();
172 if (log) {
173 log->Printf("Frame we stepped into is inlined into the frame "
174 "we were stepping from, stopping.");
175 }
176 return true;
177 }
178 }
179
180 if (log) {
181 StreamString s;
182 s.PutCString("Stepped in to: ");
183 addr_t stop_addr =
184 m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
185 s.Address(stop_addr, m_thread.CalculateTarget()
186 ->GetArchitecture()
187 .GetAddressByteSize());
188 s.PutCString(" stepping out to: ");
189 addr_t return_addr = return_frame->GetRegisterContext()->GetPC();
190 s.Address(return_addr, m_thread.CalculateTarget()
191 ->GetArchitecture()
192 .GetAddressByteSize());
193 log->Printf("%s.", s.GetData());
194 }
195
Adrian Prantl05097242018-04-30 16:49:04 +0000196 // StepInstruction should probably have the tri-state RunMode, but
197 // for now it is safer to run others.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000198 const bool stop_others = false;
199 m_thread.QueueThreadPlanForStepOutNoShouldStop(
Jonas Devliegheree103ae92018-11-15 01:18:15 +0000200 false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
201 m_status);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000202 return false;
203 } else {
204 if (log) {
205 log->PutCString(
206 "The stack id we are stepping in changed, but our parent frame "
207 "did not when stepping from code with no symbols. "
208 "We are probably just confused about where we are, stopping.");
209 }
210 SetPlanComplete();
211 return true;
212 }
213 } else {
214 if (log)
215 log->Printf("Could not find previous frame, stopping.");
216 SetPlanComplete();
217 return true;
218 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000219 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000220 } else {
221 lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC(0);
222 if (pc_addr != m_instruction_addr) {
223 if (--m_iteration_count <= 0) {
224 SetPlanComplete();
225 return true;
226 } else {
227 // We are still stepping, reset the start pc, and in case we've stepped
Adrian Prantl05097242018-04-30 16:49:04 +0000228 // in or out, reset the current stack id.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000229 SetUpState();
230 return false;
231 }
232 } else
233 return false;
234 }
235}
236
237bool ThreadPlanStepInstruction::StopOthers() { return m_stop_other_threads; }
238
239StateType ThreadPlanStepInstruction::GetPlanRunState() {
240 return eStateStepping;
241}
242
243bool ThreadPlanStepInstruction::WillStop() { return true; }
244
245bool ThreadPlanStepInstruction::MischiefManaged() {
246 if (IsPlanComplete()) {
247 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
248 if (log)
249 log->Printf("Completed single instruction step plan.");
250 ThreadPlan::MischiefManaged();
251 return true;
252 } else {
253 return false;
254 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000255}