1 //===-- ThreadPlanStepOut.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 #include "lldb/Target/ThreadPlanStepOut.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Breakpoint/Breakpoint.h"
17 #include "lldb/lldb-private-log.h"
18 #include "lldb/Core/Log.h"
19 #include "lldb/Core/Value.h"
20 #include "lldb/Core/ValueObjectConstResult.h"
21 #include "lldb/Target/Process.h"
22 #include "lldb/Target/RegisterContext.h"
23 #include "lldb/Target/StopInfo.h"
24 #include "lldb/Target/Target.h"
25 #include "lldb/Target/ThreadPlanStepOverRange.h"
26 
27 using namespace lldb;
28 using namespace lldb_private;
29 
30 //----------------------------------------------------------------------
31 // ThreadPlanStepOut: Step out of the current frame
32 //----------------------------------------------------------------------
33 ThreadPlanStepOut::ThreadPlanStepOut
34 (
35     Thread &thread,
36     SymbolContext *context,
37     bool first_insn,
38     bool stop_others,
39     Vote stop_vote,
40     Vote run_vote,
41     uint32_t frame_idx
42 ) :
43     ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote),
44     m_step_from_context (context),
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_first_insn (first_insn),
49     m_stop_others (stop_others),
50     m_step_through_inline_plan_sp(),
51     m_step_out_plan_sp (),
52     m_immediate_step_from_function(NULL)
53 
54 {
55     m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
56 
57     StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
58     StackFrameSP immediate_return_from_sp (m_thread.GetStackFrameAtIndex (frame_idx));
59 
60     if (!return_frame_sp || !immediate_return_from_sp)
61         return; // we can't do anything here.  ValidatePlan() will return false.
62 
63     m_step_out_to_id = return_frame_sp->GetStackID();
64     m_immediate_step_from_id = immediate_return_from_sp->GetStackID();
65 
66     StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
67 
68     // If the frame directly below the one we are returning to is inlined, we have to be
69     // a little more careful.  It is non-trivial to determine the real "return code address" for
70     // an inlined frame, so we have to work our way to that frame and then step out.
71     if (immediate_return_from_sp && immediate_return_from_sp->IsInlined())
72     {
73         if (frame_idx > 0)
74         {
75             // First queue a plan that gets us to this inlined frame, and when we get there we'll queue a second
76             // plan that walks us out of this frame.
77             m_step_out_plan_sp.reset (new ThreadPlanStepOut(m_thread,
78                                                             NULL,
79                                                             false,
80                                                             stop_others,
81                                                             eVoteNoOpinion,
82                                                             eVoteNoOpinion,
83                                                             frame_idx - 1));
84         }
85         else
86         {
87             // If we're already at the inlined frame we're stepping through, then just do that now.
88             QueueInlinedStepPlan(false);
89         }
90 
91     }
92     else if (return_frame_sp)
93     {
94         // Find the return address and set a breakpoint there:
95         // FIXME - can we do this more securely if we know first_insn?
96 
97         m_return_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress(&m_thread.GetProcess()->GetTarget());
98         Breakpoint *return_bp = m_thread.CalculateTarget()->CreateBreakpoint (m_return_addr, true).get();
99         if (return_bp != NULL)
100         {
101             return_bp->SetThreadID(m_thread.GetID());
102             m_return_bp_id = return_bp->GetID();
103         }
104 
105         if (immediate_return_from_sp)
106         {
107             const SymbolContext &sc = immediate_return_from_sp->GetSymbolContext(eSymbolContextFunction);
108             if (sc.function)
109             {
110                 m_immediate_step_from_function = sc.function;
111             }
112         }
113     }
114 
115 }
116 
117 void
118 ThreadPlanStepOut::DidPush()
119 {
120     if (m_step_out_plan_sp)
121         m_thread.QueueThreadPlan(m_step_out_plan_sp, false);
122     else if (m_step_through_inline_plan_sp)
123         m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
124 }
125 
126 ThreadPlanStepOut::~ThreadPlanStepOut ()
127 {
128     if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
129         m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id);
130 }
131 
132 void
133 ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
134 {
135     if (level == lldb::eDescriptionLevelBrief)
136         s->Printf ("step out");
137     else
138     {
139         if (m_step_out_plan_sp)
140             s->Printf ("Stepping out to inlined frame so we can walk through it.");
141         else if (m_step_through_inline_plan_sp)
142             s->Printf ("Stepping out by stepping through inlined function.");
143         else
144             s->Printf ("Stepping out from address 0x%llx to return address 0x%llx using breakpoint site %d",
145                        (uint64_t)m_step_from_insn,
146                        (uint64_t)m_return_addr,
147                        m_return_bp_id);
148     }
149 }
150 
151 bool
152 ThreadPlanStepOut::ValidatePlan (Stream *error)
153 {
154     if (m_step_out_plan_sp)
155         return m_step_out_plan_sp->ValidatePlan (error);
156     else if (m_step_through_inline_plan_sp)
157         return m_step_through_inline_plan_sp->ValidatePlan (error);
158     else if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
159     {
160         error->PutCString("Could not create return address breakpoint.");
161         return false;
162     }
163     else
164         return true;
165 }
166 
167 bool
168 ThreadPlanStepOut::PlanExplainsStop ()
169 {
170     // If one of our child plans just finished, then we do explain the stop.
171     if (m_step_out_plan_sp)
172     {
173         if (m_step_out_plan_sp->MischiefManaged())
174         {
175             // If this one is done, then we are all done.
176             CalculateReturnValue();
177             SetPlanComplete();
178             return true;
179         }
180         else
181             return false;
182     }
183     else if (m_step_through_inline_plan_sp)
184     {
185         if (m_step_through_inline_plan_sp->MischiefManaged())
186             return true;
187         else
188             return false;
189     }
190 
191     // We don't explain signals or breakpoints (breakpoints that handle stepping in or
192     // out will be handled by a child plan.
193 
194     StopInfoSP stop_info_sp = GetPrivateStopReason();
195     if (stop_info_sp)
196     {
197         StopReason reason = stop_info_sp->GetStopReason();
198         switch (reason)
199         {
200         case eStopReasonBreakpoint:
201         {
202             // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
203             BreakpointSiteSP site_sp (m_thread.GetProcess()->GetBreakpointSiteList().FindByID (stop_info_sp->GetValue()));
204             if (site_sp && site_sp->IsBreakpointAtThisSite (m_return_bp_id))
205             {
206                 bool done;
207 
208                 StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
209 
210                 if (m_step_out_to_id == frame_zero_id)
211                     done = true;
212                 else if (m_step_out_to_id < frame_zero_id)
213                 {
214                     // Either we stepped past the breakpoint, or the stack ID calculation
215                     // was incorrect and we should probably stop.
216                     done = true;
217                 }
218                 else
219                 {
220                     if (m_immediate_step_from_id < frame_zero_id)
221                         done = true;
222                     else
223                         done = false;
224                 }
225 
226                 if (done)
227                 {
228                     CalculateReturnValue();
229                     SetPlanComplete();
230                 }
231 
232                 // If there was only one owner, then we're done.  But if we also hit some
233                 // user breakpoint on our way out, we should mark ourselves as done, but
234                 // also not claim to explain the stop, since it is more important to report
235                 // the user breakpoint than the step out completion.
236 
237                 if (site_sp->GetNumberOfOwners() == 1)
238                     return true;
239 
240             }
241             return false;
242         }
243         case eStopReasonWatchpoint:
244         case eStopReasonSignal:
245         case eStopReasonException:
246             return false;
247 
248         default:
249             return true;
250         }
251     }
252     return true;
253 }
254 
255 bool
256 ThreadPlanStepOut::ShouldStop (Event *event_ptr)
257 {
258         if (IsPlanComplete())
259             return true;
260 
261         bool done;
262 
263         StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
264         if (frame_zero_id < m_step_out_to_id)
265             done = false;
266         else
267             done = true;
268 
269         if (done)
270         {
271             CalculateReturnValue();
272             SetPlanComplete();
273             return true;
274         }
275         else
276         {
277             if (m_step_out_plan_sp)
278             {
279                 if (m_step_out_plan_sp->MischiefManaged())
280                 {
281                     // Now step through the inlined stack we are in:
282                     if (QueueInlinedStepPlan(true))
283                     {
284                         return false;
285                     }
286                     else
287                     {
288                         CalculateReturnValue();
289                         SetPlanComplete ();
290                         return true;
291                     }
292                 }
293                 else
294                     return m_step_out_plan_sp->ShouldStop(event_ptr);
295             }
296             else if (m_step_through_inline_plan_sp)
297             {
298                 if (m_step_through_inline_plan_sp->MischiefManaged())
299                 {
300                     // We don't calculate the return value here because we don't know how to.
301                     // But in case we had a return value sitting around from our process in
302                     // getting here, let's clear it out.
303                     m_return_valobj_sp.reset();
304                     SetPlanComplete();
305                     return true;
306                 }
307                 else
308                     return m_step_through_inline_plan_sp->ShouldStop(event_ptr);
309             }
310             else
311                 return false;
312         }
313 }
314 
315 bool
316 ThreadPlanStepOut::StopOthers ()
317 {
318     return m_stop_others;
319 }
320 
321 StateType
322 ThreadPlanStepOut::GetPlanRunState ()
323 {
324     return eStateRunning;
325 }
326 
327 bool
328 ThreadPlanStepOut::WillResume (StateType resume_state, bool current_plan)
329 {
330     ThreadPlan::WillResume (resume_state, current_plan);
331     if (m_step_out_plan_sp || m_step_through_inline_plan_sp)
332         return true;
333 
334     if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
335         return false;
336 
337     if (current_plan)
338     {
339         Breakpoint *return_bp = m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get();
340         if (return_bp != NULL)
341             return_bp->SetEnabled (true);
342     }
343     return true;
344 }
345 
346 bool
347 ThreadPlanStepOut::WillStop ()
348 {
349     if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
350     {
351         Breakpoint *return_bp = m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get();
352         if (return_bp != NULL)
353             return_bp->SetEnabled (false);
354     }
355 
356     return true;
357 }
358 
359 bool
360 ThreadPlanStepOut::MischiefManaged ()
361 {
362     if (IsPlanComplete())
363     {
364         // Did I reach my breakpoint?  If so I'm done.
365         //
366         // I also check the stack depth, since if we've blown past the breakpoint for some
367         // reason and we're now stopping for some other reason altogether, then we're done
368         // with this step out operation.
369 
370         LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
371         if (log)
372             log->Printf("Completed step out plan.");
373         if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
374         {
375             m_thread.CalculateTarget()->RemoveBreakpointByID (m_return_bp_id);
376             m_return_bp_id = LLDB_INVALID_BREAK_ID;
377         }
378 
379         ThreadPlan::MischiefManaged ();
380         return true;
381     }
382     else
383     {
384         return false;
385     }
386 }
387 
388 bool
389 ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now)
390 {
391     // Now figure out the range of this inlined block, and set up a "step through range"
392     // plan for that.  If we've been provided with a context, then use the block in that
393     // context.
394     StackFrameSP immediate_return_from_sp (m_thread.GetStackFrameAtIndex (0));
395     if (!immediate_return_from_sp)
396         return false;
397 
398     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
399     if (log)
400     {
401         StreamString s;
402         immediate_return_from_sp->Dump(&s, true, false);
403         log->Printf("Queuing inlined frame to step past: %s.", s.GetData());
404     }
405 
406     Block *from_block = immediate_return_from_sp->GetFrameBlock();
407     if (from_block)
408     {
409         Block *inlined_block = from_block->GetContainingInlinedBlock();
410         if (inlined_block)
411         {
412             size_t num_ranges = inlined_block->GetNumRanges();
413             AddressRange inline_range;
414             if (inlined_block->GetRangeAtIndex(0, inline_range))
415             {
416                 SymbolContext inlined_sc;
417                 inlined_block->CalculateSymbolContext(&inlined_sc);
418                 RunMode run_mode = m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads;
419                 ThreadPlanStepOverRange *step_through_inline_plan_ptr = new ThreadPlanStepOverRange(m_thread,
420                                                                                                     inline_range,
421                                                                                                     inlined_sc,
422                                                                                                     run_mode);
423                 step_through_inline_plan_ptr->SetOkayToDiscard(true);
424                 StreamString errors;
425                 if (!step_through_inline_plan_ptr->ValidatePlan(&errors))
426                 {
427                     //FIXME: Log this failure.
428                     delete step_through_inline_plan_ptr;
429                     return false;
430                 }
431 
432                 for (size_t i = 1; i < num_ranges; i++)
433                 {
434                     if (inlined_block->GetRangeAtIndex (i, inline_range))
435                         step_through_inline_plan_ptr->AddRange (inline_range);
436                 }
437                 m_step_through_inline_plan_sp.reset (step_through_inline_plan_ptr);
438                 if (queue_now)
439                     m_thread.QueueThreadPlan (m_step_through_inline_plan_sp, false);
440                 return true;
441             }
442         }
443     }
444 
445     return false;
446 }
447 
448 void
449 ThreadPlanStepOut::CalculateReturnValue ()
450 {
451     if (m_return_valobj_sp)
452         return;
453 
454     if (m_immediate_step_from_function != NULL)
455     {
456         Type *return_type = m_immediate_step_from_function->GetType();
457         lldb::clang_type_t return_clang_type = m_immediate_step_from_function->GetReturnClangType();
458         if (return_type && return_clang_type)
459         {
460             ClangASTType ast_type (return_type->GetClangAST(), return_clang_type);
461 
462             lldb::ABISP abi_sp = m_thread.GetProcess()->GetABI();
463             if (abi_sp)
464             {
465                 m_return_valobj_sp = abi_sp->GetReturnValueObject(m_thread, ast_type);
466             }
467         }
468     }
469 }
470 
471 bool
472 ThreadPlanStepOut::IsPlanStale()
473 {
474     // If we are still lower on the stack than the frame we are returning to, then
475     // there's something for us to do.  Otherwise, we're stale.
476 
477     StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
478     if (frame_zero_id < m_step_out_to_id)
479         return false;
480     else
481         return true;
482 }
483 
484