xref: /openbsd-src/gnu/llvm/lldb/source/Target/ThreadPlanStepOut.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- ThreadPlanStepOut.cpp ---------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "lldb/Target/ThreadPlanStepOut.h"
10061da546Spatrick #include "lldb/Breakpoint/Breakpoint.h"
11061da546Spatrick #include "lldb/Core/Value.h"
12061da546Spatrick #include "lldb/Core/ValueObjectConstResult.h"
13061da546Spatrick #include "lldb/Symbol/Block.h"
14061da546Spatrick #include "lldb/Symbol/Function.h"
15061da546Spatrick #include "lldb/Symbol/Symbol.h"
16061da546Spatrick #include "lldb/Symbol/Type.h"
17061da546Spatrick #include "lldb/Target/ABI.h"
18061da546Spatrick #include "lldb/Target/Process.h"
19061da546Spatrick #include "lldb/Target/RegisterContext.h"
20061da546Spatrick #include "lldb/Target/StopInfo.h"
21061da546Spatrick #include "lldb/Target/Target.h"
22061da546Spatrick #include "lldb/Target/ThreadPlanStepOverRange.h"
23061da546Spatrick #include "lldb/Target/ThreadPlanStepThrough.h"
24*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
25061da546Spatrick #include "lldb/Utility/Log.h"
26061da546Spatrick 
27061da546Spatrick #include <memory>
28061da546Spatrick 
29061da546Spatrick using namespace lldb;
30061da546Spatrick using namespace lldb_private;
31061da546Spatrick 
32061da546Spatrick uint32_t ThreadPlanStepOut::s_default_flag_values = 0;
33061da546Spatrick 
34061da546Spatrick // ThreadPlanStepOut: Step out of the current frame
ThreadPlanStepOut(Thread & thread,SymbolContext * context,bool first_insn,bool stop_others,Vote report_stop_vote,Vote report_run_vote,uint32_t frame_idx,LazyBool step_out_avoids_code_without_debug_info,bool continue_to_next_branch,bool gather_return_value)35061da546Spatrick ThreadPlanStepOut::ThreadPlanStepOut(
36061da546Spatrick     Thread &thread, SymbolContext *context, bool first_insn, bool stop_others,
37be691f3bSpatrick     Vote report_stop_vote, Vote report_run_vote, uint32_t frame_idx,
38061da546Spatrick     LazyBool step_out_avoids_code_without_debug_info,
39061da546Spatrick     bool continue_to_next_branch, bool gather_return_value)
40be691f3bSpatrick     : ThreadPlan(ThreadPlan::eKindStepOut, "Step out", thread, report_stop_vote,
41be691f3bSpatrick                  report_run_vote),
42061da546Spatrick       ThreadPlanShouldStopHere(this), m_step_from_insn(LLDB_INVALID_ADDRESS),
43061da546Spatrick       m_return_bp_id(LLDB_INVALID_BREAK_ID),
44061da546Spatrick       m_return_addr(LLDB_INVALID_ADDRESS), m_stop_others(stop_others),
45061da546Spatrick       m_immediate_step_from_function(nullptr),
46061da546Spatrick       m_calculate_return_value(gather_return_value) {
47*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Step);
48061da546Spatrick   SetFlagsToDefault();
49061da546Spatrick   SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
50061da546Spatrick 
51dda28197Spatrick   m_step_from_insn = thread.GetRegisterContext()->GetPC(0);
52061da546Spatrick 
53061da546Spatrick   uint32_t return_frame_index = frame_idx + 1;
54dda28197Spatrick   StackFrameSP return_frame_sp(thread.GetStackFrameAtIndex(return_frame_index));
55dda28197Spatrick   StackFrameSP immediate_return_from_sp(thread.GetStackFrameAtIndex(frame_idx));
56061da546Spatrick 
57061da546Spatrick   if (!return_frame_sp || !immediate_return_from_sp)
58061da546Spatrick     return; // we can't do anything here.  ValidatePlan() will return false.
59061da546Spatrick 
60061da546Spatrick   // While stepping out, behave as-if artificial frames are not present.
61061da546Spatrick   while (return_frame_sp->IsArtificial()) {
62061da546Spatrick     m_stepped_past_frames.push_back(return_frame_sp);
63061da546Spatrick 
64061da546Spatrick     ++return_frame_index;
65dda28197Spatrick     return_frame_sp = thread.GetStackFrameAtIndex(return_frame_index);
66061da546Spatrick 
67061da546Spatrick     // We never expect to see an artificial frame without a regular ancestor.
68061da546Spatrick     // If this happens, log the issue and defensively refuse to step out.
69061da546Spatrick     if (!return_frame_sp) {
70061da546Spatrick       LLDB_LOG(log, "Can't step out of frame with artificial ancestors");
71061da546Spatrick       return;
72061da546Spatrick     }
73061da546Spatrick   }
74061da546Spatrick 
75061da546Spatrick   m_step_out_to_id = return_frame_sp->GetStackID();
76061da546Spatrick   m_immediate_step_from_id = immediate_return_from_sp->GetStackID();
77061da546Spatrick 
78061da546Spatrick   // If the frame directly below the one we are returning to is inlined, we
79061da546Spatrick   // have to be a little more careful.  It is non-trivial to determine the real
80061da546Spatrick   // "return code address" for an inlined frame, so we have to work our way to
81061da546Spatrick   // that frame and then step out.
82061da546Spatrick   if (immediate_return_from_sp->IsInlined()) {
83061da546Spatrick     if (frame_idx > 0) {
84061da546Spatrick       // First queue a plan that gets us to this inlined frame, and when we get
85061da546Spatrick       // there we'll queue a second plan that walks us out of this frame.
86061da546Spatrick       m_step_out_to_inline_plan_sp = std::make_shared<ThreadPlanStepOut>(
87dda28197Spatrick           thread, nullptr, false, stop_others, eVoteNoOpinion, eVoteNoOpinion,
88061da546Spatrick           frame_idx - 1, eLazyBoolNo, continue_to_next_branch);
89061da546Spatrick       static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get())
90061da546Spatrick           ->SetShouldStopHereCallbacks(nullptr, nullptr);
91061da546Spatrick       m_step_out_to_inline_plan_sp->SetPrivate(true);
92061da546Spatrick     } else {
93061da546Spatrick       // If we're already at the inlined frame we're stepping through, then
94061da546Spatrick       // just do that now.
95061da546Spatrick       QueueInlinedStepPlan(false);
96061da546Spatrick     }
97061da546Spatrick   } else {
98061da546Spatrick     // Find the return address and set a breakpoint there:
99061da546Spatrick     // FIXME - can we do this more securely if we know first_insn?
100061da546Spatrick 
101061da546Spatrick     Address return_address(return_frame_sp->GetFrameCodeAddress());
102061da546Spatrick     if (continue_to_next_branch) {
103061da546Spatrick       SymbolContext return_address_sc;
104061da546Spatrick       AddressRange range;
105061da546Spatrick       Address return_address_decr_pc = return_address;
106061da546Spatrick       if (return_address_decr_pc.GetOffset() > 0)
107061da546Spatrick         return_address_decr_pc.Slide(-1);
108061da546Spatrick 
109061da546Spatrick       return_address_decr_pc.CalculateSymbolContext(
110061da546Spatrick           &return_address_sc, lldb::eSymbolContextLineEntry);
111061da546Spatrick       if (return_address_sc.line_entry.IsValid()) {
112061da546Spatrick         const bool include_inlined_functions = false;
113061da546Spatrick         range = return_address_sc.line_entry.GetSameLineContiguousAddressRange(
114061da546Spatrick             include_inlined_functions);
115061da546Spatrick         if (range.GetByteSize() > 0) {
116dda28197Spatrick           return_address = m_process.AdvanceAddressToNextBranchInstruction(
117061da546Spatrick               return_address, range);
118061da546Spatrick         }
119061da546Spatrick       }
120061da546Spatrick     }
121dda28197Spatrick     m_return_addr = return_address.GetLoadAddress(&m_process.GetTarget());
122061da546Spatrick 
123061da546Spatrick     if (m_return_addr == LLDB_INVALID_ADDRESS)
124061da546Spatrick       return;
125061da546Spatrick 
126061da546Spatrick     // Perform some additional validation on the return address.
127061da546Spatrick     uint32_t permissions = 0;
128dda28197Spatrick     if (!m_process.GetLoadAddressPermissions(m_return_addr, permissions)) {
129dda28197Spatrick       LLDB_LOGF(log, "ThreadPlanStepOut(%p): Return address (0x%" PRIx64
130dda28197Spatrick                 ") permissions not found.", static_cast<void *>(this),
131061da546Spatrick                 m_return_addr);
132061da546Spatrick     } else if (!(permissions & ePermissionsExecutable)) {
133061da546Spatrick       m_constructor_errors.Printf("Return address (0x%" PRIx64
134061da546Spatrick                                   ") did not point to executable memory.",
135061da546Spatrick                                   m_return_addr);
136061da546Spatrick       LLDB_LOGF(log, "ThreadPlanStepOut(%p): %s", static_cast<void *>(this),
137061da546Spatrick                 m_constructor_errors.GetData());
138061da546Spatrick       return;
139061da546Spatrick     }
140061da546Spatrick 
141dda28197Spatrick     Breakpoint *return_bp =
142dda28197Spatrick         GetTarget().CreateBreakpoint(m_return_addr, true, false).get();
143061da546Spatrick 
144061da546Spatrick     if (return_bp != nullptr) {
145061da546Spatrick       if (return_bp->IsHardware() && !return_bp->HasResolvedLocations())
146061da546Spatrick         m_could_not_resolve_hw_bp = true;
147dda28197Spatrick       return_bp->SetThreadID(m_tid);
148061da546Spatrick       m_return_bp_id = return_bp->GetID();
149061da546Spatrick       return_bp->SetBreakpointKind("step-out");
150061da546Spatrick     }
151061da546Spatrick 
152061da546Spatrick     if (immediate_return_from_sp) {
153061da546Spatrick       const SymbolContext &sc =
154061da546Spatrick           immediate_return_from_sp->GetSymbolContext(eSymbolContextFunction);
155061da546Spatrick       if (sc.function) {
156061da546Spatrick         m_immediate_step_from_function = sc.function;
157061da546Spatrick       }
158061da546Spatrick     }
159061da546Spatrick   }
160061da546Spatrick }
161061da546Spatrick 
SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info)162061da546Spatrick void ThreadPlanStepOut::SetupAvoidNoDebug(
163061da546Spatrick     LazyBool step_out_avoids_code_without_debug_info) {
164061da546Spatrick   bool avoid_nodebug = true;
165061da546Spatrick   switch (step_out_avoids_code_without_debug_info) {
166061da546Spatrick   case eLazyBoolYes:
167061da546Spatrick     avoid_nodebug = true;
168061da546Spatrick     break;
169061da546Spatrick   case eLazyBoolNo:
170061da546Spatrick     avoid_nodebug = false;
171061da546Spatrick     break;
172061da546Spatrick   case eLazyBoolCalculate:
173dda28197Spatrick     avoid_nodebug = GetThread().GetStepOutAvoidsNoDebug();
174061da546Spatrick     break;
175061da546Spatrick   }
176061da546Spatrick   if (avoid_nodebug)
177061da546Spatrick     GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
178061da546Spatrick   else
179061da546Spatrick     GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
180061da546Spatrick }
181061da546Spatrick 
DidPush()182061da546Spatrick void ThreadPlanStepOut::DidPush() {
183dda28197Spatrick   Thread &thread = GetThread();
184061da546Spatrick   if (m_step_out_to_inline_plan_sp)
185dda28197Spatrick     thread.QueueThreadPlan(m_step_out_to_inline_plan_sp, false);
186061da546Spatrick   else if (m_step_through_inline_plan_sp)
187dda28197Spatrick     thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
188061da546Spatrick }
189061da546Spatrick 
~ThreadPlanStepOut()190061da546Spatrick ThreadPlanStepOut::~ThreadPlanStepOut() {
191061da546Spatrick   if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
192dda28197Spatrick     GetTarget().RemoveBreakpointByID(m_return_bp_id);
193061da546Spatrick }
194061da546Spatrick 
GetDescription(Stream * s,lldb::DescriptionLevel level)195061da546Spatrick void ThreadPlanStepOut::GetDescription(Stream *s,
196061da546Spatrick                                        lldb::DescriptionLevel level) {
197061da546Spatrick   if (level == lldb::eDescriptionLevelBrief)
198061da546Spatrick     s->Printf("step out");
199061da546Spatrick   else {
200061da546Spatrick     if (m_step_out_to_inline_plan_sp)
201061da546Spatrick       s->Printf("Stepping out to inlined frame so we can walk through it.");
202061da546Spatrick     else if (m_step_through_inline_plan_sp)
203061da546Spatrick       s->Printf("Stepping out by stepping through inlined function.");
204061da546Spatrick     else {
205061da546Spatrick       s->Printf("Stepping out from ");
206061da546Spatrick       Address tmp_address;
207061da546Spatrick       if (tmp_address.SetLoadAddress(m_step_from_insn, &GetTarget())) {
208dda28197Spatrick         tmp_address.Dump(s, &m_process, Address::DumpStyleResolvedDescription,
209061da546Spatrick                          Address::DumpStyleLoadAddress);
210061da546Spatrick       } else {
211061da546Spatrick         s->Printf("address 0x%" PRIx64 "", (uint64_t)m_step_from_insn);
212061da546Spatrick       }
213061da546Spatrick 
214061da546Spatrick       // FIXME: find some useful way to present the m_return_id, since there may
215061da546Spatrick       // be multiple copies of the
216061da546Spatrick       // same function on the stack.
217061da546Spatrick 
218061da546Spatrick       s->Printf(" returning to frame at ");
219061da546Spatrick       if (tmp_address.SetLoadAddress(m_return_addr, &GetTarget())) {
220dda28197Spatrick         tmp_address.Dump(s, &m_process, Address::DumpStyleResolvedDescription,
221061da546Spatrick                          Address::DumpStyleLoadAddress);
222061da546Spatrick       } else {
223061da546Spatrick         s->Printf("address 0x%" PRIx64 "", (uint64_t)m_return_addr);
224061da546Spatrick       }
225061da546Spatrick 
226061da546Spatrick       if (level == eDescriptionLevelVerbose)
227061da546Spatrick         s->Printf(" using breakpoint site %d", m_return_bp_id);
228061da546Spatrick     }
229061da546Spatrick   }
230061da546Spatrick 
231dda28197Spatrick   if (m_stepped_past_frames.empty())
232dda28197Spatrick     return;
233dda28197Spatrick 
234061da546Spatrick   s->Printf("\n");
235061da546Spatrick   for (StackFrameSP frame_sp : m_stepped_past_frames) {
236061da546Spatrick     s->Printf("Stepped out past: ");
237061da546Spatrick     frame_sp->DumpUsingSettingsFormat(s);
238061da546Spatrick   }
239061da546Spatrick }
240061da546Spatrick 
ValidatePlan(Stream * error)241061da546Spatrick bool ThreadPlanStepOut::ValidatePlan(Stream *error) {
242061da546Spatrick   if (m_step_out_to_inline_plan_sp)
243061da546Spatrick     return m_step_out_to_inline_plan_sp->ValidatePlan(error);
244061da546Spatrick 
245061da546Spatrick   if (m_step_through_inline_plan_sp)
246061da546Spatrick     return m_step_through_inline_plan_sp->ValidatePlan(error);
247061da546Spatrick 
248061da546Spatrick   if (m_could_not_resolve_hw_bp) {
249061da546Spatrick     if (error)
250061da546Spatrick       error->PutCString(
251061da546Spatrick           "Could not create hardware breakpoint for thread plan.");
252061da546Spatrick     return false;
253061da546Spatrick   }
254061da546Spatrick 
255061da546Spatrick   if (m_return_bp_id == LLDB_INVALID_BREAK_ID) {
256061da546Spatrick     if (error) {
257061da546Spatrick       error->PutCString("Could not create return address breakpoint.");
258061da546Spatrick       if (m_constructor_errors.GetSize() > 0) {
259061da546Spatrick         error->PutCString(" ");
260061da546Spatrick         error->PutCString(m_constructor_errors.GetString());
261061da546Spatrick       }
262061da546Spatrick     }
263061da546Spatrick     return false;
264061da546Spatrick   }
265061da546Spatrick 
266061da546Spatrick   return true;
267061da546Spatrick }
268061da546Spatrick 
DoPlanExplainsStop(Event * event_ptr)269061da546Spatrick bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) {
270061da546Spatrick   // If the step out plan is done, then we just need to step through the
271061da546Spatrick   // inlined frame.
272061da546Spatrick   if (m_step_out_to_inline_plan_sp) {
273061da546Spatrick     return m_step_out_to_inline_plan_sp->MischiefManaged();
274061da546Spatrick   } else if (m_step_through_inline_plan_sp) {
275061da546Spatrick     if (m_step_through_inline_plan_sp->MischiefManaged()) {
276061da546Spatrick       CalculateReturnValue();
277061da546Spatrick       SetPlanComplete();
278061da546Spatrick       return true;
279061da546Spatrick     } else
280061da546Spatrick       return false;
281061da546Spatrick   } else if (m_step_out_further_plan_sp) {
282061da546Spatrick     return m_step_out_further_plan_sp->MischiefManaged();
283061da546Spatrick   }
284061da546Spatrick 
285061da546Spatrick   // We don't explain signals or breakpoints (breakpoints that handle stepping
286061da546Spatrick   // in or out will be handled by a child plan.
287061da546Spatrick 
288061da546Spatrick   StopInfoSP stop_info_sp = GetPrivateStopInfo();
289061da546Spatrick   if (stop_info_sp) {
290061da546Spatrick     StopReason reason = stop_info_sp->GetStopReason();
291061da546Spatrick     if (reason == eStopReasonBreakpoint) {
292061da546Spatrick       // If this is OUR breakpoint, we're fine, otherwise we don't know why
293061da546Spatrick       // this happened...
294061da546Spatrick       BreakpointSiteSP site_sp(
295dda28197Spatrick           m_process.GetBreakpointSiteList().FindByID(stop_info_sp->GetValue()));
296061da546Spatrick       if (site_sp && site_sp->IsBreakpointAtThisSite(m_return_bp_id)) {
297061da546Spatrick         bool done;
298061da546Spatrick 
299dda28197Spatrick         StackID frame_zero_id =
300dda28197Spatrick             GetThread().GetStackFrameAtIndex(0)->GetStackID();
301061da546Spatrick 
302061da546Spatrick         if (m_step_out_to_id == frame_zero_id)
303061da546Spatrick           done = true;
304061da546Spatrick         else if (m_step_out_to_id < frame_zero_id) {
305061da546Spatrick           // Either we stepped past the breakpoint, or the stack ID calculation
306061da546Spatrick           // was incorrect and we should probably stop.
307061da546Spatrick           done = true;
308061da546Spatrick         } else {
309061da546Spatrick           done = (m_immediate_step_from_id < frame_zero_id);
310061da546Spatrick         }
311061da546Spatrick 
312061da546Spatrick         if (done) {
313061da546Spatrick           if (InvokeShouldStopHereCallback(eFrameCompareOlder, m_status)) {
314061da546Spatrick             CalculateReturnValue();
315061da546Spatrick             SetPlanComplete();
316061da546Spatrick           }
317061da546Spatrick         }
318061da546Spatrick 
319061da546Spatrick         // If there was only one owner, then we're done.  But if we also hit
320061da546Spatrick         // some user breakpoint on our way out, we should mark ourselves as
321061da546Spatrick         // done, but also not claim to explain the stop, since it is more
322061da546Spatrick         // important to report the user breakpoint than the step out
323061da546Spatrick         // completion.
324061da546Spatrick 
325061da546Spatrick         if (site_sp->GetNumberOfOwners() == 1)
326061da546Spatrick           return true;
327061da546Spatrick       }
328061da546Spatrick       return false;
329061da546Spatrick     } else if (IsUsuallyUnexplainedStopReason(reason))
330061da546Spatrick       return false;
331061da546Spatrick     else
332061da546Spatrick       return true;
333061da546Spatrick   }
334061da546Spatrick   return true;
335061da546Spatrick }
336061da546Spatrick 
ShouldStop(Event * event_ptr)337061da546Spatrick bool ThreadPlanStepOut::ShouldStop(Event *event_ptr) {
338061da546Spatrick   if (IsPlanComplete())
339061da546Spatrick     return true;
340061da546Spatrick 
341061da546Spatrick   bool done = false;
342061da546Spatrick   if (m_step_out_to_inline_plan_sp) {
343061da546Spatrick     if (m_step_out_to_inline_plan_sp->MischiefManaged()) {
344061da546Spatrick       // Now step through the inlined stack we are in:
345061da546Spatrick       if (QueueInlinedStepPlan(true)) {
346061da546Spatrick         // If we can't queue a plan to do this, then just call ourselves done.
347061da546Spatrick         m_step_out_to_inline_plan_sp.reset();
348061da546Spatrick         SetPlanComplete(false);
349061da546Spatrick         return true;
350061da546Spatrick       } else
351061da546Spatrick         done = true;
352061da546Spatrick     } else
353061da546Spatrick       return m_step_out_to_inline_plan_sp->ShouldStop(event_ptr);
354061da546Spatrick   } else if (m_step_through_inline_plan_sp) {
355061da546Spatrick     if (m_step_through_inline_plan_sp->MischiefManaged())
356061da546Spatrick       done = true;
357061da546Spatrick     else
358061da546Spatrick       return m_step_through_inline_plan_sp->ShouldStop(event_ptr);
359061da546Spatrick   } else if (m_step_out_further_plan_sp) {
360061da546Spatrick     if (m_step_out_further_plan_sp->MischiefManaged())
361061da546Spatrick       m_step_out_further_plan_sp.reset();
362061da546Spatrick     else
363061da546Spatrick       return m_step_out_further_plan_sp->ShouldStop(event_ptr);
364061da546Spatrick   }
365061da546Spatrick 
366061da546Spatrick   if (!done) {
367dda28197Spatrick     StackID frame_zero_id = GetThread().GetStackFrameAtIndex(0)->GetStackID();
368061da546Spatrick     done = !(frame_zero_id < m_step_out_to_id);
369061da546Spatrick   }
370061da546Spatrick 
371061da546Spatrick   // The normal step out computations think we are done, so all we need to do
372061da546Spatrick   // is consult the ShouldStopHere, and we are done.
373061da546Spatrick 
374061da546Spatrick   if (done) {
375061da546Spatrick     if (InvokeShouldStopHereCallback(eFrameCompareOlder, m_status)) {
376061da546Spatrick       CalculateReturnValue();
377061da546Spatrick       SetPlanComplete();
378061da546Spatrick     } else {
379061da546Spatrick       m_step_out_further_plan_sp =
380061da546Spatrick           QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder, m_status);
381061da546Spatrick       done = false;
382061da546Spatrick     }
383061da546Spatrick   }
384061da546Spatrick 
385061da546Spatrick   return done;
386061da546Spatrick }
387061da546Spatrick 
StopOthers()388061da546Spatrick bool ThreadPlanStepOut::StopOthers() { return m_stop_others; }
389061da546Spatrick 
GetPlanRunState()390061da546Spatrick StateType ThreadPlanStepOut::GetPlanRunState() { return eStateRunning; }
391061da546Spatrick 
DoWillResume(StateType resume_state,bool current_plan)392061da546Spatrick bool ThreadPlanStepOut::DoWillResume(StateType resume_state,
393061da546Spatrick                                      bool current_plan) {
394061da546Spatrick   if (m_step_out_to_inline_plan_sp || m_step_through_inline_plan_sp)
395061da546Spatrick     return true;
396061da546Spatrick 
397061da546Spatrick   if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
398061da546Spatrick     return false;
399061da546Spatrick 
400061da546Spatrick   if (current_plan) {
401dda28197Spatrick     Breakpoint *return_bp = GetTarget().GetBreakpointByID(m_return_bp_id).get();
402061da546Spatrick     if (return_bp != nullptr)
403061da546Spatrick       return_bp->SetEnabled(true);
404061da546Spatrick   }
405061da546Spatrick   return true;
406061da546Spatrick }
407061da546Spatrick 
WillStop()408061da546Spatrick bool ThreadPlanStepOut::WillStop() {
409061da546Spatrick   if (m_return_bp_id != LLDB_INVALID_BREAK_ID) {
410dda28197Spatrick     Breakpoint *return_bp = GetTarget().GetBreakpointByID(m_return_bp_id).get();
411061da546Spatrick     if (return_bp != nullptr)
412061da546Spatrick       return_bp->SetEnabled(false);
413061da546Spatrick   }
414061da546Spatrick 
415061da546Spatrick   return true;
416061da546Spatrick }
417061da546Spatrick 
MischiefManaged()418061da546Spatrick bool ThreadPlanStepOut::MischiefManaged() {
419061da546Spatrick   if (IsPlanComplete()) {
420061da546Spatrick     // Did I reach my breakpoint?  If so I'm done.
421061da546Spatrick     //
422061da546Spatrick     // I also check the stack depth, since if we've blown past the breakpoint
423061da546Spatrick     // for some
424061da546Spatrick     // reason and we're now stopping for some other reason altogether, then
425061da546Spatrick     // we're done with this step out operation.
426061da546Spatrick 
427*f6aab3d8Srobert     Log *log = GetLog(LLDBLog::Step);
428061da546Spatrick     if (log)
429061da546Spatrick       LLDB_LOGF(log, "Completed step out plan.");
430061da546Spatrick     if (m_return_bp_id != LLDB_INVALID_BREAK_ID) {
431dda28197Spatrick       GetTarget().RemoveBreakpointByID(m_return_bp_id);
432061da546Spatrick       m_return_bp_id = LLDB_INVALID_BREAK_ID;
433061da546Spatrick     }
434061da546Spatrick 
435061da546Spatrick     ThreadPlan::MischiefManaged();
436061da546Spatrick     return true;
437061da546Spatrick   } else {
438061da546Spatrick     return false;
439061da546Spatrick   }
440061da546Spatrick }
441061da546Spatrick 
QueueInlinedStepPlan(bool queue_now)442061da546Spatrick bool ThreadPlanStepOut::QueueInlinedStepPlan(bool queue_now) {
443061da546Spatrick   // Now figure out the range of this inlined block, and set up a "step through
444061da546Spatrick   // range" plan for that.  If we've been provided with a context, then use the
445061da546Spatrick   // block in that context.
446dda28197Spatrick   Thread &thread = GetThread();
447dda28197Spatrick   StackFrameSP immediate_return_from_sp(thread.GetStackFrameAtIndex(0));
448061da546Spatrick   if (!immediate_return_from_sp)
449061da546Spatrick     return false;
450061da546Spatrick 
451*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Step);
452061da546Spatrick   if (log) {
453061da546Spatrick     StreamString s;
454061da546Spatrick     immediate_return_from_sp->Dump(&s, true, false);
455061da546Spatrick     LLDB_LOGF(log, "Queuing inlined frame to step past: %s.", s.GetData());
456061da546Spatrick   }
457061da546Spatrick 
458061da546Spatrick   Block *from_block = immediate_return_from_sp->GetFrameBlock();
459061da546Spatrick   if (from_block) {
460061da546Spatrick     Block *inlined_block = from_block->GetContainingInlinedBlock();
461061da546Spatrick     if (inlined_block) {
462061da546Spatrick       size_t num_ranges = inlined_block->GetNumRanges();
463061da546Spatrick       AddressRange inline_range;
464061da546Spatrick       if (inlined_block->GetRangeAtIndex(0, inline_range)) {
465061da546Spatrick         SymbolContext inlined_sc;
466061da546Spatrick         inlined_block->CalculateSymbolContext(&inlined_sc);
467061da546Spatrick         inlined_sc.target_sp = GetTarget().shared_from_this();
468061da546Spatrick         RunMode run_mode =
469061da546Spatrick             m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads;
470061da546Spatrick         const LazyBool avoid_no_debug = eLazyBoolNo;
471061da546Spatrick 
472061da546Spatrick         m_step_through_inline_plan_sp =
473061da546Spatrick             std::make_shared<ThreadPlanStepOverRange>(
474dda28197Spatrick                 thread, inline_range, inlined_sc, run_mode, avoid_no_debug);
475061da546Spatrick         ThreadPlanStepOverRange *step_through_inline_plan_ptr =
476061da546Spatrick             static_cast<ThreadPlanStepOverRange *>(
477061da546Spatrick                 m_step_through_inline_plan_sp.get());
478061da546Spatrick         m_step_through_inline_plan_sp->SetPrivate(true);
479061da546Spatrick 
480061da546Spatrick         step_through_inline_plan_ptr->SetOkayToDiscard(true);
481061da546Spatrick         StreamString errors;
482061da546Spatrick         if (!step_through_inline_plan_ptr->ValidatePlan(&errors)) {
483061da546Spatrick           // FIXME: Log this failure.
484061da546Spatrick           delete step_through_inline_plan_ptr;
485061da546Spatrick           return false;
486061da546Spatrick         }
487061da546Spatrick 
488061da546Spatrick         for (size_t i = 1; i < num_ranges; i++) {
489061da546Spatrick           if (inlined_block->GetRangeAtIndex(i, inline_range))
490061da546Spatrick             step_through_inline_plan_ptr->AddRange(inline_range);
491061da546Spatrick         }
492061da546Spatrick 
493061da546Spatrick         if (queue_now)
494dda28197Spatrick           thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
495061da546Spatrick         return true;
496061da546Spatrick       }
497061da546Spatrick     }
498061da546Spatrick   }
499061da546Spatrick 
500061da546Spatrick   return false;
501061da546Spatrick }
502061da546Spatrick 
CalculateReturnValue()503061da546Spatrick void ThreadPlanStepOut::CalculateReturnValue() {
504061da546Spatrick   if (m_return_valobj_sp)
505061da546Spatrick     return;
506061da546Spatrick 
507061da546Spatrick   if (!m_calculate_return_value)
508061da546Spatrick     return;
509061da546Spatrick 
510061da546Spatrick   if (m_immediate_step_from_function != nullptr) {
511061da546Spatrick     CompilerType return_compiler_type =
512061da546Spatrick         m_immediate_step_from_function->GetCompilerType()
513061da546Spatrick             .GetFunctionReturnType();
514061da546Spatrick     if (return_compiler_type) {
515dda28197Spatrick       lldb::ABISP abi_sp = m_process.GetABI();
516061da546Spatrick       if (abi_sp)
517061da546Spatrick         m_return_valobj_sp =
518dda28197Spatrick             abi_sp->GetReturnValueObject(GetThread(), return_compiler_type);
519061da546Spatrick     }
520061da546Spatrick   }
521061da546Spatrick }
522061da546Spatrick 
IsPlanStale()523061da546Spatrick bool ThreadPlanStepOut::IsPlanStale() {
524061da546Spatrick   // If we are still lower on the stack than the frame we are returning to,
525061da546Spatrick   // then there's something for us to do.  Otherwise, we're stale.
526061da546Spatrick 
527dda28197Spatrick   StackID frame_zero_id = GetThread().GetStackFrameAtIndex(0)->GetStackID();
528061da546Spatrick   return !(frame_zero_id < m_step_out_to_id);
529061da546Spatrick }
530