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