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_takes_iteration_count = true;
47     SetUpState();
48 }
49 
50 ThreadPlanStepInstruction::~ThreadPlanStepInstruction ()
51 {
52 }
53 
54 void
55 ThreadPlanStepInstruction::SetUpState()
56 {
57     m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0);
58     StackFrameSP start_frame_sp(m_thread.GetStackFrameAtIndex(0));
59     m_stack_id = start_frame_sp->GetStackID();
60 
61     m_start_has_symbol = start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != NULL;
62 
63     StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1);
64     if (parent_frame_sp)
65         m_parent_frame_id = parent_frame_sp->GetStackID();
66 }
67 
68 void
69 ThreadPlanStepInstruction::GetDescription (Stream *s, lldb::DescriptionLevel level)
70 {
71     if (level == lldb::eDescriptionLevelBrief)
72     {
73         if (m_step_over)
74             s->Printf ("instruction step over");
75         else
76             s->Printf ("instruction step into");
77     }
78     else
79     {
80         s->Printf ("Stepping one instruction past ");
81         s->Address(m_instruction_addr, sizeof (addr_t));
82         if (!m_start_has_symbol)
83             s->Printf(" which has no symbol");
84 
85         if (m_step_over)
86             s->Printf(" stepping over calls");
87         else
88             s->Printf(" stepping into calls");
89     }
90 }
91 
92 bool
93 ThreadPlanStepInstruction::ValidatePlan (Stream *error)
94 {
95     // Since we read the instruction we're stepping over from the thread,
96     // this plan will always work.
97     return true;
98 }
99 
100 bool
101 ThreadPlanStepInstruction::DoPlanExplainsStop (Event *event_ptr)
102 {
103     StopInfoSP stop_info_sp = GetPrivateStopInfo ();
104     if (stop_info_sp)
105     {
106         StopReason reason = stop_info_sp->GetStopReason();
107         if (reason == eStopReasonTrace || reason == eStopReasonNone)
108             return true;
109         else
110             return false;
111     }
112     return false;
113 }
114 
115 bool
116 ThreadPlanStepInstruction::IsPlanStale ()
117 {
118     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
119     StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
120     if (cur_frame_id == m_stack_id)
121     {
122         if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
123             return true;
124         else
125             return false;
126     }
127     else if (cur_frame_id < m_stack_id)
128     {
129         // If the current frame is younger than the start frame and we are stepping over, then we need to continue,
130         // but if we are doing just one step, we're done.
131         if (m_step_over)
132             return false;
133         else
134             return true;
135     }
136     else
137     {
138         if (log)
139         {
140             log->Printf ("ThreadPlanStepInstruction::IsPlanStale - Current frame is older than start frame, plan is stale.");
141         }
142         return true;
143     }
144 }
145 
146 bool
147 ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
148 {
149     if (m_step_over)
150     {
151         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
152 
153         StackFrameSP cur_frame_sp = m_thread.GetStackFrameAtIndex(0);
154         if (!cur_frame_sp)
155         {
156             if (log)
157                 log->Printf ("ThreadPlanStepInstruction couldn't get the 0th frame, stopping.");
158             SetPlanComplete();
159             return true;
160         }
161 
162         StackID cur_frame_zero_id = cur_frame_sp->GetStackID();
163 
164         if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id)
165         {
166             if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
167             {
168                 if (--m_iteration_count <= 0)
169                 {
170                     SetPlanComplete();
171                     return true;
172                 }
173                 else
174                 {
175                     // We are still stepping, reset the start pc, and in case we've stepped out,
176                     // reset the current stack id.
177                     SetUpState();
178                     return false;
179                 }
180             }
181             else
182                 return false;
183         }
184         else
185         {
186             // We've stepped in, step back out again:
187             StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
188             if (return_frame)
189             {
190                 if (return_frame->GetStackID() != m_parent_frame_id || m_start_has_symbol)
191                 {
192                     // next-instruction shouldn't step out of inlined functions.  But we may have stepped into a
193                     // real function that starts with an inlined function, and we do want to step out of that...
194 
195                     if (cur_frame_sp->IsInlined())
196                     {
197                         StackFrameSP parent_frame_sp = m_thread.GetFrameWithStackID(m_stack_id);
198 
199                         if(parent_frame_sp && parent_frame_sp->GetConcreteFrameIndex() == cur_frame_sp->GetConcreteFrameIndex())
200                         {
201                             SetPlanComplete();
202                             if (log)
203                             {
204                                 log->Printf("Frame we stepped into is inlined into the frame we were stepping from, stopping.");
205                             }
206                             return true;
207                         }
208                     }
209 
210                     if (log)
211                     {
212                         StreamString s;
213                         s.PutCString ("Stepped in to: ");
214                         addr_t stop_addr = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
215                         s.Address (stop_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
216                         s.PutCString (" stepping out to: ");
217                         addr_t return_addr = return_frame->GetRegisterContext()->GetPC();
218                         s.Address (return_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
219                         log->Printf("%s.", s.GetData());
220                     }
221 
222                     // StepInstruction should probably have the tri-state RunMode, but for now it is safer to
223                     // run others.
224                     const bool stop_others = false;
225                     m_thread.QueueThreadPlanForStepOutNoShouldStop(false,
226                                                                    NULL,
227                                                                    true,
228                                                                    stop_others,
229                                                                    eVoteNo,
230                                                                    eVoteNoOpinion,
231                                                                    0);
232                     return false;
233                 }
234                 else
235                 {
236                     if (log)
237                     {
238                         log->PutCString("The stack id we are stepping in changed, but our parent frame did not when stepping from code with no symbols.  "
239                         "We are probably just confused about where we are, stopping.");
240                     }
241                     SetPlanComplete();
242                     return true;
243                 }
244             }
245             else
246             {
247                 if (log)
248                     log->Printf("Could not find previous frame, stopping.");
249                 SetPlanComplete();
250                 return true;
251             }
252 
253         }
254 
255     }
256     else
257     {
258         if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
259         {
260             if (--m_iteration_count <= 0)
261             {
262                 SetPlanComplete();
263                 return true;
264             }
265             else
266             {
267                 // We are still stepping, reset the start pc, and in case we've stepped in or out,
268                 // reset the current stack id.
269                 SetUpState();
270                 return false;
271             }
272         }
273         else
274             return false;
275     }
276 }
277 
278 bool
279 ThreadPlanStepInstruction::StopOthers ()
280 {
281     return m_stop_other_threads;
282 }
283 
284 StateType
285 ThreadPlanStepInstruction::GetPlanRunState ()
286 {
287     return eStateStepping;
288 }
289 
290 bool
291 ThreadPlanStepInstruction::WillStop ()
292 {
293     return true;
294 }
295 
296 bool
297 ThreadPlanStepInstruction::MischiefManaged ()
298 {
299     if (IsPlanComplete())
300     {
301         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
302         if (log)
303             log->Printf("Completed single instruction step plan.");
304         ThreadPlan::MischiefManaged ();
305         return true;
306     }
307     else
308     {
309         return false;
310     }
311 }
312 
313