130fdc8d8SChris Lattner //===-- ThreadPlanStepInstruction.cpp ---------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner 
1030fdc8d8SChris Lattner // C Includes
1130fdc8d8SChris Lattner // C++ Includes
1230fdc8d8SChris Lattner // Other libraries and framework includes
1330fdc8d8SChris Lattner // Project includes
14*e65b2cf2SEugene Zelenko #include "lldb/Target/ThreadPlanStepInstruction.h"
1530fdc8d8SChris Lattner #include "lldb/Core/Log.h"
1630fdc8d8SChris Lattner #include "lldb/Core/Stream.h"
1730fdc8d8SChris Lattner #include "lldb/Target/Process.h"
18f4b47e15SGreg Clayton #include "lldb/Target/RegisterContext.h"
19f4b47e15SGreg Clayton #include "lldb/Target/RegisterContext.h"
20f4b47e15SGreg Clayton #include "lldb/Target/StopInfo.h"
21f4b47e15SGreg Clayton #include "lldb/Target/Target.h"
2230fdc8d8SChris Lattner 
2330fdc8d8SChris Lattner using namespace lldb;
2430fdc8d8SChris Lattner using namespace lldb_private;
2530fdc8d8SChris Lattner 
2630fdc8d8SChris Lattner //----------------------------------------------------------------------
2730fdc8d8SChris Lattner // ThreadPlanStepInstruction: Step over the current instruction
2830fdc8d8SChris Lattner //----------------------------------------------------------------------
2930fdc8d8SChris Lattner 
3030fdc8d8SChris Lattner ThreadPlanStepInstruction::ThreadPlanStepInstruction
3130fdc8d8SChris Lattner (
3230fdc8d8SChris Lattner     Thread &thread,
3330fdc8d8SChris Lattner     bool step_over,
3430fdc8d8SChris Lattner     bool stop_other_threads,
3530fdc8d8SChris Lattner     Vote stop_vote,
3630fdc8d8SChris Lattner     Vote run_vote
3730fdc8d8SChris Lattner ) :
38b01e742aSJim Ingham     ThreadPlan (ThreadPlan::eKindStepInstruction, "Step over single instruction", thread, stop_vote, run_vote),
3930fdc8d8SChris Lattner     m_instruction_addr (0),
401ee0d4f7SBenjamin Kramer     m_stop_other_threads (stop_other_threads),
416b35c86fSJim Ingham     m_step_over (step_over)
421ee0d4f7SBenjamin Kramer {
437a88ec9aSJim Ingham     m_takes_iteration_count = true;
447a88ec9aSJim Ingham     SetUpState();
4530fdc8d8SChris Lattner }
4630fdc8d8SChris Lattner 
47*e65b2cf2SEugene Zelenko ThreadPlanStepInstruction::~ThreadPlanStepInstruction() = default;
4830fdc8d8SChris Lattner 
4930fdc8d8SChris Lattner void
507a88ec9aSJim Ingham ThreadPlanStepInstruction::SetUpState()
517a88ec9aSJim Ingham {
527a88ec9aSJim Ingham     m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0);
537a88ec9aSJim Ingham     StackFrameSP start_frame_sp(m_thread.GetStackFrameAtIndex(0));
547a88ec9aSJim Ingham     m_stack_id = start_frame_sp->GetStackID();
557a88ec9aSJim Ingham 
56*e65b2cf2SEugene Zelenko     m_start_has_symbol = start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != nullptr;
577a88ec9aSJim Ingham 
587a88ec9aSJim Ingham     StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1);
597a88ec9aSJim Ingham     if (parent_frame_sp)
607a88ec9aSJim Ingham         m_parent_frame_id = parent_frame_sp->GetStackID();
617a88ec9aSJim Ingham }
627a88ec9aSJim Ingham 
637a88ec9aSJim Ingham void
6430fdc8d8SChris Lattner ThreadPlanStepInstruction::GetDescription (Stream *s, lldb::DescriptionLevel level)
6530fdc8d8SChris Lattner {
6630fdc8d8SChris Lattner     if (level == lldb::eDescriptionLevelBrief)
6730fdc8d8SChris Lattner     {
6830fdc8d8SChris Lattner         if (m_step_over)
6930fdc8d8SChris Lattner             s->Printf ("instruction step over");
7030fdc8d8SChris Lattner         else
7130fdc8d8SChris Lattner             s->Printf ("instruction step into");
7230fdc8d8SChris Lattner     }
7330fdc8d8SChris Lattner     else
7430fdc8d8SChris Lattner     {
7530fdc8d8SChris Lattner         s->Printf ("Stepping one instruction past ");
7630fdc8d8SChris Lattner         s->Address(m_instruction_addr, sizeof (addr_t));
77a7d4822cSJim Ingham         if (!m_start_has_symbol)
78a7d4822cSJim Ingham             s->Printf(" which has no symbol");
79a7d4822cSJim Ingham 
8030fdc8d8SChris Lattner         if (m_step_over)
8130fdc8d8SChris Lattner             s->Printf(" stepping over calls");
8230fdc8d8SChris Lattner         else
8330fdc8d8SChris Lattner             s->Printf(" stepping into calls");
8430fdc8d8SChris Lattner     }
8530fdc8d8SChris Lattner }
8630fdc8d8SChris Lattner 
8730fdc8d8SChris Lattner bool
8830fdc8d8SChris Lattner ThreadPlanStepInstruction::ValidatePlan (Stream *error)
8930fdc8d8SChris Lattner {
9030fdc8d8SChris Lattner     // Since we read the instruction we're stepping over from the thread,
9130fdc8d8SChris Lattner     // this plan will always work.
9230fdc8d8SChris Lattner     return true;
9330fdc8d8SChris Lattner }
9430fdc8d8SChris Lattner 
9530fdc8d8SChris Lattner bool
96221d51cfSJim Ingham ThreadPlanStepInstruction::DoPlanExplainsStop (Event *event_ptr)
9730fdc8d8SChris Lattner {
9860c4118cSJim Ingham     StopInfoSP stop_info_sp = GetPrivateStopInfo ();
99b15bfc75SJim Ingham     if (stop_info_sp)
10030fdc8d8SChris Lattner     {
101b15bfc75SJim Ingham         StopReason reason = stop_info_sp->GetStopReason();
102*e65b2cf2SEugene Zelenko         return (reason == eStopReasonTrace || reason == eStopReasonNone);
10330fdc8d8SChris Lattner     }
10430fdc8d8SChris Lattner     return false;
10530fdc8d8SChris Lattner }
10630fdc8d8SChris Lattner 
10730fdc8d8SChris Lattner bool
1087a88ec9aSJim Ingham ThreadPlanStepInstruction::IsPlanStale ()
1097a88ec9aSJim Ingham {
1107a88ec9aSJim Ingham     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
1117a88ec9aSJim Ingham     StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
1127a88ec9aSJim Ingham     if (cur_frame_id == m_stack_id)
1137a88ec9aSJim Ingham     {
114*e65b2cf2SEugene Zelenko         return (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr);
1157a88ec9aSJim Ingham     }
1167a88ec9aSJim Ingham     else if (cur_frame_id < m_stack_id)
1177a88ec9aSJim Ingham     {
1187a88ec9aSJim Ingham         // If the current frame is younger than the start frame and we are stepping over, then we need to continue,
1197a88ec9aSJim Ingham         // but if we are doing just one step, we're done.
120*e65b2cf2SEugene Zelenko         return !m_step_over;
1217a88ec9aSJim Ingham     }
1227a88ec9aSJim Ingham     else
1237a88ec9aSJim Ingham     {
1247a88ec9aSJim Ingham         if (log)
1257a88ec9aSJim Ingham         {
1267a88ec9aSJim Ingham             log->Printf ("ThreadPlanStepInstruction::IsPlanStale - Current frame is older than start frame, plan is stale.");
1277a88ec9aSJim Ingham         }
1287a88ec9aSJim Ingham         return true;
1297a88ec9aSJim Ingham     }
1307a88ec9aSJim Ingham }
1317a88ec9aSJim Ingham 
1327a88ec9aSJim Ingham bool
13330fdc8d8SChris Lattner ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
13430fdc8d8SChris Lattner {
13530fdc8d8SChris Lattner     if (m_step_over)
13630fdc8d8SChris Lattner     {
1375160ce5cSGreg Clayton         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
1386b35c86fSJim Ingham 
139c0b4d5a1SJim Ingham         StackFrameSP cur_frame_sp = m_thread.GetStackFrameAtIndex(0);
140c0b4d5a1SJim Ingham         if (!cur_frame_sp)
141c0b4d5a1SJim Ingham         {
142c0b4d5a1SJim Ingham             if (log)
143c0b4d5a1SJim Ingham                 log->Printf ("ThreadPlanStepInstruction couldn't get the 0th frame, stopping.");
144c0b4d5a1SJim Ingham             SetPlanComplete();
145c0b4d5a1SJim Ingham             return true;
146c0b4d5a1SJim Ingham         }
147c0b4d5a1SJim Ingham 
148c0b4d5a1SJim Ingham         StackID cur_frame_zero_id = cur_frame_sp->GetStackID();
1496b35c86fSJim Ingham 
1506b35c86fSJim Ingham         if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id)
15130fdc8d8SChris Lattner         {
15230fdc8d8SChris Lattner             if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
15330fdc8d8SChris Lattner             {
1547a88ec9aSJim Ingham                 if (--m_iteration_count <= 0)
1557a88ec9aSJim Ingham                 {
15630fdc8d8SChris Lattner                     SetPlanComplete();
15730fdc8d8SChris Lattner                     return true;
15830fdc8d8SChris Lattner                 }
15930fdc8d8SChris Lattner                 else
1607a88ec9aSJim Ingham                 {
1617a88ec9aSJim Ingham                     // We are still stepping, reset the start pc, and in case we've stepped out,
1627a88ec9aSJim Ingham                     // reset the current stack id.
1637a88ec9aSJim Ingham                     SetUpState();
1647a88ec9aSJim Ingham                     return false;
1657a88ec9aSJim Ingham                 }
1667a88ec9aSJim Ingham             }
1677a88ec9aSJim Ingham             else
16830fdc8d8SChris Lattner                 return false;
16930fdc8d8SChris Lattner         }
17030fdc8d8SChris Lattner         else
17130fdc8d8SChris Lattner         {
17230fdc8d8SChris Lattner             // We've stepped in, step back out again:
173b57e4a1bSJason Molenda             StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
17430fdc8d8SChris Lattner             if (return_frame)
17530fdc8d8SChris Lattner             {
176a7d4822cSJim Ingham                 if (return_frame->GetStackID() != m_parent_frame_id || m_start_has_symbol)
177886a3e2cSJim Ingham                 {
178c0b4d5a1SJim Ingham                     // next-instruction shouldn't step out of inlined functions.  But we may have stepped into a
179c0b4d5a1SJim Ingham                     // real function that starts with an inlined function, and we do want to step out of that...
180c0b4d5a1SJim Ingham 
181c0b4d5a1SJim Ingham                     if (cur_frame_sp->IsInlined())
182c0b4d5a1SJim Ingham                     {
183c0b4d5a1SJim Ingham                         StackFrameSP parent_frame_sp = m_thread.GetFrameWithStackID(m_stack_id);
184c0b4d5a1SJim Ingham 
185c0b4d5a1SJim Ingham                         if(parent_frame_sp && parent_frame_sp->GetConcreteFrameIndex() == cur_frame_sp->GetConcreteFrameIndex())
186c0b4d5a1SJim Ingham                         {
187c0b4d5a1SJim Ingham                             SetPlanComplete();
188c0b4d5a1SJim Ingham                             if (log)
189c0b4d5a1SJim Ingham                             {
190c0b4d5a1SJim Ingham                                 log->Printf("Frame we stepped into is inlined into the frame we were stepping from, stopping.");
191c0b4d5a1SJim Ingham                             }
192c0b4d5a1SJim Ingham                             return true;
193c0b4d5a1SJim Ingham                         }
194c0b4d5a1SJim Ingham                     }
195c0b4d5a1SJim Ingham 
19630fdc8d8SChris Lattner                     if (log)
19730fdc8d8SChris Lattner                     {
19830fdc8d8SChris Lattner                         StreamString s;
19930fdc8d8SChris Lattner                         s.PutCString ("Stepped in to: ");
2009da7bd07SGreg Clayton                         addr_t stop_addr = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
2011ac04c30SGreg Clayton                         s.Address (stop_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
20230fdc8d8SChris Lattner                         s.PutCString (" stepping out to: ");
2039da7bd07SGreg Clayton                         addr_t return_addr = return_frame->GetRegisterContext()->GetPC();
2041ac04c30SGreg Clayton                         s.Address (return_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
20530fdc8d8SChris Lattner                         log->Printf("%s.", s.GetData());
20630fdc8d8SChris Lattner                     }
2074a58e968SJim Ingham 
2084a58e968SJim Ingham                     // StepInstruction should probably have the tri-state RunMode, but for now it is safer to
2094a58e968SJim Ingham                     // run others.
2104a58e968SJim Ingham                     const bool stop_others = false;
2114b4b2478SJim Ingham                     m_thread.QueueThreadPlanForStepOutNoShouldStop(false,
212*e65b2cf2SEugene Zelenko                                                                    nullptr,
21364e7ead1SJim Ingham                                                                    true,
2144a58e968SJim Ingham                                                                    stop_others,
21564e7ead1SJim Ingham                                                                    eVoteNo,
21664e7ead1SJim Ingham                                                                    eVoteNoOpinion,
21764e7ead1SJim Ingham                                                                    0);
21830fdc8d8SChris Lattner                     return false;
21930fdc8d8SChris Lattner                 }
22030fdc8d8SChris Lattner                 else
22130fdc8d8SChris Lattner                 {
22230fdc8d8SChris Lattner                     if (log)
223886a3e2cSJim Ingham                     {
224a7d4822cSJim Ingham                         log->PutCString("The stack id we are stepping in changed, but our parent frame did not when stepping from code with no symbols.  "
225886a3e2cSJim Ingham                         "We are probably just confused about where we are, stopping.");
226886a3e2cSJim Ingham                     }
227886a3e2cSJim Ingham                     SetPlanComplete();
228886a3e2cSJim Ingham                     return true;
229886a3e2cSJim Ingham                 }
230886a3e2cSJim Ingham             }
231886a3e2cSJim Ingham             else
232886a3e2cSJim Ingham             {
233886a3e2cSJim Ingham                 if (log)
23430fdc8d8SChris Lattner                     log->Printf("Could not find previous frame, stopping.");
23530fdc8d8SChris Lattner                 SetPlanComplete();
23630fdc8d8SChris Lattner                 return true;
23730fdc8d8SChris Lattner             }
23830fdc8d8SChris Lattner         }
23930fdc8d8SChris Lattner     }
24030fdc8d8SChris Lattner     else
24130fdc8d8SChris Lattner     {
24230fdc8d8SChris Lattner         if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
24330fdc8d8SChris Lattner         {
2447a88ec9aSJim Ingham             if (--m_iteration_count <= 0)
2457a88ec9aSJim Ingham             {
24630fdc8d8SChris Lattner                 SetPlanComplete();
24730fdc8d8SChris Lattner                 return true;
24830fdc8d8SChris Lattner             }
24930fdc8d8SChris Lattner             else
2507a88ec9aSJim Ingham             {
2517a88ec9aSJim Ingham                 // We are still stepping, reset the start pc, and in case we've stepped in or out,
2527a88ec9aSJim Ingham                 // reset the current stack id.
2537a88ec9aSJim Ingham                 SetUpState();
2547a88ec9aSJim Ingham                 return false;
2557a88ec9aSJim Ingham             }
2567a88ec9aSJim Ingham         }
2577a88ec9aSJim Ingham         else
25830fdc8d8SChris Lattner             return false;
25930fdc8d8SChris Lattner     }
26030fdc8d8SChris Lattner }
26130fdc8d8SChris Lattner 
26230fdc8d8SChris Lattner bool
26330fdc8d8SChris Lattner ThreadPlanStepInstruction::StopOthers ()
26430fdc8d8SChris Lattner {
26530fdc8d8SChris Lattner     return m_stop_other_threads;
26630fdc8d8SChris Lattner }
26730fdc8d8SChris Lattner 
26830fdc8d8SChris Lattner StateType
26906e827ccSJim Ingham ThreadPlanStepInstruction::GetPlanRunState ()
27030fdc8d8SChris Lattner {
27130fdc8d8SChris Lattner     return eStateStepping;
27230fdc8d8SChris Lattner }
27330fdc8d8SChris Lattner 
27430fdc8d8SChris Lattner bool
27530fdc8d8SChris Lattner ThreadPlanStepInstruction::WillStop ()
27630fdc8d8SChris Lattner {
27730fdc8d8SChris Lattner     return true;
27830fdc8d8SChris Lattner }
27930fdc8d8SChris Lattner 
28030fdc8d8SChris Lattner bool
28130fdc8d8SChris Lattner ThreadPlanStepInstruction::MischiefManaged ()
28230fdc8d8SChris Lattner {
28330fdc8d8SChris Lattner     if (IsPlanComplete())
28430fdc8d8SChris Lattner     {
2855160ce5cSGreg Clayton         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
28630fdc8d8SChris Lattner         if (log)
28730fdc8d8SChris Lattner             log->Printf("Completed single instruction step plan.");
28830fdc8d8SChris Lattner         ThreadPlan::MischiefManaged ();
28930fdc8d8SChris Lattner         return true;
29030fdc8d8SChris Lattner     }
29130fdc8d8SChris Lattner     else
29230fdc8d8SChris Lattner     {
29330fdc8d8SChris Lattner         return false;
29430fdc8d8SChris Lattner     }
29530fdc8d8SChris Lattner }
296