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