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