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_stack_depth (0),
45     m_step_from_insn (LLDB_INVALID_ADDRESS),
46     m_return_bp_id(LLDB_INVALID_BREAK_ID),
47     m_return_addr (LLDB_INVALID_ADDRESS),
48     m_stepped_out(false),
49     m_should_stop(false),
50     m_ran_analyze (false),
51     m_explains_stop(false),
52     m_until_points(),
53     m_stop_others (stop_others)
54 {
55 
56     SetOkayToDiscard(true);
57     // Stash away our "until" addresses:
58     Target &target = m_thread.GetProcess().GetTarget();
59 
60     StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (frame_idx));
61     if (frame_sp)
62     {
63         m_step_from_insn = frame_sp->GetStackID().GetPC();
64         lldb::user_id_t thread_id = m_thread.GetID();
65 
66         // Find the return address and set a breakpoint there:
67         // FIXME - can we do this more securely if we know first_insn?
68 
69         StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
70         if (return_frame_sp)
71         {
72             // TODO: add inline functionality
73             m_return_addr = return_frame_sp->GetStackID().GetPC();
74             Breakpoint *return_bp = target.CreateBreakpoint (m_return_addr, true).get();
75             if (return_bp != NULL)
76             {
77                 return_bp->SetThreadID(thread_id);
78                 m_return_bp_id = return_bp->GetID();
79             }
80         }
81 
82         m_stack_depth = m_thread.GetStackFrameCount() - frame_idx;
83 
84         // Now set breakpoints on all our return addresses:
85         for (int i = 0; i < num_addresses; i++)
86         {
87             Breakpoint *until_bp = target.CreateBreakpoint (address_list[i], true).get();
88             if (until_bp != NULL)
89             {
90                 until_bp->SetThreadID(thread_id);
91                 m_until_points[address_list[i]] = until_bp->GetID();
92             }
93             else
94             {
95                 m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
96             }
97         }
98     }
99 }
100 
101 ThreadPlanStepUntil::~ThreadPlanStepUntil ()
102 {
103     Clear();
104 }
105 
106 void
107 ThreadPlanStepUntil::Clear()
108 {
109     Target &target = m_thread.GetProcess().GetTarget();
110     if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
111     {
112         target.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.RemoveBreakpointByID((*pos).second);
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                     if (m_stack_depth > m_thread.GetStackFrameCount())
208                     {
209                         m_stepped_out = true;
210                         SetPlanComplete();
211                     }
212                     else
213                         m_should_stop = false;
214 
215                     if (this_site->GetNumberOfOwners() == 1)
216                         m_explains_stop = true;
217                     else
218                         m_explains_stop = false;
219                     return;
220                 }
221                 else
222                 {
223                     // Check if we've hit one of our "until" breakpoints.
224                     until_collection::iterator pos, end = m_until_points.end();
225                     for (pos = m_until_points.begin(); pos != end; pos++)
226                     {
227                         if (this_site->IsBreakpointAtThisSite ((*pos).second))
228                         {
229                             // If we're at the right stack depth, then we're done.
230                             if (m_stack_depth == m_thread.GetStackFrameCount())
231                                 SetPlanComplete();
232                             else
233                                 m_should_stop = false;
234 
235                             // Otherwise we've hit this breakpoint recursively.  If we're the
236                             // only breakpoint here, then we do explain the stop, and we'll continue.
237                             // If not then we should let higher plans handle this stop.
238                             if (this_site->GetNumberOfOwners() == 1)
239                                 m_explains_stop = true;
240                             else
241                             {
242                                 m_should_stop = true;
243                                 m_explains_stop = false;
244                             }
245                             return;
246                         }
247                     }
248                 }
249                 // If we get here we haven't hit any of our breakpoints, so let the higher
250                 // plans take care of the stop.
251                 m_explains_stop = false;
252                 return;
253             }
254             case eStopReasonWatchpoint:
255             case eStopReasonSignal:
256             case eStopReasonException:
257                 m_explains_stop = false;
258                 break;
259             default:
260                 m_explains_stop = true;
261                 break;
262         }
263     }
264 }
265 
266 bool
267 ThreadPlanStepUntil::PlanExplainsStop ()
268 {
269     // We don't explain signals or breakpoints (breakpoints that handle stepping in or
270     // out will be handled by a child plan.
271     AnalyzeStop();
272     return m_explains_stop;
273 }
274 
275 bool
276 ThreadPlanStepUntil::ShouldStop (Event *event_ptr)
277 {
278     // If we've told our self in ExplainsStop that we plan to continue, then
279     // do so here.  Otherwise, as long as this thread has stopped for a reason,
280     // we will stop.
281 
282     StopInfoSP stop_info_sp = GetPrivateStopReason();
283     if (stop_info_sp == NULL || stop_info_sp->GetStopReason() == eStopReasonNone)
284         return false;
285 
286     AnalyzeStop();
287     return m_should_stop;
288 }
289 
290 bool
291 ThreadPlanStepUntil::StopOthers ()
292 {
293     return m_stop_others;
294 }
295 
296 StateType
297 ThreadPlanStepUntil::GetPlanRunState ()
298 {
299     return eStateRunning;
300 }
301 
302 bool
303 ThreadPlanStepUntil::WillResume (StateType resume_state, bool current_plan)
304 {
305     ThreadPlan::WillResume (resume_state, current_plan);
306     if (current_plan)
307     {
308         Target &target = m_thread.GetProcess().GetTarget();
309         Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
310         if (return_bp != NULL)
311             return_bp->SetEnabled (true);
312 
313         until_collection::iterator pos, end = m_until_points.end();
314         for (pos = m_until_points.begin(); pos != end; pos++)
315         {
316             Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
317             if (until_bp != NULL)
318                 until_bp->SetEnabled (true);
319         }
320     }
321 
322     m_should_stop = true;
323     m_ran_analyze = false;
324     m_explains_stop = false;
325     return true;
326 }
327 
328 bool
329 ThreadPlanStepUntil::WillStop ()
330 {
331     Target &target = m_thread.GetProcess().GetTarget();
332     Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
333     if (return_bp != NULL)
334         return_bp->SetEnabled (false);
335 
336     until_collection::iterator pos, end = m_until_points.end();
337     for (pos = m_until_points.begin(); pos != end; pos++)
338     {
339         Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
340         if (until_bp != NULL)
341             until_bp->SetEnabled (false);
342     }
343     return true;
344 }
345 
346 bool
347 ThreadPlanStepUntil::MischiefManaged ()
348 {
349 
350     // I'm letting "PlanExplainsStop" do all the work, and just reporting that here.
351     bool done = false;
352     if (IsPlanComplete())
353     {
354         LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
355         if (log)
356             log->Printf("Completed step until plan.");
357 
358         Clear();
359         done = true;
360     }
361     if (done)
362         ThreadPlan::MischiefManaged ();
363 
364     return done;
365 
366 }
367 
368