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