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 
1130fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepInstruction.h"
1230fdc8d8SChris Lattner 
1330fdc8d8SChris Lattner // C Includes
1430fdc8d8SChris Lattner // C++ Includes
1530fdc8d8SChris Lattner // Other libraries and framework includes
1630fdc8d8SChris Lattner // Project includes
1730fdc8d8SChris Lattner #include "lldb/lldb-private-log.h"
1830fdc8d8SChris Lattner #include "lldb/Core/Log.h"
1930fdc8d8SChris Lattner #include "lldb/Core/Stream.h"
2030fdc8d8SChris Lattner #include "lldb/Target/Process.h"
21f4b47e15SGreg Clayton #include "lldb/Target/RegisterContext.h"
22f4b47e15SGreg Clayton #include "lldb/Target/RegisterContext.h"
23f4b47e15SGreg Clayton #include "lldb/Target/StopInfo.h"
24f4b47e15SGreg Clayton #include "lldb/Target/Target.h"
2530fdc8d8SChris Lattner 
2630fdc8d8SChris Lattner using namespace lldb;
2730fdc8d8SChris Lattner using namespace lldb_private;
2830fdc8d8SChris Lattner 
2930fdc8d8SChris Lattner //----------------------------------------------------------------------
3030fdc8d8SChris Lattner // ThreadPlanStepInstruction: Step over the current instruction
3130fdc8d8SChris Lattner //----------------------------------------------------------------------
3230fdc8d8SChris Lattner 
3330fdc8d8SChris Lattner ThreadPlanStepInstruction::ThreadPlanStepInstruction
3430fdc8d8SChris Lattner (
3530fdc8d8SChris Lattner     Thread &thread,
3630fdc8d8SChris Lattner     bool step_over,
3730fdc8d8SChris Lattner     bool stop_other_threads,
3830fdc8d8SChris Lattner     Vote stop_vote,
3930fdc8d8SChris Lattner     Vote run_vote
4030fdc8d8SChris Lattner ) :
41b01e742aSJim Ingham     ThreadPlan (ThreadPlan::eKindStepInstruction, "Step over single instruction", thread, stop_vote, run_vote),
4230fdc8d8SChris Lattner     m_instruction_addr (0),
431ee0d4f7SBenjamin Kramer     m_stop_other_threads (stop_other_threads),
446b35c86fSJim Ingham     m_step_over (step_over)
451ee0d4f7SBenjamin Kramer {
46*7a88ec9aSJim Ingham     m_takes_iteration_count = true;
47*7a88ec9aSJim Ingham     SetUpState();
4830fdc8d8SChris Lattner }
4930fdc8d8SChris Lattner 
5030fdc8d8SChris Lattner ThreadPlanStepInstruction::~ThreadPlanStepInstruction ()
5130fdc8d8SChris Lattner {
5230fdc8d8SChris Lattner }
5330fdc8d8SChris Lattner 
5430fdc8d8SChris Lattner void
55*7a88ec9aSJim Ingham ThreadPlanStepInstruction::SetUpState()
56*7a88ec9aSJim Ingham {
57*7a88ec9aSJim Ingham     m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0);
58*7a88ec9aSJim Ingham     StackFrameSP start_frame_sp(m_thread.GetStackFrameAtIndex(0));
59*7a88ec9aSJim Ingham     m_stack_id = start_frame_sp->GetStackID();
60*7a88ec9aSJim Ingham 
61*7a88ec9aSJim Ingham     m_start_has_symbol = start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != NULL;
62*7a88ec9aSJim Ingham 
63*7a88ec9aSJim Ingham     StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1);
64*7a88ec9aSJim Ingham     if (parent_frame_sp)
65*7a88ec9aSJim Ingham         m_parent_frame_id = parent_frame_sp->GetStackID();
66*7a88ec9aSJim Ingham }
67*7a88ec9aSJim Ingham 
68*7a88ec9aSJim Ingham void
6930fdc8d8SChris Lattner ThreadPlanStepInstruction::GetDescription (Stream *s, lldb::DescriptionLevel level)
7030fdc8d8SChris Lattner {
7130fdc8d8SChris Lattner     if (level == lldb::eDescriptionLevelBrief)
7230fdc8d8SChris Lattner     {
7330fdc8d8SChris Lattner         if (m_step_over)
7430fdc8d8SChris Lattner             s->Printf ("instruction step over");
7530fdc8d8SChris Lattner         else
7630fdc8d8SChris Lattner             s->Printf ("instruction step into");
7730fdc8d8SChris Lattner     }
7830fdc8d8SChris Lattner     else
7930fdc8d8SChris Lattner     {
8030fdc8d8SChris Lattner         s->Printf ("Stepping one instruction past ");
8130fdc8d8SChris Lattner         s->Address(m_instruction_addr, sizeof (addr_t));
82a7d4822cSJim Ingham         if (!m_start_has_symbol)
83a7d4822cSJim Ingham             s->Printf(" which has no symbol");
84a7d4822cSJim Ingham 
8530fdc8d8SChris Lattner         if (m_step_over)
8630fdc8d8SChris Lattner             s->Printf(" stepping over calls");
8730fdc8d8SChris Lattner         else
8830fdc8d8SChris Lattner             s->Printf(" stepping into calls");
8930fdc8d8SChris Lattner     }
9030fdc8d8SChris Lattner }
9130fdc8d8SChris Lattner 
9230fdc8d8SChris Lattner bool
9330fdc8d8SChris Lattner ThreadPlanStepInstruction::ValidatePlan (Stream *error)
9430fdc8d8SChris Lattner {
9530fdc8d8SChris Lattner     // Since we read the instruction we're stepping over from the thread,
9630fdc8d8SChris Lattner     // this plan will always work.
9730fdc8d8SChris Lattner     return true;
9830fdc8d8SChris Lattner }
9930fdc8d8SChris Lattner 
10030fdc8d8SChris Lattner bool
101221d51cfSJim Ingham ThreadPlanStepInstruction::DoPlanExplainsStop (Event *event_ptr)
10230fdc8d8SChris Lattner {
10360c4118cSJim Ingham     StopInfoSP stop_info_sp = GetPrivateStopInfo ();
104b15bfc75SJim Ingham     if (stop_info_sp)
10530fdc8d8SChris Lattner     {
106b15bfc75SJim Ingham         StopReason reason = stop_info_sp->GetStopReason();
10730fdc8d8SChris Lattner         if (reason == eStopReasonTrace || reason == eStopReasonNone)
10830fdc8d8SChris Lattner             return true;
10930fdc8d8SChris Lattner         else
11030fdc8d8SChris Lattner             return false;
11130fdc8d8SChris Lattner     }
11230fdc8d8SChris Lattner     return false;
11330fdc8d8SChris Lattner }
11430fdc8d8SChris Lattner 
11530fdc8d8SChris Lattner bool
116*7a88ec9aSJim Ingham ThreadPlanStepInstruction::IsPlanStale ()
117*7a88ec9aSJim Ingham {
118*7a88ec9aSJim Ingham     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
119*7a88ec9aSJim Ingham     StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
120*7a88ec9aSJim Ingham     if (cur_frame_id == m_stack_id)
121*7a88ec9aSJim Ingham     {
122*7a88ec9aSJim Ingham         if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
123*7a88ec9aSJim Ingham             return true;
124*7a88ec9aSJim Ingham         else
125*7a88ec9aSJim Ingham             return false;
126*7a88ec9aSJim Ingham     }
127*7a88ec9aSJim Ingham     else if (cur_frame_id < m_stack_id)
128*7a88ec9aSJim Ingham     {
129*7a88ec9aSJim Ingham         // If the current frame is younger than the start frame and we are stepping over, then we need to continue,
130*7a88ec9aSJim Ingham         // but if we are doing just one step, we're done.
131*7a88ec9aSJim Ingham         if (m_step_over)
132*7a88ec9aSJim Ingham             return false;
133*7a88ec9aSJim Ingham         else
134*7a88ec9aSJim Ingham             return true;
135*7a88ec9aSJim Ingham     }
136*7a88ec9aSJim Ingham     else
137*7a88ec9aSJim Ingham     {
138*7a88ec9aSJim Ingham         if (log)
139*7a88ec9aSJim Ingham         {
140*7a88ec9aSJim Ingham             log->Printf ("ThreadPlanStepInstruction::IsPlanStale - Current frame is older than start frame, plan is stale.");
141*7a88ec9aSJim Ingham         }
142*7a88ec9aSJim Ingham         return true;
143*7a88ec9aSJim Ingham     }
144*7a88ec9aSJim Ingham }
145*7a88ec9aSJim Ingham 
146*7a88ec9aSJim Ingham bool
14730fdc8d8SChris Lattner ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
14830fdc8d8SChris Lattner {
14930fdc8d8SChris Lattner     if (m_step_over)
15030fdc8d8SChris Lattner     {
1515160ce5cSGreg Clayton         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
1526b35c86fSJim Ingham 
1536b35c86fSJim Ingham         StackID cur_frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
1546b35c86fSJim Ingham 
1556b35c86fSJim Ingham         if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id)
15630fdc8d8SChris Lattner         {
15730fdc8d8SChris Lattner             if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
15830fdc8d8SChris Lattner             {
159*7a88ec9aSJim Ingham                 if (--m_iteration_count <= 0)
160*7a88ec9aSJim Ingham                 {
16130fdc8d8SChris Lattner                     SetPlanComplete();
16230fdc8d8SChris Lattner                     return true;
16330fdc8d8SChris Lattner                 }
16430fdc8d8SChris Lattner                 else
165*7a88ec9aSJim Ingham                 {
166*7a88ec9aSJim Ingham                     // We are still stepping, reset the start pc, and in case we've stepped out,
167*7a88ec9aSJim Ingham                     // reset the current stack id.
168*7a88ec9aSJim Ingham                     SetUpState();
169*7a88ec9aSJim Ingham                     return false;
170*7a88ec9aSJim Ingham                 }
171*7a88ec9aSJim Ingham             }
172*7a88ec9aSJim Ingham             else
17330fdc8d8SChris Lattner                 return false;
17430fdc8d8SChris Lattner         }
17530fdc8d8SChris Lattner         else
17630fdc8d8SChris Lattner         {
17730fdc8d8SChris Lattner             // We've stepped in, step back out again:
178b57e4a1bSJason Molenda             StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
17930fdc8d8SChris Lattner             if (return_frame)
18030fdc8d8SChris Lattner             {
181a7d4822cSJim Ingham                 if (return_frame->GetStackID() != m_parent_frame_id || m_start_has_symbol)
182886a3e2cSJim Ingham                 {
18330fdc8d8SChris Lattner                     if (log)
18430fdc8d8SChris Lattner                     {
18530fdc8d8SChris Lattner                         StreamString s;
18630fdc8d8SChris Lattner                         s.PutCString ("Stepped in to: ");
1879da7bd07SGreg Clayton                         addr_t stop_addr = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
1881ac04c30SGreg Clayton                         s.Address (stop_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
18930fdc8d8SChris Lattner                         s.PutCString (" stepping out to: ");
1909da7bd07SGreg Clayton                         addr_t return_addr = return_frame->GetRegisterContext()->GetPC();
1911ac04c30SGreg Clayton                         s.Address (return_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
19230fdc8d8SChris Lattner                         log->Printf("%s.", s.GetData());
19330fdc8d8SChris Lattner                     }
1944a58e968SJim Ingham 
1954a58e968SJim Ingham                     // StepInstruction should probably have the tri-state RunMode, but for now it is safer to
1964a58e968SJim Ingham                     // run others.
1974a58e968SJim Ingham                     const bool stop_others = false;
1984b4b2478SJim Ingham                     m_thread.QueueThreadPlanForStepOutNoShouldStop(false,
19964e7ead1SJim Ingham                                                                    NULL,
20064e7ead1SJim Ingham                                                                    true,
2014a58e968SJim Ingham                                                                    stop_others,
20264e7ead1SJim Ingham                                                                    eVoteNo,
20364e7ead1SJim Ingham                                                                    eVoteNoOpinion,
20464e7ead1SJim Ingham                                                                    0);
20530fdc8d8SChris Lattner                     return false;
20630fdc8d8SChris Lattner                 }
20730fdc8d8SChris Lattner                 else
20830fdc8d8SChris Lattner                 {
20930fdc8d8SChris Lattner                     if (log)
210886a3e2cSJim Ingham                     {
211a7d4822cSJim Ingham                         log->PutCString("The stack id we are stepping in changed, but our parent frame did not when stepping from code with no symbols.  "
212886a3e2cSJim Ingham                         "We are probably just confused about where we are, stopping.");
213886a3e2cSJim Ingham                     }
214886a3e2cSJim Ingham                     SetPlanComplete();
215886a3e2cSJim Ingham                     return true;
216886a3e2cSJim Ingham                 }
217886a3e2cSJim Ingham             }
218886a3e2cSJim Ingham             else
219886a3e2cSJim Ingham             {
220886a3e2cSJim Ingham                 if (log)
22130fdc8d8SChris Lattner                     log->Printf("Could not find previous frame, stopping.");
22230fdc8d8SChris Lattner                 SetPlanComplete();
22330fdc8d8SChris Lattner                 return true;
22430fdc8d8SChris Lattner             }
22530fdc8d8SChris Lattner 
22630fdc8d8SChris Lattner         }
22730fdc8d8SChris Lattner 
22830fdc8d8SChris Lattner     }
22930fdc8d8SChris Lattner     else
23030fdc8d8SChris Lattner     {
23130fdc8d8SChris Lattner         if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
23230fdc8d8SChris Lattner         {
233*7a88ec9aSJim Ingham             if (--m_iteration_count <= 0)
234*7a88ec9aSJim Ingham             {
23530fdc8d8SChris Lattner                 SetPlanComplete();
23630fdc8d8SChris Lattner                 return true;
23730fdc8d8SChris Lattner             }
23830fdc8d8SChris Lattner             else
239*7a88ec9aSJim Ingham             {
240*7a88ec9aSJim Ingham                 // We are still stepping, reset the start pc, and in case we've stepped in or out,
241*7a88ec9aSJim Ingham                 // reset the current stack id.
242*7a88ec9aSJim Ingham                 SetUpState();
243*7a88ec9aSJim Ingham                 return false;
244*7a88ec9aSJim Ingham             }
245*7a88ec9aSJim Ingham         }
246*7a88ec9aSJim Ingham         else
24730fdc8d8SChris Lattner             return false;
24830fdc8d8SChris Lattner     }
24930fdc8d8SChris Lattner }
25030fdc8d8SChris Lattner 
25130fdc8d8SChris Lattner bool
25230fdc8d8SChris Lattner ThreadPlanStepInstruction::StopOthers ()
25330fdc8d8SChris Lattner {
25430fdc8d8SChris Lattner     return m_stop_other_threads;
25530fdc8d8SChris Lattner }
25630fdc8d8SChris Lattner 
25730fdc8d8SChris Lattner StateType
25806e827ccSJim Ingham ThreadPlanStepInstruction::GetPlanRunState ()
25930fdc8d8SChris Lattner {
26030fdc8d8SChris Lattner     return eStateStepping;
26130fdc8d8SChris Lattner }
26230fdc8d8SChris Lattner 
26330fdc8d8SChris Lattner bool
26430fdc8d8SChris Lattner ThreadPlanStepInstruction::WillStop ()
26530fdc8d8SChris Lattner {
26630fdc8d8SChris Lattner     return true;
26730fdc8d8SChris Lattner }
26830fdc8d8SChris Lattner 
26930fdc8d8SChris Lattner bool
27030fdc8d8SChris Lattner ThreadPlanStepInstruction::MischiefManaged ()
27130fdc8d8SChris Lattner {
27230fdc8d8SChris Lattner     if (IsPlanComplete())
27330fdc8d8SChris Lattner     {
2745160ce5cSGreg Clayton         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
27530fdc8d8SChris Lattner         if (log)
27630fdc8d8SChris Lattner             log->Printf("Completed single instruction step plan.");
27730fdc8d8SChris Lattner         ThreadPlan::MischiefManaged ();
27830fdc8d8SChris Lattner         return true;
27930fdc8d8SChris Lattner     }
28030fdc8d8SChris Lattner     else
28130fdc8d8SChris Lattner     {
28230fdc8d8SChris Lattner         return false;
28330fdc8d8SChris Lattner     }
28430fdc8d8SChris Lattner }
28530fdc8d8SChris Lattner 
286