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