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 
ThreadPlanStepUntil(Thread & thread,lldb::addr_t * address_list,size_t num_addresses,bool stop_others,uint32_t frame_idx)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     // Stash away our "until" addresses:
55     TargetSP target_sp (m_thread.CalculateTarget());
56 
57     StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (frame_idx));
58     if (frame_sp)
59     {
60         m_step_from_insn = frame_sp->GetStackID().GetPC();
61         lldb::user_id_t thread_id = m_thread.GetID();
62 
63         // Find the return address and set a breakpoint there:
64         // FIXME - can we do this more securely if we know first_insn?
65 
66         StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
67         if (return_frame_sp)
68         {
69             // TODO: add inline functionality
70             m_return_addr = return_frame_sp->GetStackID().GetPC();
71             Breakpoint *return_bp = target_sp->CreateBreakpoint (m_return_addr, true).get();
72             if (return_bp != NULL)
73             {
74                 return_bp->SetThreadID(thread_id);
75                 m_return_bp_id = return_bp->GetID();
76                 return_bp->SetBreakpointKind ("until-return-backstop");
77             }
78         }
79 
80         m_stack_id = m_thread.GetStackFrameAtIndex(frame_idx)->GetStackID();
81 
82         // Now set breakpoints on all our return addresses:
83         for (size_t i = 0; i < num_addresses; i++)
84         {
85             Breakpoint *until_bp = target_sp->CreateBreakpoint (address_list[i], true).get();
86             if (until_bp != NULL)
87             {
88                 until_bp->SetThreadID(thread_id);
89                 m_until_points[address_list[i]] = until_bp->GetID();
90                 until_bp->SetBreakpointKind("until-target");
91             }
92             else
93             {
94                 m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
95             }
96         }
97     }
98 }
99 
~ThreadPlanStepUntil()100 ThreadPlanStepUntil::~ThreadPlanStepUntil ()
101 {
102     Clear();
103 }
104 
105 void
Clear()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
GetDescription(Stream * s,lldb::DescriptionLevel level)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%" PRIx64 " until we reach 0x%" PRIx64 " 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%" PRIx64 " 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%" PRIx64 " (bp: %d)", (uint64_t) (*pos).first, (*pos).second);
150             }
151         }
152         s->Printf(" stepped out address is 0x%" PRIx64 ".", (uint64_t) m_return_addr);
153     }
154 }
155 
156 bool
ValidatePlan(Stream * error)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
AnalyzeStop()174 ThreadPlanStepUntil::AnalyzeStop()
175 {
176     if (m_ran_analyze)
177         return;
178 
179     StopInfoSP stop_info_sp = GetPrivateStopInfo ();
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             case eStopReasonExec:
297             case eStopReasonThreadExiting:
298                 m_explains_stop = false;
299                 break;
300             default:
301                 m_explains_stop = true;
302                 break;
303         }
304     }
305 }
306 
307 bool
DoPlanExplainsStop(Event * event_ptr)308 ThreadPlanStepUntil::DoPlanExplainsStop (Event *event_ptr)
309 {
310     // We don't explain signals or breakpoints (breakpoints that handle stepping in or
311     // out will be handled by a child plan.
312     AnalyzeStop();
313     return m_explains_stop;
314 }
315 
316 bool
ShouldStop(Event * event_ptr)317 ThreadPlanStepUntil::ShouldStop (Event *event_ptr)
318 {
319     // If we've told our self in ExplainsStop that we plan to continue, then
320     // do so here.  Otherwise, as long as this thread has stopped for a reason,
321     // we will stop.
322 
323     StopInfoSP stop_info_sp = GetPrivateStopInfo ();
324     if (!stop_info_sp || stop_info_sp->GetStopReason() == eStopReasonNone)
325         return false;
326 
327     AnalyzeStop();
328     return m_should_stop;
329 }
330 
331 bool
StopOthers()332 ThreadPlanStepUntil::StopOthers ()
333 {
334     return m_stop_others;
335 }
336 
337 StateType
GetPlanRunState()338 ThreadPlanStepUntil::GetPlanRunState ()
339 {
340     return eStateRunning;
341 }
342 
343 bool
DoWillResume(StateType resume_state,bool current_plan)344 ThreadPlanStepUntil::DoWillResume (StateType resume_state, bool current_plan)
345 {
346     if (current_plan)
347     {
348         TargetSP target_sp (m_thread.CalculateTarget());
349         if (target_sp)
350         {
351             Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
352             if (return_bp != NULL)
353                 return_bp->SetEnabled (true);
354 
355             until_collection::iterator pos, end = m_until_points.end();
356             for (pos = m_until_points.begin(); pos != end; pos++)
357             {
358                 Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
359                 if (until_bp != NULL)
360                     until_bp->SetEnabled (true);
361             }
362         }
363     }
364 
365     m_should_stop = true;
366     m_ran_analyze = false;
367     m_explains_stop = false;
368     return true;
369 }
370 
371 bool
WillStop()372 ThreadPlanStepUntil::WillStop ()
373 {
374     TargetSP target_sp (m_thread.CalculateTarget());
375     if (target_sp)
376     {
377         Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
378         if (return_bp != NULL)
379             return_bp->SetEnabled (false);
380 
381         until_collection::iterator pos, end = m_until_points.end();
382         for (pos = m_until_points.begin(); pos != end; pos++)
383         {
384             Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
385             if (until_bp != NULL)
386                 until_bp->SetEnabled (false);
387         }
388     }
389     return true;
390 }
391 
392 bool
MischiefManaged()393 ThreadPlanStepUntil::MischiefManaged ()
394 {
395 
396     // I'm letting "PlanExplainsStop" do all the work, and just reporting that here.
397     bool done = false;
398     if (IsPlanComplete())
399     {
400         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
401         if (log)
402             log->Printf("Completed step until plan.");
403 
404         Clear();
405         done = true;
406     }
407     if (done)
408         ThreadPlan::MischiefManaged ();
409 
410     return done;
411 
412 }
413 
414