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