1ac7ddfbfSEd Maste //===-- ThreadPlanStepOut.cpp -----------------------------------*- C++ -*-===//
2ac7ddfbfSEd Maste //
3ac7ddfbfSEd Maste //                     The LLVM Compiler Infrastructure
4ac7ddfbfSEd Maste //
5ac7ddfbfSEd Maste // This file is distributed under the University of Illinois Open Source
6ac7ddfbfSEd Maste // License. See LICENSE.TXT for details.
7ac7ddfbfSEd Maste //
8ac7ddfbfSEd Maste //===----------------------------------------------------------------------===//
9ac7ddfbfSEd Maste 
109f2f44ceSEd Maste #include "lldb/Target/ThreadPlanStepOut.h"
11ac7ddfbfSEd Maste #include "lldb/Breakpoint/Breakpoint.h"
12ac7ddfbfSEd Maste #include "lldb/Core/Value.h"
13ac7ddfbfSEd Maste #include "lldb/Core/ValueObjectConstResult.h"
14ac7ddfbfSEd Maste #include "lldb/Symbol/Block.h"
15ac7ddfbfSEd Maste #include "lldb/Symbol/Function.h"
16444ed5c5SDimitry Andric #include "lldb/Symbol/Symbol.h"
17ac7ddfbfSEd Maste #include "lldb/Symbol/Type.h"
181c3bbb01SEd Maste #include "lldb/Target/ABI.h"
19ac7ddfbfSEd Maste #include "lldb/Target/Process.h"
20ac7ddfbfSEd Maste #include "lldb/Target/RegisterContext.h"
21ac7ddfbfSEd Maste #include "lldb/Target/StopInfo.h"
22ac7ddfbfSEd Maste #include "lldb/Target/Target.h"
23ac7ddfbfSEd Maste #include "lldb/Target/ThreadPlanStepOverRange.h"
240127ef0fSEd Maste #include "lldb/Target/ThreadPlanStepThrough.h"
25f678e45dSDimitry Andric #include "lldb/Utility/Log.h"
26ac7ddfbfSEd Maste 
27ac7ddfbfSEd Maste using namespace lldb;
28ac7ddfbfSEd Maste using namespace lldb_private;
29ac7ddfbfSEd Maste 
300127ef0fSEd Maste uint32_t ThreadPlanStepOut::s_default_flag_values = 0;
310127ef0fSEd Maste 
32ac7ddfbfSEd Maste //----------------------------------------------------------------------
33ac7ddfbfSEd Maste // ThreadPlanStepOut: Step out of the current frame
34ac7ddfbfSEd Maste //----------------------------------------------------------------------
ThreadPlanStepOut(Thread & thread,SymbolContext * context,bool first_insn,bool stop_others,Vote stop_vote,Vote run_vote,uint32_t frame_idx,LazyBool step_out_avoids_code_without_debug_info,bool continue_to_next_branch,bool gather_return_value)35435933ddSDimitry Andric ThreadPlanStepOut::ThreadPlanStepOut(
36435933ddSDimitry Andric     Thread &thread, SymbolContext *context, bool first_insn, bool stop_others,
37435933ddSDimitry Andric     Vote stop_vote, Vote run_vote, uint32_t frame_idx,
38444ed5c5SDimitry Andric     LazyBool step_out_avoids_code_without_debug_info,
39435933ddSDimitry Andric     bool continue_to_next_branch, bool gather_return_value)
40435933ddSDimitry Andric     : ThreadPlan(ThreadPlan::eKindStepOut, "Step out", thread, stop_vote,
41435933ddSDimitry Andric                  run_vote),
42435933ddSDimitry Andric       ThreadPlanShouldStopHere(this), m_step_from_insn(LLDB_INVALID_ADDRESS),
43ac7ddfbfSEd Maste       m_return_bp_id(LLDB_INVALID_BREAK_ID),
44435933ddSDimitry Andric       m_return_addr(LLDB_INVALID_ADDRESS), m_stop_others(stop_others),
45435933ddSDimitry Andric       m_immediate_step_from_function(nullptr),
46435933ddSDimitry Andric       m_calculate_return_value(gather_return_value) {
47*b5893f02SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
480127ef0fSEd Maste   SetFlagsToDefault();
490127ef0fSEd Maste   SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
500127ef0fSEd Maste 
51ac7ddfbfSEd Maste   m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
52ac7ddfbfSEd Maste 
53*b5893f02SDimitry Andric   uint32_t return_frame_index = frame_idx + 1;
54*b5893f02SDimitry Andric   StackFrameSP return_frame_sp(
55*b5893f02SDimitry Andric       m_thread.GetStackFrameAtIndex(return_frame_index));
56435933ddSDimitry Andric   StackFrameSP immediate_return_from_sp(
57435933ddSDimitry Andric       m_thread.GetStackFrameAtIndex(frame_idx));
58ac7ddfbfSEd Maste 
59ac7ddfbfSEd Maste   if (!return_frame_sp || !immediate_return_from_sp)
60ac7ddfbfSEd Maste     return; // we can't do anything here.  ValidatePlan() will return false.
61ac7ddfbfSEd Maste 
62*b5893f02SDimitry Andric   // While stepping out, behave as-if artificial frames are not present.
63*b5893f02SDimitry Andric   while (return_frame_sp->IsArtificial()) {
64*b5893f02SDimitry Andric     m_stepped_past_frames.push_back(return_frame_sp);
65*b5893f02SDimitry Andric 
66*b5893f02SDimitry Andric     ++return_frame_index;
67*b5893f02SDimitry Andric     return_frame_sp = m_thread.GetStackFrameAtIndex(return_frame_index);
68*b5893f02SDimitry Andric 
69*b5893f02SDimitry Andric     // We never expect to see an artificial frame without a regular ancestor.
70*b5893f02SDimitry Andric     // If this happens, log the issue and defensively refuse to step out.
71*b5893f02SDimitry Andric     if (!return_frame_sp) {
72*b5893f02SDimitry Andric       LLDB_LOG(log, "Can't step out of frame with artificial ancestors");
73*b5893f02SDimitry Andric       return;
74*b5893f02SDimitry Andric     }
75*b5893f02SDimitry Andric   }
76*b5893f02SDimitry Andric 
77ac7ddfbfSEd Maste   m_step_out_to_id = return_frame_sp->GetStackID();
78ac7ddfbfSEd Maste   m_immediate_step_from_id = immediate_return_from_sp->GetStackID();
79ac7ddfbfSEd Maste 
804ba319b5SDimitry Andric   // If the frame directly below the one we are returning to is inlined, we
814ba319b5SDimitry Andric   // have to be a little more careful.  It is non-trivial to determine the real
824ba319b5SDimitry Andric   // "return code address" for an inlined frame, so we have to work our way to
834ba319b5SDimitry Andric   // that frame and then step out.
84*b5893f02SDimitry Andric   if (immediate_return_from_sp->IsInlined()) {
85435933ddSDimitry Andric     if (frame_idx > 0) {
86435933ddSDimitry Andric       // First queue a plan that gets us to this inlined frame, and when we get
874ba319b5SDimitry Andric       // there we'll queue a second plan that walks us out of this frame.
88435933ddSDimitry Andric       m_step_out_to_inline_plan_sp.reset(new ThreadPlanStepOut(
89435933ddSDimitry Andric           m_thread, nullptr, false, stop_others, eVoteNoOpinion, eVoteNoOpinion,
90435933ddSDimitry Andric           frame_idx - 1, eLazyBoolNo, continue_to_next_branch));
91435933ddSDimitry Andric       static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get())
92435933ddSDimitry Andric           ->SetShouldStopHereCallbacks(nullptr, nullptr);
937aa51b79SEd Maste       m_step_out_to_inline_plan_sp->SetPrivate(true);
94435933ddSDimitry Andric     } else {
954ba319b5SDimitry Andric       // If we're already at the inlined frame we're stepping through, then
964ba319b5SDimitry Andric       // just do that now.
97ac7ddfbfSEd Maste       QueueInlinedStepPlan(false);
98ac7ddfbfSEd Maste     }
99*b5893f02SDimitry Andric   } else {
100ac7ddfbfSEd Maste     // Find the return address and set a breakpoint there:
101ac7ddfbfSEd Maste     // FIXME - can we do this more securely if we know first_insn?
102ac7ddfbfSEd Maste 
103444ed5c5SDimitry Andric     Address return_address(return_frame_sp->GetFrameCodeAddress());
104435933ddSDimitry Andric     if (continue_to_next_branch) {
105444ed5c5SDimitry Andric       SymbolContext return_address_sc;
106444ed5c5SDimitry Andric       AddressRange range;
107444ed5c5SDimitry Andric       Address return_address_decr_pc = return_address;
108444ed5c5SDimitry Andric       if (return_address_decr_pc.GetOffset() > 0)
109444ed5c5SDimitry Andric         return_address_decr_pc.Slide(-1);
110444ed5c5SDimitry Andric 
111435933ddSDimitry Andric       return_address_decr_pc.CalculateSymbolContext(
112435933ddSDimitry Andric           &return_address_sc, lldb::eSymbolContextLineEntry);
113435933ddSDimitry Andric       if (return_address_sc.line_entry.IsValid()) {
114435933ddSDimitry Andric         range =
115435933ddSDimitry Andric             return_address_sc.line_entry.GetSameLineContiguousAddressRange();
116435933ddSDimitry Andric         if (range.GetByteSize() > 0) {
117435933ddSDimitry Andric           return_address =
118435933ddSDimitry Andric               m_thread.GetProcess()->AdvanceAddressToNextBranchInstruction(
119435933ddSDimitry Andric                   return_address, range);
120444ed5c5SDimitry Andric         }
121444ed5c5SDimitry Andric       }
122444ed5c5SDimitry Andric     }
123435933ddSDimitry Andric     m_return_addr =
124435933ddSDimitry Andric         return_address.GetLoadAddress(&m_thread.GetProcess()->GetTarget());
125ac7ddfbfSEd Maste 
126ac7ddfbfSEd Maste     if (m_return_addr == LLDB_INVALID_ADDRESS)
127ac7ddfbfSEd Maste       return;
128ac7ddfbfSEd Maste 
129435933ddSDimitry Andric     Breakpoint *return_bp = m_thread.CalculateTarget()
130435933ddSDimitry Andric                                 ->CreateBreakpoint(m_return_addr, true, false)
131435933ddSDimitry Andric                                 .get();
132*b5893f02SDimitry Andric 
133435933ddSDimitry Andric     if (return_bp != nullptr) {
134*b5893f02SDimitry Andric       if (return_bp->IsHardware() && !return_bp->HasResolvedLocations())
135*b5893f02SDimitry Andric         m_could_not_resolve_hw_bp = true;
136ac7ddfbfSEd Maste       return_bp->SetThreadID(m_thread.GetID());
137ac7ddfbfSEd Maste       m_return_bp_id = return_bp->GetID();
138ac7ddfbfSEd Maste       return_bp->SetBreakpointKind("step-out");
139ac7ddfbfSEd Maste     }
140ac7ddfbfSEd Maste 
141435933ddSDimitry Andric     if (immediate_return_from_sp) {
142435933ddSDimitry Andric       const SymbolContext &sc =
143435933ddSDimitry Andric           immediate_return_from_sp->GetSymbolContext(eSymbolContextFunction);
144435933ddSDimitry Andric       if (sc.function) {
145ac7ddfbfSEd Maste         m_immediate_step_from_function = sc.function;
146ac7ddfbfSEd Maste       }
147ac7ddfbfSEd Maste     }
148ac7ddfbfSEd Maste   }
149ac7ddfbfSEd Maste }
150ac7ddfbfSEd Maste 
SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info)151435933ddSDimitry Andric void ThreadPlanStepOut::SetupAvoidNoDebug(
152435933ddSDimitry Andric     LazyBool step_out_avoids_code_without_debug_info) {
1530127ef0fSEd Maste   bool avoid_nodebug = true;
154435933ddSDimitry Andric   switch (step_out_avoids_code_without_debug_info) {
1550127ef0fSEd Maste   case eLazyBoolYes:
1560127ef0fSEd Maste     avoid_nodebug = true;
1570127ef0fSEd Maste     break;
1580127ef0fSEd Maste   case eLazyBoolNo:
1590127ef0fSEd Maste     avoid_nodebug = false;
1600127ef0fSEd Maste     break;
1610127ef0fSEd Maste   case eLazyBoolCalculate:
1620127ef0fSEd Maste     avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug();
1630127ef0fSEd Maste     break;
1640127ef0fSEd Maste   }
1650127ef0fSEd Maste   if (avoid_nodebug)
1660127ef0fSEd Maste     GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
1670127ef0fSEd Maste   else
1680127ef0fSEd Maste     GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
1690127ef0fSEd Maste }
1700127ef0fSEd Maste 
DidPush()171435933ddSDimitry Andric void ThreadPlanStepOut::DidPush() {
1720127ef0fSEd Maste   if (m_step_out_to_inline_plan_sp)
1730127ef0fSEd Maste     m_thread.QueueThreadPlan(m_step_out_to_inline_plan_sp, false);
174ac7ddfbfSEd Maste   else if (m_step_through_inline_plan_sp)
175ac7ddfbfSEd Maste     m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
176ac7ddfbfSEd Maste }
177ac7ddfbfSEd Maste 
~ThreadPlanStepOut()178435933ddSDimitry Andric ThreadPlanStepOut::~ThreadPlanStepOut() {
179ac7ddfbfSEd Maste   if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
180ac7ddfbfSEd Maste     m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id);
181ac7ddfbfSEd Maste }
182ac7ddfbfSEd Maste 
GetDescription(Stream * s,lldb::DescriptionLevel level)183435933ddSDimitry Andric void ThreadPlanStepOut::GetDescription(Stream *s,
184435933ddSDimitry Andric                                        lldb::DescriptionLevel level) {
185ac7ddfbfSEd Maste   if (level == lldb::eDescriptionLevelBrief)
186ac7ddfbfSEd Maste     s->Printf("step out");
187435933ddSDimitry Andric   else {
1880127ef0fSEd Maste     if (m_step_out_to_inline_plan_sp)
189ac7ddfbfSEd Maste       s->Printf("Stepping out to inlined frame so we can walk through it.");
190ac7ddfbfSEd Maste     else if (m_step_through_inline_plan_sp)
191ac7ddfbfSEd Maste       s->Printf("Stepping out by stepping through inlined function.");
192435933ddSDimitry Andric     else {
1937aa51b79SEd Maste       s->Printf("Stepping out from ");
1947aa51b79SEd Maste       Address tmp_address;
195435933ddSDimitry Andric       if (tmp_address.SetLoadAddress(m_step_from_insn, &GetTarget())) {
196435933ddSDimitry Andric         tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription,
197435933ddSDimitry Andric                          Address::DumpStyleLoadAddress);
198435933ddSDimitry Andric       } else {
1997aa51b79SEd Maste         s->Printf("address 0x%" PRIx64 "", (uint64_t)m_step_from_insn);
2007aa51b79SEd Maste       }
2017aa51b79SEd Maste 
202435933ddSDimitry Andric       // FIXME: find some useful way to present the m_return_id, since there may
203435933ddSDimitry Andric       // be multiple copies of the
2047aa51b79SEd Maste       // same function on the stack.
2057aa51b79SEd Maste 
2067aa51b79SEd Maste       s->Printf(" returning to frame at ");
207435933ddSDimitry Andric       if (tmp_address.SetLoadAddress(m_return_addr, &GetTarget())) {
208435933ddSDimitry Andric         tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription,
209435933ddSDimitry Andric                          Address::DumpStyleLoadAddress);
210435933ddSDimitry Andric       } else {
2117aa51b79SEd Maste         s->Printf("address 0x%" PRIx64 "", (uint64_t)m_return_addr);
2127aa51b79SEd Maste       }
2137aa51b79SEd Maste 
2147aa51b79SEd Maste       if (level == eDescriptionLevelVerbose)
2157aa51b79SEd Maste         s->Printf(" using breakpoint site %d", m_return_bp_id);
2167aa51b79SEd Maste     }
217ac7ddfbfSEd Maste   }
218*b5893f02SDimitry Andric 
219*b5893f02SDimitry Andric   s->Printf("\n");
220*b5893f02SDimitry Andric   for (StackFrameSP frame_sp : m_stepped_past_frames) {
221*b5893f02SDimitry Andric     s->Printf("Stepped out past: ");
222*b5893f02SDimitry Andric     frame_sp->DumpUsingSettingsFormat(s);
223*b5893f02SDimitry Andric   }
224ac7ddfbfSEd Maste }
225ac7ddfbfSEd Maste 
ValidatePlan(Stream * error)226435933ddSDimitry Andric bool ThreadPlanStepOut::ValidatePlan(Stream *error) {
2270127ef0fSEd Maste   if (m_step_out_to_inline_plan_sp)
2280127ef0fSEd Maste     return m_step_out_to_inline_plan_sp->ValidatePlan(error);
229*b5893f02SDimitry Andric 
230*b5893f02SDimitry Andric   if (m_step_through_inline_plan_sp)
231ac7ddfbfSEd Maste     return m_step_through_inline_plan_sp->ValidatePlan(error);
232*b5893f02SDimitry Andric 
233*b5893f02SDimitry Andric   if (m_could_not_resolve_hw_bp) {
234*b5893f02SDimitry Andric     if (error)
235*b5893f02SDimitry Andric       error->PutCString(
236*b5893f02SDimitry Andric           "Could not create hardware breakpoint for thread plan.");
237*b5893f02SDimitry Andric     return false;
238*b5893f02SDimitry Andric   }
239*b5893f02SDimitry Andric 
240*b5893f02SDimitry Andric   if (m_return_bp_id == LLDB_INVALID_BREAK_ID) {
241ac7ddfbfSEd Maste     if (error)
242ac7ddfbfSEd Maste       error->PutCString("Could not create return address breakpoint.");
243ac7ddfbfSEd Maste     return false;
244*b5893f02SDimitry Andric   }
245*b5893f02SDimitry Andric 
246ac7ddfbfSEd Maste   return true;
247ac7ddfbfSEd Maste }
248ac7ddfbfSEd Maste 
DoPlanExplainsStop(Event * event_ptr)249435933ddSDimitry Andric bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) {
2504ba319b5SDimitry Andric   // If the step out plan is done, then we just need to step through the
2514ba319b5SDimitry Andric   // inlined frame.
252435933ddSDimitry Andric   if (m_step_out_to_inline_plan_sp) {
2539f2f44ceSEd Maste     return m_step_out_to_inline_plan_sp->MischiefManaged();
254435933ddSDimitry Andric   } else if (m_step_through_inline_plan_sp) {
255435933ddSDimitry Andric     if (m_step_through_inline_plan_sp->MischiefManaged()) {
256ac7ddfbfSEd Maste       CalculateReturnValue();
257ac7ddfbfSEd Maste       SetPlanComplete();
258ac7ddfbfSEd Maste       return true;
259435933ddSDimitry Andric     } else
260ac7ddfbfSEd Maste       return false;
261435933ddSDimitry Andric   } else if (m_step_out_further_plan_sp) {
2629f2f44ceSEd Maste     return m_step_out_further_plan_sp->MischiefManaged();
263ac7ddfbfSEd Maste   }
264ac7ddfbfSEd Maste 
265435933ddSDimitry Andric   // We don't explain signals or breakpoints (breakpoints that handle stepping
2664ba319b5SDimitry Andric   // in or out will be handled by a child plan.
267ac7ddfbfSEd Maste 
268ac7ddfbfSEd Maste   StopInfoSP stop_info_sp = GetPrivateStopInfo();
269435933ddSDimitry Andric   if (stop_info_sp) {
270ac7ddfbfSEd Maste     StopReason reason = stop_info_sp->GetStopReason();
271435933ddSDimitry Andric     if (reason == eStopReasonBreakpoint) {
2724ba319b5SDimitry Andric       // If this is OUR breakpoint, we're fine, otherwise we don't know why
2734ba319b5SDimitry Andric       // this happened...
274435933ddSDimitry Andric       BreakpointSiteSP site_sp(
275435933ddSDimitry Andric           m_thread.GetProcess()->GetBreakpointSiteList().FindByID(
276435933ddSDimitry Andric               stop_info_sp->GetValue()));
277435933ddSDimitry Andric       if (site_sp && site_sp->IsBreakpointAtThisSite(m_return_bp_id)) {
278ac7ddfbfSEd Maste         bool done;
279ac7ddfbfSEd Maste 
280ac7ddfbfSEd Maste         StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
281ac7ddfbfSEd Maste 
282ac7ddfbfSEd Maste         if (m_step_out_to_id == frame_zero_id)
283ac7ddfbfSEd Maste           done = true;
284435933ddSDimitry Andric         else if (m_step_out_to_id < frame_zero_id) {
285ac7ddfbfSEd Maste           // Either we stepped past the breakpoint, or the stack ID calculation
286ac7ddfbfSEd Maste           // was incorrect and we should probably stop.
287ac7ddfbfSEd Maste           done = true;
288435933ddSDimitry Andric         } else {
2899f2f44ceSEd Maste           done = (m_immediate_step_from_id < frame_zero_id);
290ac7ddfbfSEd Maste         }
291ac7ddfbfSEd Maste 
292435933ddSDimitry Andric         if (done) {
293*b5893f02SDimitry Andric           if (InvokeShouldStopHereCallback(eFrameCompareOlder, m_status)) {
294ac7ddfbfSEd Maste             CalculateReturnValue();
295ac7ddfbfSEd Maste             SetPlanComplete();
296ac7ddfbfSEd Maste           }
2970127ef0fSEd Maste         }
298ac7ddfbfSEd Maste 
299435933ddSDimitry Andric         // If there was only one owner, then we're done.  But if we also hit
3004ba319b5SDimitry Andric         // some user breakpoint on our way out, we should mark ourselves as
3014ba319b5SDimitry Andric         // done, but also not claim to explain the stop, since it is more
3024ba319b5SDimitry Andric         // important to report the user breakpoint than the step out
3034ba319b5SDimitry Andric         // completion.
304ac7ddfbfSEd Maste 
305ac7ddfbfSEd Maste         if (site_sp->GetNumberOfOwners() == 1)
306ac7ddfbfSEd Maste           return true;
307ac7ddfbfSEd Maste       }
308ac7ddfbfSEd Maste       return false;
309435933ddSDimitry Andric     } else if (IsUsuallyUnexplainedStopReason(reason))
310ac7ddfbfSEd Maste       return false;
3119f2f44ceSEd Maste     else
312ac7ddfbfSEd Maste       return true;
313ac7ddfbfSEd Maste   }
314ac7ddfbfSEd Maste   return true;
315ac7ddfbfSEd Maste }
316ac7ddfbfSEd Maste 
ShouldStop(Event * event_ptr)317435933ddSDimitry Andric bool ThreadPlanStepOut::ShouldStop(Event *event_ptr) {
318ac7ddfbfSEd Maste   if (IsPlanComplete())
319ac7ddfbfSEd Maste     return true;
320ac7ddfbfSEd Maste 
3210127ef0fSEd Maste   bool done = false;
322435933ddSDimitry Andric   if (m_step_out_to_inline_plan_sp) {
323435933ddSDimitry Andric     if (m_step_out_to_inline_plan_sp->MischiefManaged()) {
3240127ef0fSEd Maste       // Now step through the inlined stack we are in:
325435933ddSDimitry Andric       if (QueueInlinedStepPlan(true)) {
3260127ef0fSEd Maste         // If we can't queue a plan to do this, then just call ourselves done.
3270127ef0fSEd Maste         m_step_out_to_inline_plan_sp.reset();
3280127ef0fSEd Maste         SetPlanComplete(false);
3290127ef0fSEd Maste         return true;
330435933ddSDimitry Andric       } else
3310127ef0fSEd Maste         done = true;
332435933ddSDimitry Andric     } else
3330127ef0fSEd Maste       return m_step_out_to_inline_plan_sp->ShouldStop(event_ptr);
334435933ddSDimitry Andric   } else if (m_step_through_inline_plan_sp) {
3350127ef0fSEd Maste     if (m_step_through_inline_plan_sp->MischiefManaged())
3360127ef0fSEd Maste       done = true;
3370127ef0fSEd Maste     else
3380127ef0fSEd Maste       return m_step_through_inline_plan_sp->ShouldStop(event_ptr);
339435933ddSDimitry Andric   } else if (m_step_out_further_plan_sp) {
3400127ef0fSEd Maste     if (m_step_out_further_plan_sp->MischiefManaged())
3410127ef0fSEd Maste       m_step_out_further_plan_sp.reset();
3420127ef0fSEd Maste     else
3430127ef0fSEd Maste       return m_step_out_further_plan_sp->ShouldStop(event_ptr);
3440127ef0fSEd Maste   }
345ac7ddfbfSEd Maste 
346435933ddSDimitry Andric   if (!done) {
347ac7ddfbfSEd Maste     StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
3489f2f44ceSEd Maste     done = !(frame_zero_id < m_step_out_to_id);
3490127ef0fSEd Maste   }
3500127ef0fSEd Maste 
3514ba319b5SDimitry Andric   // The normal step out computations think we are done, so all we need to do
3524ba319b5SDimitry Andric   // is consult the ShouldStopHere, and we are done.
353ac7ddfbfSEd Maste 
354435933ddSDimitry Andric   if (done) {
355*b5893f02SDimitry Andric     if (InvokeShouldStopHereCallback(eFrameCompareOlder, m_status)) {
356ac7ddfbfSEd Maste       CalculateReturnValue();
357ac7ddfbfSEd Maste       SetPlanComplete();
358435933ddSDimitry Andric     } else {
359435933ddSDimitry Andric       m_step_out_further_plan_sp =
360*b5893f02SDimitry Andric           QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder, m_status);
3610127ef0fSEd Maste       done = false;
362ac7ddfbfSEd Maste     }
363ac7ddfbfSEd Maste   }
3640127ef0fSEd Maste 
3650127ef0fSEd Maste   return done;
366ac7ddfbfSEd Maste }
367ac7ddfbfSEd Maste 
StopOthers()368435933ddSDimitry Andric bool ThreadPlanStepOut::StopOthers() { return m_stop_others; }
369ac7ddfbfSEd Maste 
GetPlanRunState()370435933ddSDimitry Andric StateType ThreadPlanStepOut::GetPlanRunState() { return eStateRunning; }
371ac7ddfbfSEd Maste 
DoWillResume(StateType resume_state,bool current_plan)372435933ddSDimitry Andric bool ThreadPlanStepOut::DoWillResume(StateType resume_state,
373435933ddSDimitry Andric                                      bool current_plan) {
3740127ef0fSEd Maste   if (m_step_out_to_inline_plan_sp || m_step_through_inline_plan_sp)
375ac7ddfbfSEd Maste     return true;
376ac7ddfbfSEd Maste 
377ac7ddfbfSEd Maste   if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
378ac7ddfbfSEd Maste     return false;
379ac7ddfbfSEd Maste 
380435933ddSDimitry Andric   if (current_plan) {
381435933ddSDimitry Andric     Breakpoint *return_bp =
382435933ddSDimitry Andric         m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get();
3839f2f44ceSEd Maste     if (return_bp != nullptr)
384ac7ddfbfSEd Maste       return_bp->SetEnabled(true);
385ac7ddfbfSEd Maste   }
386ac7ddfbfSEd Maste   return true;
387ac7ddfbfSEd Maste }
388ac7ddfbfSEd Maste 
WillStop()389435933ddSDimitry Andric bool ThreadPlanStepOut::WillStop() {
390435933ddSDimitry Andric   if (m_return_bp_id != LLDB_INVALID_BREAK_ID) {
391435933ddSDimitry Andric     Breakpoint *return_bp =
392435933ddSDimitry Andric         m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get();
3939f2f44ceSEd Maste     if (return_bp != nullptr)
394ac7ddfbfSEd Maste       return_bp->SetEnabled(false);
395ac7ddfbfSEd Maste   }
396ac7ddfbfSEd Maste 
397ac7ddfbfSEd Maste   return true;
398ac7ddfbfSEd Maste }
399ac7ddfbfSEd Maste 
MischiefManaged()400435933ddSDimitry Andric bool ThreadPlanStepOut::MischiefManaged() {
401435933ddSDimitry Andric   if (IsPlanComplete()) {
402ac7ddfbfSEd Maste     // Did I reach my breakpoint?  If so I'm done.
403ac7ddfbfSEd Maste     //
404435933ddSDimitry Andric     // I also check the stack depth, since if we've blown past the breakpoint
405435933ddSDimitry Andric     // for some
406435933ddSDimitry Andric     // reason and we're now stopping for some other reason altogether, then
4074ba319b5SDimitry Andric     // we're done with this step out operation.
408ac7ddfbfSEd Maste 
409ac7ddfbfSEd Maste     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
410ac7ddfbfSEd Maste     if (log)
411ac7ddfbfSEd Maste       log->Printf("Completed step out plan.");
412435933ddSDimitry Andric     if (m_return_bp_id != LLDB_INVALID_BREAK_ID) {
413ac7ddfbfSEd Maste       m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id);
414ac7ddfbfSEd Maste       m_return_bp_id = LLDB_INVALID_BREAK_ID;
415ac7ddfbfSEd Maste     }
416ac7ddfbfSEd Maste 
417ac7ddfbfSEd Maste     ThreadPlan::MischiefManaged();
418ac7ddfbfSEd Maste     return true;
419435933ddSDimitry Andric   } else {
420ac7ddfbfSEd Maste     return false;
421ac7ddfbfSEd Maste   }
422ac7ddfbfSEd Maste }
423ac7ddfbfSEd Maste 
QueueInlinedStepPlan(bool queue_now)424435933ddSDimitry Andric bool ThreadPlanStepOut::QueueInlinedStepPlan(bool queue_now) {
425435933ddSDimitry Andric   // Now figure out the range of this inlined block, and set up a "step through
4264ba319b5SDimitry Andric   // range" plan for that.  If we've been provided with a context, then use the
4274ba319b5SDimitry Andric   // block in that context.
428ac7ddfbfSEd Maste   StackFrameSP immediate_return_from_sp(m_thread.GetStackFrameAtIndex(0));
429ac7ddfbfSEd Maste   if (!immediate_return_from_sp)
430ac7ddfbfSEd Maste     return false;
431ac7ddfbfSEd Maste 
432ac7ddfbfSEd Maste   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
433435933ddSDimitry Andric   if (log) {
434ac7ddfbfSEd Maste     StreamString s;
435ac7ddfbfSEd Maste     immediate_return_from_sp->Dump(&s, true, false);
436ac7ddfbfSEd Maste     log->Printf("Queuing inlined frame to step past: %s.", s.GetData());
437ac7ddfbfSEd Maste   }
438ac7ddfbfSEd Maste 
439ac7ddfbfSEd Maste   Block *from_block = immediate_return_from_sp->GetFrameBlock();
440435933ddSDimitry Andric   if (from_block) {
441ac7ddfbfSEd Maste     Block *inlined_block = from_block->GetContainingInlinedBlock();
442435933ddSDimitry Andric     if (inlined_block) {
443ac7ddfbfSEd Maste       size_t num_ranges = inlined_block->GetNumRanges();
444ac7ddfbfSEd Maste       AddressRange inline_range;
445435933ddSDimitry Andric       if (inlined_block->GetRangeAtIndex(0, inline_range)) {
446ac7ddfbfSEd Maste         SymbolContext inlined_sc;
447ac7ddfbfSEd Maste         inlined_block->CalculateSymbolContext(&inlined_sc);
448ac7ddfbfSEd Maste         inlined_sc.target_sp = GetTarget().shared_from_this();
449435933ddSDimitry Andric         RunMode run_mode =
450435933ddSDimitry Andric             m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads;
4510127ef0fSEd Maste         const LazyBool avoid_no_debug = eLazyBoolNo;
4527aa51b79SEd Maste 
453435933ddSDimitry Andric         m_step_through_inline_plan_sp.reset(new ThreadPlanStepOverRange(
454435933ddSDimitry Andric             m_thread, inline_range, inlined_sc, run_mode, avoid_no_debug));
455435933ddSDimitry Andric         ThreadPlanStepOverRange *step_through_inline_plan_ptr =
456435933ddSDimitry Andric             static_cast<ThreadPlanStepOverRange *>(
457435933ddSDimitry Andric                 m_step_through_inline_plan_sp.get());
4587aa51b79SEd Maste         m_step_through_inline_plan_sp->SetPrivate(true);
4597aa51b79SEd Maste 
460ac7ddfbfSEd Maste         step_through_inline_plan_ptr->SetOkayToDiscard(true);
461ac7ddfbfSEd Maste         StreamString errors;
462435933ddSDimitry Andric         if (!step_through_inline_plan_ptr->ValidatePlan(&errors)) {
463ac7ddfbfSEd Maste           // FIXME: Log this failure.
464ac7ddfbfSEd Maste           delete step_through_inline_plan_ptr;
465ac7ddfbfSEd Maste           return false;
466ac7ddfbfSEd Maste         }
467ac7ddfbfSEd Maste 
468435933ddSDimitry Andric         for (size_t i = 1; i < num_ranges; i++) {
469ac7ddfbfSEd Maste           if (inlined_block->GetRangeAtIndex(i, inline_range))
470ac7ddfbfSEd Maste             step_through_inline_plan_ptr->AddRange(inline_range);
471ac7ddfbfSEd Maste         }
4727aa51b79SEd Maste 
473ac7ddfbfSEd Maste         if (queue_now)
474ac7ddfbfSEd Maste           m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
475ac7ddfbfSEd Maste         return true;
476ac7ddfbfSEd Maste       }
477ac7ddfbfSEd Maste     }
478ac7ddfbfSEd Maste   }
479ac7ddfbfSEd Maste 
480ac7ddfbfSEd Maste   return false;
481ac7ddfbfSEd Maste }
482ac7ddfbfSEd Maste 
CalculateReturnValue()483435933ddSDimitry Andric void ThreadPlanStepOut::CalculateReturnValue() {
484ac7ddfbfSEd Maste   if (m_return_valobj_sp)
485ac7ddfbfSEd Maste     return;
486ac7ddfbfSEd Maste 
487435933ddSDimitry Andric   if (!m_calculate_return_value)
488435933ddSDimitry Andric     return;
489435933ddSDimitry Andric 
490435933ddSDimitry Andric   if (m_immediate_step_from_function != nullptr) {
491435933ddSDimitry Andric     CompilerType return_compiler_type =
492435933ddSDimitry Andric         m_immediate_step_from_function->GetCompilerType()
493435933ddSDimitry Andric             .GetFunctionReturnType();
494435933ddSDimitry Andric     if (return_compiler_type) {
495ac7ddfbfSEd Maste       lldb::ABISP abi_sp = m_thread.GetProcess()->GetABI();
496ac7ddfbfSEd Maste       if (abi_sp)
497435933ddSDimitry Andric         m_return_valobj_sp =
498435933ddSDimitry Andric             abi_sp->GetReturnValueObject(m_thread, return_compiler_type);
499ac7ddfbfSEd Maste     }
500ac7ddfbfSEd Maste   }
501ac7ddfbfSEd Maste }
502ac7ddfbfSEd Maste 
IsPlanStale()503435933ddSDimitry Andric bool ThreadPlanStepOut::IsPlanStale() {
5044ba319b5SDimitry Andric   // If we are still lower on the stack than the frame we are returning to,
5054ba319b5SDimitry Andric   // then there's something for us to do.  Otherwise, we're stale.
506ac7ddfbfSEd Maste 
507ac7ddfbfSEd Maste   StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
5089f2f44ceSEd Maste   return !(frame_zero_id < m_step_out_to_id);
509ac7ddfbfSEd Maste }
510