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