1 //===-- ThreadPlanStepInstruction.cpp ---------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 
11 #include "lldb/Target/ThreadPlanStepInstruction.h"
12 
13 // C Includes
14 // C++ Includes
15 // Other libraries and framework includes
16 // Project includes
17 #include "lldb/lldb-private-log.h"
18 #include "lldb/Core/Log.h"
19 #include "lldb/Core/Stream.h"
20 #include "lldb/Target/Process.h"
21 #include "lldb/Target/RegisterContext.h"
22 #include "lldb/Target/RegisterContext.h"
23 #include "lldb/Target/StopInfo.h"
24 #include "lldb/Target/Target.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 //----------------------------------------------------------------------
30 // ThreadPlanStepInstruction: Step over the current instruction
31 //----------------------------------------------------------------------
32 
33 ThreadPlanStepInstruction::ThreadPlanStepInstruction
34 (
35     Thread &thread,
36     bool step_over,
37     bool stop_other_threads,
38     Vote stop_vote,
39     Vote run_vote
40 ) :
41     ThreadPlan (ThreadPlan::eKindStepInstruction, "Step over single instruction", thread, stop_vote, run_vote),
42     m_instruction_addr (0),
43     m_stop_other_threads (stop_other_threads),
44     m_step_over (step_over)
45 {
46     m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0);
47     m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
48 }
49 
50 ThreadPlanStepInstruction::~ThreadPlanStepInstruction ()
51 {
52 }
53 
54 void
55 ThreadPlanStepInstruction::GetDescription (Stream *s, lldb::DescriptionLevel level)
56 {
57     if (level == lldb::eDescriptionLevelBrief)
58     {
59         if (m_step_over)
60             s->Printf ("instruction step over");
61         else
62             s->Printf ("instruction step into");
63     }
64     else
65     {
66         s->Printf ("Stepping one instruction past ");
67         s->Address(m_instruction_addr, sizeof (addr_t));
68         if (m_step_over)
69             s->Printf(" stepping over calls");
70         else
71             s->Printf(" stepping into calls");
72     }
73 }
74 
75 bool
76 ThreadPlanStepInstruction::ValidatePlan (Stream *error)
77 {
78     // Since we read the instruction we're stepping over from the thread,
79     // this plan will always work.
80     return true;
81 }
82 
83 bool
84 ThreadPlanStepInstruction::PlanExplainsStop (Event *event_ptr)
85 {
86     StopInfoSP stop_info_sp = GetPrivateStopReason();
87     if (stop_info_sp)
88     {
89         StopReason reason = stop_info_sp->GetStopReason();
90         if (reason == eStopReasonTrace || reason == eStopReasonNone)
91             return true;
92         else
93             return false;
94     }
95     return false;
96 }
97 
98 bool
99 ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
100 {
101     if (m_step_over)
102     {
103         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
104 
105         StackID cur_frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
106 
107         if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id)
108         {
109             if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
110             {
111                 SetPlanComplete();
112                 return true;
113             }
114             else
115                 return false;
116         }
117         else
118         {
119             // We've stepped in, step back out again:
120             StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
121             if (return_frame)
122             {
123                 if (log)
124                 {
125                     StreamString s;
126                     s.PutCString ("Stepped in to: ");
127                     addr_t stop_addr = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
128                     s.Address (stop_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
129                     s.PutCString (" stepping out to: ");
130                     addr_t return_addr = return_frame->GetRegisterContext()->GetPC();
131                     s.Address (return_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
132                     log->Printf("%s.", s.GetData());
133                 }
134 
135                 // StepInstruction should probably have the tri-state RunMode, but for now it is safer to
136                 // run others.
137                 const bool stop_others = false;
138                 m_thread.QueueThreadPlanForStepOut(false,
139                                                    NULL,
140                                                    true,
141                                                    stop_others,
142                                                    eVoteNo,
143                                                    eVoteNoOpinion,
144                                                    0);
145                 return false;
146             }
147             else
148             {
149                 if (log)
150                     log->Printf("Could not find previous frame, stopping.");
151                 SetPlanComplete();
152                 return true;
153             }
154 
155         }
156 
157     }
158     else
159     {
160         if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
161         {
162             SetPlanComplete();
163             return true;
164         }
165         else
166             return false;
167     }
168 }
169 
170 bool
171 ThreadPlanStepInstruction::StopOthers ()
172 {
173     return m_stop_other_threads;
174 }
175 
176 StateType
177 ThreadPlanStepInstruction::GetPlanRunState ()
178 {
179     return eStateStepping;
180 }
181 
182 bool
183 ThreadPlanStepInstruction::WillStop ()
184 {
185     return true;
186 }
187 
188 bool
189 ThreadPlanStepInstruction::MischiefManaged ()
190 {
191     if (IsPlanComplete())
192     {
193         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
194         if (log)
195             log->Printf("Completed single instruction step plan.");
196         ThreadPlan::MischiefManaged ();
197         return true;
198     }
199     else
200     {
201         return false;
202     }
203 }
204 
205