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 ) :
42     ThreadPlan (ThreadPlan::eKindStepUntil, "Step until", thread, eVoteNoOpinion, eVoteNoOpinion),
43     m_stack_depth (0),
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     Target &target = m_thread.GetProcess().GetTarget();
58 
59     m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
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     StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
66     // TODO: add inline functionality
67     m_return_addr = return_frame->GetRegisterContext()->GetPC();
68     Breakpoint *return_bp = target.CreateBreakpoint (m_return_addr, true).get();
69     if (return_bp != NULL)
70     {
71         return_bp->SetThreadID(thread_id);
72         m_return_bp_id = return_bp->GetID();
73     }
74     else
75     {
76         m_return_bp_id = LLDB_INVALID_BREAK_ID;
77     }
78 
79     m_stack_depth = m_thread.GetStackFrameCount();
80 
81     // Now set breakpoints on all our return addresses:
82     for (int i = 0; i < num_addresses; i++)
83     {
84         Breakpoint *until_bp = target.CreateBreakpoint (address_list[i], true).get();
85         if (until_bp != NULL)
86         {
87             until_bp->SetThreadID(thread_id);
88             m_until_points[address_list[i]] = until_bp->GetID();
89         }
90         else
91         {
92             m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
93         }
94     }
95 }
96 
97 ThreadPlanStepUntil::~ThreadPlanStepUntil ()
98 {
99     Clear();
100 }
101 
102 void
103 ThreadPlanStepUntil::Clear()
104 {
105     Target &target = m_thread.GetProcess().GetTarget();
106     if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
107     {
108         target.RemoveBreakpointByID(m_return_bp_id);
109         m_return_bp_id = LLDB_INVALID_BREAK_ID;
110     }
111 
112     until_collection::iterator pos, end = m_until_points.end();
113     for (pos = m_until_points.begin(); pos != end; pos++)
114     {
115         target.RemoveBreakpointByID((*pos).second);
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%llx until we reach 0x%llx 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%llx 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%llx (bp: %d)", (uint64_t) (*pos).first, (*pos).second);
144             }
145         }
146         s->Printf(" stepped out address is 0x%lx.", (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 = GetPrivateStopReason();
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         switch (reason)
182         {
183             case eStopReasonBreakpoint:
184             {
185                 // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
186                 BreakpointSiteSP this_site = m_thread.GetProcess().GetBreakpointSiteList().FindByID (stop_info_sp->GetValue());
187                 if (!this_site)
188                 {
189                     m_explains_stop = false;
190                     return;
191                 }
192 
193                 if (this_site->IsBreakpointAtThisSite (m_return_bp_id))
194                 {
195                     // If we are at our "step out" breakpoint, and the stack depth has shrunk, then
196                     // this is indeed our stop.
197                     // If the stack depth has grown, then we've hit our step out breakpoint recursively.
198                     // If we are the only breakpoint at that location, then we do explain the stop, and
199                     // we'll just continue.
200                     // If there was another breakpoint here, then we don't explain the stop, but we won't
201                     // mark ourselves Completed, because maybe that breakpoint will continue, and then
202                     // we'll finish the "until".
203                     if (m_stack_depth > m_thread.GetStackFrameCount())
204                     {
205                         m_stepped_out = true;
206                         SetPlanComplete();
207                     }
208                     else
209                         m_should_stop = false;
210 
211                     if (this_site->GetNumberOfOwners() == 1)
212                         m_explains_stop = true;
213                     else
214                         m_explains_stop = false;
215                     return;
216                 }
217                 else
218                 {
219                     // Check if we've hit one of our "until" breakpoints.
220                     until_collection::iterator pos, end = m_until_points.end();
221                     for (pos = m_until_points.begin(); pos != end; pos++)
222                     {
223                         if (this_site->IsBreakpointAtThisSite ((*pos).second))
224                         {
225                             // If we're at the right stack depth, then we're done.
226                             if (m_stack_depth == m_thread.GetStackFrameCount())
227                                 SetPlanComplete();
228                             else
229                                 m_should_stop = false;
230 
231                             // Otherwise we've hit this breakpoint recursively.  If we're the
232                             // only breakpoint here, then we do explain the stop, and we'll continue.
233                             // If not then we should let higher plans handle this stop.
234                             if (this_site->GetNumberOfOwners() == 1)
235                                 m_explains_stop = true;
236                             else
237                             {
238                                 m_should_stop = true;
239                                 m_explains_stop = false;
240                             }
241                             return;
242                         }
243                     }
244                 }
245                 // If we get here we haven't hit any of our breakpoints, so let the higher
246                 // plans take care of the stop.
247                 m_explains_stop = false;
248                 return;
249             }
250             case eStopReasonWatchpoint:
251             case eStopReasonSignal:
252             case eStopReasonException:
253                 m_explains_stop = false;
254                 break;
255             default:
256                 m_explains_stop = true;
257                 break;
258         }
259     }
260 }
261 
262 bool
263 ThreadPlanStepUntil::PlanExplainsStop ()
264 {
265     // We don't explain signals or breakpoints (breakpoints that handle stepping in or
266     // out will be handled by a child plan.
267     AnalyzeStop();
268     return m_explains_stop;
269 }
270 
271 bool
272 ThreadPlanStepUntil::ShouldStop (Event *event_ptr)
273 {
274     // If we've told our self in ExplainsStop that we plan to continue, then
275     // do so here.  Otherwise, as long as this thread has stopped for a reason,
276     // we will stop.
277 
278     StopInfoSP stop_info_sp = GetPrivateStopReason();
279     if (stop_info_sp == NULL || stop_info_sp->GetStopReason() == eStopReasonNone)
280         return false;
281 
282     AnalyzeStop();
283     return m_should_stop;
284 }
285 
286 bool
287 ThreadPlanStepUntil::StopOthers ()
288 {
289     return m_stop_others;
290 }
291 
292 StateType
293 ThreadPlanStepUntil::RunState ()
294 {
295     return eStateRunning;
296 }
297 
298 bool
299 ThreadPlanStepUntil::WillResume (StateType resume_state, bool current_plan)
300 {
301     ThreadPlan::WillResume (resume_state, current_plan);
302     if (current_plan)
303     {
304         Target &target = m_thread.GetProcess().GetTarget();
305         Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
306         if (return_bp != NULL)
307             return_bp->SetEnabled (true);
308 
309         until_collection::iterator pos, end = m_until_points.end();
310         for (pos = m_until_points.begin(); pos != end; pos++)
311         {
312             Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
313             if (until_bp != NULL)
314                 until_bp->SetEnabled (true);
315         }
316     }
317 
318     m_should_stop = true;
319     m_ran_analyze = false;
320     m_explains_stop = false;
321     return true;
322 }
323 
324 bool
325 ThreadPlanStepUntil::WillStop ()
326 {
327     Target &target = m_thread.GetProcess().GetTarget();
328     Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
329     if (return_bp != NULL)
330         return_bp->SetEnabled (false);
331 
332     until_collection::iterator pos, end = m_until_points.end();
333     for (pos = m_until_points.begin(); pos != end; pos++)
334     {
335         Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
336         if (until_bp != NULL)
337             until_bp->SetEnabled (false);
338     }
339     return true;
340 }
341 
342 bool
343 ThreadPlanStepUntil::MischiefManaged ()
344 {
345 
346     // I'm letting "PlanExplainsStop" do all the work, and just reporting that here.
347     bool done = false;
348     if (IsPlanComplete())
349     {
350         Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
351         if (log)
352             log->Printf("Completed step until plan.");
353 
354         Clear();
355         done = true;
356     }
357     if (done)
358         ThreadPlan::MischiefManaged ();
359 
360     return done;
361 
362 }
363 
364