1ac7ddfbfSEd Maste //===-- ThreadPlanStepInstruction.cpp ---------------------------*- C++ -*-===//
2ac7ddfbfSEd Maste //
3ac7ddfbfSEd Maste // The LLVM Compiler Infrastructure
4ac7ddfbfSEd Maste //
5ac7ddfbfSEd Maste // This file is distributed under the University of Illinois Open Source
6ac7ddfbfSEd Maste // License. See LICENSE.TXT for details.
7ac7ddfbfSEd Maste //
8ac7ddfbfSEd Maste //===----------------------------------------------------------------------===//
9ac7ddfbfSEd Maste
109f2f44ceSEd Maste #include "lldb/Target/ThreadPlanStepInstruction.h"
11ac7ddfbfSEd Maste #include "lldb/Target/Process.h"
12ac7ddfbfSEd Maste #include "lldb/Target/RegisterContext.h"
13ac7ddfbfSEd Maste #include "lldb/Target/RegisterContext.h"
14ac7ddfbfSEd Maste #include "lldb/Target/StopInfo.h"
15ac7ddfbfSEd Maste #include "lldb/Target/Target.h"
16f678e45dSDimitry Andric #include "lldb/Utility/Log.h"
17f678e45dSDimitry Andric #include "lldb/Utility/Stream.h"
18ac7ddfbfSEd Maste
19ac7ddfbfSEd Maste using namespace lldb;
20ac7ddfbfSEd Maste using namespace lldb_private;
21ac7ddfbfSEd Maste
22ac7ddfbfSEd Maste //----------------------------------------------------------------------
23ac7ddfbfSEd Maste // ThreadPlanStepInstruction: Step over the current instruction
24ac7ddfbfSEd Maste //----------------------------------------------------------------------
25ac7ddfbfSEd Maste
ThreadPlanStepInstruction(Thread & thread,bool step_over,bool stop_other_threads,Vote stop_vote,Vote run_vote)26435933ddSDimitry Andric ThreadPlanStepInstruction::ThreadPlanStepInstruction(Thread &thread,
27ac7ddfbfSEd Maste bool step_over,
28ac7ddfbfSEd Maste bool stop_other_threads,
29ac7ddfbfSEd Maste Vote stop_vote,
30435933ddSDimitry Andric Vote run_vote)
31435933ddSDimitry Andric : ThreadPlan(ThreadPlan::eKindStepInstruction,
32435933ddSDimitry Andric "Step over single instruction", thread, stop_vote, run_vote),
33435933ddSDimitry Andric m_instruction_addr(0), m_stop_other_threads(stop_other_threads),
34435933ddSDimitry Andric m_step_over(step_over) {
350127ef0fSEd Maste m_takes_iteration_count = true;
360127ef0fSEd Maste SetUpState();
37ac7ddfbfSEd Maste }
38ac7ddfbfSEd Maste
399f2f44ceSEd Maste ThreadPlanStepInstruction::~ThreadPlanStepInstruction() = default;
40ac7ddfbfSEd Maste
SetUpState()41435933ddSDimitry Andric void ThreadPlanStepInstruction::SetUpState() {
420127ef0fSEd Maste m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0);
430127ef0fSEd Maste StackFrameSP start_frame_sp(m_thread.GetStackFrameAtIndex(0));
440127ef0fSEd Maste m_stack_id = start_frame_sp->GetStackID();
450127ef0fSEd Maste
46435933ddSDimitry Andric m_start_has_symbol =
47435933ddSDimitry Andric start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != nullptr;
480127ef0fSEd Maste
490127ef0fSEd Maste StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1);
500127ef0fSEd Maste if (parent_frame_sp)
510127ef0fSEd Maste m_parent_frame_id = parent_frame_sp->GetStackID();
520127ef0fSEd Maste }
530127ef0fSEd Maste
GetDescription(Stream * s,lldb::DescriptionLevel level)54435933ddSDimitry Andric void ThreadPlanStepInstruction::GetDescription(Stream *s,
55435933ddSDimitry Andric lldb::DescriptionLevel level) {
56*b5893f02SDimitry Andric auto PrintFailureIfAny = [&]() {
57*b5893f02SDimitry Andric if (m_status.Success())
58*b5893f02SDimitry Andric return;
59*b5893f02SDimitry Andric s->Printf(" failed (%s)", m_status.AsCString());
60*b5893f02SDimitry Andric };
61*b5893f02SDimitry Andric
62435933ddSDimitry Andric if (level == lldb::eDescriptionLevelBrief) {
63ac7ddfbfSEd Maste if (m_step_over)
64ac7ddfbfSEd Maste s->Printf("instruction step over");
65ac7ddfbfSEd Maste else
66ac7ddfbfSEd Maste s->Printf("instruction step into");
67*b5893f02SDimitry Andric
68*b5893f02SDimitry Andric PrintFailureIfAny();
69435933ddSDimitry Andric } else {
70ac7ddfbfSEd Maste s->Printf("Stepping one instruction past ");
71ac7ddfbfSEd Maste s->Address(m_instruction_addr, sizeof(addr_t));
72ac7ddfbfSEd Maste if (!m_start_has_symbol)
73ac7ddfbfSEd Maste s->Printf(" which has no symbol");
74ac7ddfbfSEd Maste
75ac7ddfbfSEd Maste if (m_step_over)
76ac7ddfbfSEd Maste s->Printf(" stepping over calls");
77ac7ddfbfSEd Maste else
78ac7ddfbfSEd Maste s->Printf(" stepping into calls");
79*b5893f02SDimitry Andric
80*b5893f02SDimitry Andric PrintFailureIfAny();
81ac7ddfbfSEd Maste }
82ac7ddfbfSEd Maste }
83ac7ddfbfSEd Maste
ValidatePlan(Stream * error)84435933ddSDimitry Andric bool ThreadPlanStepInstruction::ValidatePlan(Stream *error) {
854ba319b5SDimitry Andric // Since we read the instruction we're stepping over from the thread, this
864ba319b5SDimitry Andric // plan will always work.
87ac7ddfbfSEd Maste return true;
88ac7ddfbfSEd Maste }
89ac7ddfbfSEd Maste
DoPlanExplainsStop(Event * event_ptr)90435933ddSDimitry Andric bool ThreadPlanStepInstruction::DoPlanExplainsStop(Event *event_ptr) {
91ac7ddfbfSEd Maste StopInfoSP stop_info_sp = GetPrivateStopInfo();
92435933ddSDimitry Andric if (stop_info_sp) {
93ac7ddfbfSEd Maste StopReason reason = stop_info_sp->GetStopReason();
949f2f44ceSEd Maste return (reason == eStopReasonTrace || reason == eStopReasonNone);
95ac7ddfbfSEd Maste }
96ac7ddfbfSEd Maste return false;
97ac7ddfbfSEd Maste }
98ac7ddfbfSEd Maste
IsPlanStale()99435933ddSDimitry Andric bool ThreadPlanStepInstruction::IsPlanStale() {
1000127ef0fSEd Maste Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
1010127ef0fSEd Maste StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
102435933ddSDimitry Andric if (cur_frame_id == m_stack_id) {
103f678e45dSDimitry Andric // Set plan Complete when we reach next instruction
104f678e45dSDimitry Andric uint64_t pc = m_thread.GetRegisterContext()->GetPC(0);
105f678e45dSDimitry Andric uint32_t max_opcode_size = m_thread.CalculateTarget()
106f678e45dSDimitry Andric ->GetArchitecture().GetMaximumOpcodeByteSize();
107f678e45dSDimitry Andric bool next_instruction_reached = (pc > m_instruction_addr) &&
108f678e45dSDimitry Andric (pc <= m_instruction_addr + max_opcode_size);
109f678e45dSDimitry Andric if (next_instruction_reached) {
110f678e45dSDimitry Andric SetPlanComplete();
111f678e45dSDimitry Andric }
1129f2f44ceSEd Maste return (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr);
113435933ddSDimitry Andric } else if (cur_frame_id < m_stack_id) {
114435933ddSDimitry Andric // If the current frame is younger than the start frame and we are stepping
1154ba319b5SDimitry Andric // over, then we need to continue, but if we are doing just one step, we're
1164ba319b5SDimitry Andric // done.
1179f2f44ceSEd Maste return !m_step_over;
118435933ddSDimitry Andric } else {
119435933ddSDimitry Andric if (log) {
120435933ddSDimitry Andric log->Printf("ThreadPlanStepInstruction::IsPlanStale - Current frame is "
121435933ddSDimitry Andric "older than start frame, plan is stale.");
1220127ef0fSEd Maste }
1230127ef0fSEd Maste return true;
1240127ef0fSEd Maste }
1250127ef0fSEd Maste }
1260127ef0fSEd Maste
ShouldStop(Event * event_ptr)127435933ddSDimitry Andric bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) {
128435933ddSDimitry Andric if (m_step_over) {
129ac7ddfbfSEd Maste Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
130ac7ddfbfSEd Maste
1317aa51b79SEd Maste StackFrameSP cur_frame_sp = m_thread.GetStackFrameAtIndex(0);
132435933ddSDimitry Andric if (!cur_frame_sp) {
1337aa51b79SEd Maste if (log)
134435933ddSDimitry Andric log->Printf(
135435933ddSDimitry Andric "ThreadPlanStepInstruction couldn't get the 0th frame, stopping.");
1367aa51b79SEd Maste SetPlanComplete();
1377aa51b79SEd Maste return true;
1387aa51b79SEd Maste }
1397aa51b79SEd Maste
1407aa51b79SEd Maste StackID cur_frame_zero_id = cur_frame_sp->GetStackID();
141ac7ddfbfSEd Maste
142435933ddSDimitry Andric if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id) {
143435933ddSDimitry Andric if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr) {
144435933ddSDimitry Andric if (--m_iteration_count <= 0) {
145ac7ddfbfSEd Maste SetPlanComplete();
146ac7ddfbfSEd Maste return true;
147435933ddSDimitry Andric } else {
148435933ddSDimitry Andric // We are still stepping, reset the start pc, and in case we've
1494ba319b5SDimitry Andric // stepped out, reset the current stack id.
1500127ef0fSEd Maste SetUpState();
1510127ef0fSEd Maste return false;
1520127ef0fSEd Maste }
153435933ddSDimitry Andric } else
154ac7ddfbfSEd Maste return false;
155435933ddSDimitry Andric } else {
156ac7ddfbfSEd Maste // We've stepped in, step back out again:
157ac7ddfbfSEd Maste StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
158435933ddSDimitry Andric if (return_frame) {
159435933ddSDimitry Andric if (return_frame->GetStackID() != m_parent_frame_id ||
160435933ddSDimitry Andric m_start_has_symbol) {
161435933ddSDimitry Andric // next-instruction shouldn't step out of inlined functions. But we
1624ba319b5SDimitry Andric // may have stepped into a real function that starts with an inlined
1634ba319b5SDimitry Andric // function, and we do want to step out of that...
1647aa51b79SEd Maste
165435933ddSDimitry Andric if (cur_frame_sp->IsInlined()) {
166435933ddSDimitry Andric StackFrameSP parent_frame_sp =
167435933ddSDimitry Andric m_thread.GetFrameWithStackID(m_stack_id);
1687aa51b79SEd Maste
169435933ddSDimitry Andric if (parent_frame_sp &&
170435933ddSDimitry Andric parent_frame_sp->GetConcreteFrameIndex() ==
171435933ddSDimitry Andric cur_frame_sp->GetConcreteFrameIndex()) {
1727aa51b79SEd Maste SetPlanComplete();
173435933ddSDimitry Andric if (log) {
174435933ddSDimitry Andric log->Printf("Frame we stepped into is inlined into the frame "
175435933ddSDimitry Andric "we were stepping from, stopping.");
1767aa51b79SEd Maste }
1777aa51b79SEd Maste return true;
1787aa51b79SEd Maste }
1797aa51b79SEd Maste }
1807aa51b79SEd Maste
181435933ddSDimitry Andric if (log) {
182ac7ddfbfSEd Maste StreamString s;
183ac7ddfbfSEd Maste s.PutCString("Stepped in to: ");
184435933ddSDimitry Andric addr_t stop_addr =
185435933ddSDimitry Andric m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
186435933ddSDimitry Andric s.Address(stop_addr, m_thread.CalculateTarget()
187435933ddSDimitry Andric ->GetArchitecture()
188435933ddSDimitry Andric .GetAddressByteSize());
189ac7ddfbfSEd Maste s.PutCString(" stepping out to: ");
190ac7ddfbfSEd Maste addr_t return_addr = return_frame->GetRegisterContext()->GetPC();
191435933ddSDimitry Andric s.Address(return_addr, m_thread.CalculateTarget()
192435933ddSDimitry Andric ->GetArchitecture()
193435933ddSDimitry Andric .GetAddressByteSize());
194ac7ddfbfSEd Maste log->Printf("%s.", s.GetData());
195ac7ddfbfSEd Maste }
196ac7ddfbfSEd Maste
1974ba319b5SDimitry Andric // StepInstruction should probably have the tri-state RunMode, but
1984ba319b5SDimitry Andric // for now it is safer to run others.
199ac7ddfbfSEd Maste const bool stop_others = false;
200435933ddSDimitry Andric m_thread.QueueThreadPlanForStepOutNoShouldStop(
201*b5893f02SDimitry Andric false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
202*b5893f02SDimitry Andric m_status);
203ac7ddfbfSEd Maste return false;
204435933ddSDimitry Andric } else {
205435933ddSDimitry Andric if (log) {
206435933ddSDimitry Andric log->PutCString(
207435933ddSDimitry Andric "The stack id we are stepping in changed, but our parent frame "
208435933ddSDimitry Andric "did not when stepping from code with no symbols. "
209ac7ddfbfSEd Maste "We are probably just confused about where we are, stopping.");
210ac7ddfbfSEd Maste }
211ac7ddfbfSEd Maste SetPlanComplete();
212ac7ddfbfSEd Maste return true;
213ac7ddfbfSEd Maste }
214435933ddSDimitry Andric } else {
215ac7ddfbfSEd Maste if (log)
216ac7ddfbfSEd Maste log->Printf("Could not find previous frame, stopping.");
217ac7ddfbfSEd Maste SetPlanComplete();
218ac7ddfbfSEd Maste return true;
219ac7ddfbfSEd Maste }
220ac7ddfbfSEd Maste }
221435933ddSDimitry Andric } else {
2224bb0738eSEd Maste lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC(0);
223435933ddSDimitry Andric if (pc_addr != m_instruction_addr) {
224435933ddSDimitry Andric if (--m_iteration_count <= 0) {
225ac7ddfbfSEd Maste SetPlanComplete();
226ac7ddfbfSEd Maste return true;
227435933ddSDimitry Andric } else {
228435933ddSDimitry Andric // We are still stepping, reset the start pc, and in case we've stepped
2294ba319b5SDimitry Andric // in or out, reset the current stack id.
2300127ef0fSEd Maste SetUpState();
2310127ef0fSEd Maste return false;
2320127ef0fSEd Maste }
233435933ddSDimitry Andric } else
234ac7ddfbfSEd Maste return false;
235ac7ddfbfSEd Maste }
236ac7ddfbfSEd Maste }
237ac7ddfbfSEd Maste
StopOthers()238435933ddSDimitry Andric bool ThreadPlanStepInstruction::StopOthers() { return m_stop_other_threads; }
239ac7ddfbfSEd Maste
GetPlanRunState()240435933ddSDimitry Andric StateType ThreadPlanStepInstruction::GetPlanRunState() {
241ac7ddfbfSEd Maste return eStateStepping;
242ac7ddfbfSEd Maste }
243ac7ddfbfSEd Maste
WillStop()244435933ddSDimitry Andric bool ThreadPlanStepInstruction::WillStop() { return true; }
245ac7ddfbfSEd Maste
MischiefManaged()246435933ddSDimitry Andric bool ThreadPlanStepInstruction::MischiefManaged() {
247435933ddSDimitry Andric if (IsPlanComplete()) {
248ac7ddfbfSEd Maste Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
249ac7ddfbfSEd Maste if (log)
250ac7ddfbfSEd Maste log->Printf("Completed single instruction step plan.");
251ac7ddfbfSEd Maste ThreadPlan::MischiefManaged();
252ac7ddfbfSEd Maste return true;
253435933ddSDimitry Andric } else {
254ac7ddfbfSEd Maste return false;
255ac7ddfbfSEd Maste }
256ac7ddfbfSEd Maste }
257