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