1 //===-- ThreadPlanStepUntil.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 //m_should_stop
10 
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "lldb/Target/ThreadPlanStepUntil.h"
15 
16 // C Includes
17 // C++ Includes
18 // Other libraries and framework includes
19 // Project includes
20 #include "lldb/Breakpoint/Breakpoint.h"
21 #include "lldb/lldb-private-log.h"
22 #include "lldb/Core/Log.h"
23 #include "lldb/Target/Process.h"
24 #include "lldb/Target/RegisterContext.h"
25 #include "lldb/Target/StopInfo.h"
26 #include "lldb/Target/Target.h"
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 
31 //----------------------------------------------------------------------
32 // ThreadPlanStepUntil: Run until we reach a given line number or step out of the current frame
33 //----------------------------------------------------------------------
34 
35 ThreadPlanStepUntil::ThreadPlanStepUntil
36 (
37     Thread &thread,
38     lldb::addr_t *address_list,
39     size_t num_addresses,
40     bool stop_others,
41     uint32_t frame_idx
42 ) :
43     ThreadPlan (ThreadPlan::eKindStepUntil, "Step until", thread, eVoteNoOpinion, eVoteNoOpinion),
44     m_stack_depth (0),
45     m_step_from_insn (LLDB_INVALID_ADDRESS),
46     m_return_bp_id(LLDB_INVALID_BREAK_ID),
47     m_return_addr (LLDB_INVALID_ADDRESS),
48     m_stepped_out(false),
49     m_should_stop(false),
50     m_ran_analyze (false),
51     m_explains_stop(false),
52     m_until_points(),
53     m_stop_others (stop_others)
54 {
55 
56     SetOkayToDiscard(true);
57     // Stash away our "until" addresses:
58     TargetSP target_sp (m_thread.CalculateTarget());
59 
60     StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (frame_idx));
61     if (frame_sp)
62     {
63         m_step_from_insn = frame_sp->GetStackID().GetPC();
64         lldb::user_id_t thread_id = m_thread.GetID();
65 
66         // Find the return address and set a breakpoint there:
67         // FIXME - can we do this more securely if we know first_insn?
68 
69         StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
70         if (return_frame_sp)
71         {
72             // TODO: add inline functionality
73             m_return_addr = return_frame_sp->GetStackID().GetPC();
74             Breakpoint *return_bp = target_sp->CreateBreakpoint (m_return_addr, true).get();
75             if (return_bp != NULL)
76             {
77                 return_bp->SetThreadID(thread_id);
78                 m_return_bp_id = return_bp->GetID();
79             }
80         }
81 
82         m_stack_depth = m_thread.GetStackFrameCount() - frame_idx;
83 
84         // Now set breakpoints on all our return addresses:
85         for (int i = 0; i < num_addresses; i++)
86         {
87             Breakpoint *until_bp = target_sp->CreateBreakpoint (address_list[i], true).get();
88             if (until_bp != NULL)
89             {
90                 until_bp->SetThreadID(thread_id);
91                 m_until_points[address_list[i]] = until_bp->GetID();
92             }
93             else
94             {
95                 m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
96             }
97         }
98     }
99 }
100 
101 ThreadPlanStepUntil::~ThreadPlanStepUntil ()
102 {
103     Clear();
104 }
105 
106 void
107 ThreadPlanStepUntil::Clear()
108 {
109     TargetSP target_sp (m_thread.CalculateTarget());
110     if (target_sp)
111     {
112         if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
113         {
114             target_sp->RemoveBreakpointByID(m_return_bp_id);
115             m_return_bp_id = LLDB_INVALID_BREAK_ID;
116         }
117 
118         until_collection::iterator pos, end = m_until_points.end();
119         for (pos = m_until_points.begin(); pos != end; pos++)
120         {
121             target_sp->RemoveBreakpointByID((*pos).second);
122         }
123     }
124     m_until_points.clear();
125 }
126 
127 void
128 ThreadPlanStepUntil::GetDescription (Stream *s, lldb::DescriptionLevel level)
129 {
130     if (level == lldb::eDescriptionLevelBrief)
131     {
132         s->Printf ("step until");
133         if (m_stepped_out)
134             s->Printf (" - stepped out");
135     }
136     else
137     {
138         if (m_until_points.size() == 1)
139             s->Printf ("Stepping from address 0x%llx until we reach 0x%llx using breakpoint %d",
140                        (uint64_t)m_step_from_insn,
141                        (uint64_t) (*m_until_points.begin()).first,
142                        (*m_until_points.begin()).second);
143         else
144         {
145             until_collection::iterator pos, end = m_until_points.end();
146             s->Printf ("Stepping from address 0x%llx until we reach one of:",
147                        (uint64_t)m_step_from_insn);
148             for (pos = m_until_points.begin(); pos != end; pos++)
149             {
150                 s->Printf ("\n\t0x%llx (bp: %d)", (uint64_t) (*pos).first, (*pos).second);
151             }
152         }
153         s->Printf(" stepped out address is 0x%llx.", (uint64_t) m_return_addr);
154     }
155 }
156 
157 bool
158 ThreadPlanStepUntil::ValidatePlan (Stream *error)
159 {
160     if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
161         return false;
162     else
163     {
164         until_collection::iterator pos, end = m_until_points.end();
165         for (pos = m_until_points.begin(); pos != end; pos++)
166         {
167             if (!LLDB_BREAK_ID_IS_VALID ((*pos).second))
168                 return false;
169         }
170         return true;
171     }
172 }
173 
174 void
175 ThreadPlanStepUntil::AnalyzeStop()
176 {
177     if (m_ran_analyze)
178         return;
179 
180     StopInfoSP stop_info_sp = GetPrivateStopReason();
181     m_should_stop = true;
182     m_explains_stop = false;
183 
184     if (stop_info_sp)
185     {
186         StopReason reason = stop_info_sp->GetStopReason();
187 
188         switch (reason)
189         {
190             case eStopReasonBreakpoint:
191             {
192                 // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
193                 BreakpointSiteSP this_site = m_thread.GetProcess()->GetBreakpointSiteList().FindByID (stop_info_sp->GetValue());
194                 if (!this_site)
195                 {
196                     m_explains_stop = false;
197                     return;
198                 }
199 
200                 if (this_site->IsBreakpointAtThisSite (m_return_bp_id))
201                 {
202                     // If we are at our "step out" breakpoint, and the stack depth has shrunk, then
203                     // this is indeed our stop.
204                     // If the stack depth has grown, then we've hit our step out breakpoint recursively.
205                     // If we are the only breakpoint at that location, then we do explain the stop, and
206                     // we'll just continue.
207                     // If there was another breakpoint here, then we don't explain the stop, but we won't
208                     // mark ourselves Completed, because maybe that breakpoint will continue, and then
209                     // we'll finish the "until".
210                     if (m_stack_depth > m_thread.GetStackFrameCount())
211                     {
212                         m_stepped_out = true;
213                         SetPlanComplete();
214                     }
215                     else
216                         m_should_stop = false;
217 
218                     if (this_site->GetNumberOfOwners() == 1)
219                         m_explains_stop = true;
220                     else
221                         m_explains_stop = false;
222                     return;
223                 }
224                 else
225                 {
226                     // Check if we've hit one of our "until" breakpoints.
227                     until_collection::iterator pos, end = m_until_points.end();
228                     for (pos = m_until_points.begin(); pos != end; pos++)
229                     {
230                         if (this_site->IsBreakpointAtThisSite ((*pos).second))
231                         {
232                             // If we're at the right stack depth, then we're done.
233                             if (m_stack_depth == m_thread.GetStackFrameCount())
234                                 SetPlanComplete();
235                             else
236                                 m_should_stop = false;
237 
238                             // Otherwise we've hit this breakpoint recursively.  If we're the
239                             // only breakpoint here, then we do explain the stop, and we'll continue.
240                             // If not then we should let higher plans handle this stop.
241                             if (this_site->GetNumberOfOwners() == 1)
242                                 m_explains_stop = true;
243                             else
244                             {
245                                 m_should_stop = true;
246                                 m_explains_stop = false;
247                             }
248                             return;
249                         }
250                     }
251                 }
252                 // If we get here we haven't hit any of our breakpoints, so let the higher
253                 // plans take care of the stop.
254                 m_explains_stop = false;
255                 return;
256             }
257             case eStopReasonWatchpoint:
258             case eStopReasonSignal:
259             case eStopReasonException:
260                 m_explains_stop = false;
261                 break;
262             default:
263                 m_explains_stop = true;
264                 break;
265         }
266     }
267 }
268 
269 bool
270 ThreadPlanStepUntil::PlanExplainsStop ()
271 {
272     // We don't explain signals or breakpoints (breakpoints that handle stepping in or
273     // out will be handled by a child plan.
274     AnalyzeStop();
275     return m_explains_stop;
276 }
277 
278 bool
279 ThreadPlanStepUntil::ShouldStop (Event *event_ptr)
280 {
281     // If we've told our self in ExplainsStop that we plan to continue, then
282     // do so here.  Otherwise, as long as this thread has stopped for a reason,
283     // we will stop.
284 
285     StopInfoSP stop_info_sp = GetPrivateStopReason();
286     if (stop_info_sp == NULL || stop_info_sp->GetStopReason() == eStopReasonNone)
287         return false;
288 
289     AnalyzeStop();
290     return m_should_stop;
291 }
292 
293 bool
294 ThreadPlanStepUntil::StopOthers ()
295 {
296     return m_stop_others;
297 }
298 
299 StateType
300 ThreadPlanStepUntil::GetPlanRunState ()
301 {
302     return eStateRunning;
303 }
304 
305 bool
306 ThreadPlanStepUntil::WillResume (StateType resume_state, bool current_plan)
307 {
308     ThreadPlan::WillResume (resume_state, current_plan);
309     if (current_plan)
310     {
311         TargetSP target_sp (m_thread.CalculateTarget());
312         if (target_sp)
313         {
314             Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
315             if (return_bp != NULL)
316                 return_bp->SetEnabled (true);
317 
318             until_collection::iterator pos, end = m_until_points.end();
319             for (pos = m_until_points.begin(); pos != end; pos++)
320             {
321                 Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
322                 if (until_bp != NULL)
323                     until_bp->SetEnabled (true);
324             }
325         }
326     }
327 
328     m_should_stop = true;
329     m_ran_analyze = false;
330     m_explains_stop = false;
331     return true;
332 }
333 
334 bool
335 ThreadPlanStepUntil::WillStop ()
336 {
337     TargetSP target_sp (m_thread.CalculateTarget());
338     if (target_sp)
339     {
340         Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
341         if (return_bp != NULL)
342             return_bp->SetEnabled (false);
343 
344         until_collection::iterator pos, end = m_until_points.end();
345         for (pos = m_until_points.begin(); pos != end; pos++)
346         {
347             Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
348             if (until_bp != NULL)
349                 until_bp->SetEnabled (false);
350         }
351     }
352     return true;
353 }
354 
355 bool
356 ThreadPlanStepUntil::MischiefManaged ()
357 {
358 
359     // I'm letting "PlanExplainsStop" do all the work, and just reporting that here.
360     bool done = false;
361     if (IsPlanComplete())
362     {
363         LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
364         if (log)
365             log->Printf("Completed step until plan.");
366 
367         Clear();
368         done = true;
369     }
370     if (done)
371         ThreadPlan::MischiefManaged ();
372 
373     return done;
374 
375 }
376 
377