xref: /src/contrib/llvm-project/lldb/source/Target/ThreadPlanStepOut.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1cfca06d7SDimitry Andric //===-- ThreadPlanStepOut.cpp ---------------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste 
9e81d9d49SDimitry Andric #include "lldb/Target/ThreadPlanStepOut.h"
10f034231aSEd Maste #include "lldb/Breakpoint/Breakpoint.h"
11f034231aSEd Maste #include "lldb/Core/Value.h"
12f034231aSEd Maste #include "lldb/Core/ValueObjectConstResult.h"
13f034231aSEd Maste #include "lldb/Symbol/Block.h"
14f034231aSEd Maste #include "lldb/Symbol/Function.h"
157fed546dSDimitry Andric #include "lldb/Symbol/Symbol.h"
16f034231aSEd Maste #include "lldb/Symbol/Type.h"
175e95aa85SEd Maste #include "lldb/Target/ABI.h"
18f034231aSEd Maste #include "lldb/Target/Process.h"
19f034231aSEd Maste #include "lldb/Target/RegisterContext.h"
20f034231aSEd Maste #include "lldb/Target/StopInfo.h"
21f034231aSEd Maste #include "lldb/Target/Target.h"
22f034231aSEd Maste #include "lldb/Target/ThreadPlanStepOverRange.h"
230cac4ca3SEd Maste #include "lldb/Target/ThreadPlanStepThrough.h"
24145449b1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
2574a628f7SDimitry Andric #include "lldb/Utility/Log.h"
26f034231aSEd Maste 
275f29bb8aSDimitry Andric #include <memory>
285f29bb8aSDimitry Andric 
29f034231aSEd Maste using namespace lldb;
30f034231aSEd Maste using namespace lldb_private;
31f034231aSEd Maste 
320cac4ca3SEd Maste uint32_t ThreadPlanStepOut::s_default_flag_values = 0;
330cac4ca3SEd Maste 
34f034231aSEd Maste // 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)3514f1b3e8SDimitry Andric ThreadPlanStepOut::ThreadPlanStepOut(
3614f1b3e8SDimitry Andric     Thread &thread, SymbolContext *context, bool first_insn, bool stop_others,
37344a3780SDimitry Andric     Vote report_stop_vote, Vote report_run_vote, uint32_t frame_idx,
387fed546dSDimitry Andric     LazyBool step_out_avoids_code_without_debug_info,
3914f1b3e8SDimitry Andric     bool continue_to_next_branch, bool gather_return_value)
40344a3780SDimitry Andric     : ThreadPlan(ThreadPlan::eKindStepOut, "Step out", thread, report_stop_vote,
41344a3780SDimitry Andric                  report_run_vote),
4214f1b3e8SDimitry Andric       ThreadPlanShouldStopHere(this), m_step_from_insn(LLDB_INVALID_ADDRESS),
43f034231aSEd Maste       m_return_bp_id(LLDB_INVALID_BREAK_ID),
4414f1b3e8SDimitry Andric       m_return_addr(LLDB_INVALID_ADDRESS), m_stop_others(stop_others),
4514f1b3e8SDimitry Andric       m_immediate_step_from_function(nullptr),
4614f1b3e8SDimitry Andric       m_calculate_return_value(gather_return_value) {
47145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
480cac4ca3SEd Maste   SetFlagsToDefault();
490cac4ca3SEd Maste   SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
500cac4ca3SEd Maste 
51cfca06d7SDimitry Andric   m_step_from_insn = thread.GetRegisterContext()->GetPC(0);
52f034231aSEd Maste 
5394994d37SDimitry Andric   uint32_t return_frame_index = frame_idx + 1;
54cfca06d7SDimitry Andric   StackFrameSP return_frame_sp(thread.GetStackFrameAtIndex(return_frame_index));
55cfca06d7SDimitry Andric   StackFrameSP immediate_return_from_sp(thread.GetStackFrameAtIndex(frame_idx));
56f034231aSEd Maste 
57f034231aSEd Maste   if (!return_frame_sp || !immediate_return_from_sp)
58f034231aSEd Maste     return; // we can't do anything here.  ValidatePlan() will return false.
59f034231aSEd Maste 
6094994d37SDimitry Andric   // While stepping out, behave as-if artificial frames are not present.
6194994d37SDimitry Andric   while (return_frame_sp->IsArtificial()) {
6294994d37SDimitry Andric     m_stepped_past_frames.push_back(return_frame_sp);
6394994d37SDimitry Andric 
6494994d37SDimitry Andric     ++return_frame_index;
65cfca06d7SDimitry Andric     return_frame_sp = thread.GetStackFrameAtIndex(return_frame_index);
6694994d37SDimitry Andric 
6794994d37SDimitry Andric     // We never expect to see an artificial frame without a regular ancestor.
6894994d37SDimitry Andric     // If this happens, log the issue and defensively refuse to step out.
6994994d37SDimitry Andric     if (!return_frame_sp) {
7094994d37SDimitry Andric       LLDB_LOG(log, "Can't step out of frame with artificial ancestors");
7194994d37SDimitry Andric       return;
7294994d37SDimitry Andric     }
7394994d37SDimitry Andric   }
7494994d37SDimitry Andric 
75f034231aSEd Maste   m_step_out_to_id = return_frame_sp->GetStackID();
76f034231aSEd Maste   m_immediate_step_from_id = immediate_return_from_sp->GetStackID();
77f034231aSEd Maste 
78f73363f1SDimitry Andric   // If the frame directly below the one we are returning to is inlined, we
79f73363f1SDimitry Andric   // have to be a little more careful.  It is non-trivial to determine the real
80f73363f1SDimitry Andric   // "return code address" for an inlined frame, so we have to work our way to
81f73363f1SDimitry Andric   // that frame and then step out.
8294994d37SDimitry Andric   if (immediate_return_from_sp->IsInlined()) {
8314f1b3e8SDimitry Andric     if (frame_idx > 0) {
8414f1b3e8SDimitry Andric       // First queue a plan that gets us to this inlined frame, and when we get
85f73363f1SDimitry Andric       // there we'll queue a second plan that walks us out of this frame.
865f29bb8aSDimitry Andric       m_step_out_to_inline_plan_sp = std::make_shared<ThreadPlanStepOut>(
87cfca06d7SDimitry Andric           thread, nullptr, false, stop_others, eVoteNoOpinion, eVoteNoOpinion,
885f29bb8aSDimitry Andric           frame_idx - 1, eLazyBoolNo, continue_to_next_branch);
8914f1b3e8SDimitry Andric       static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get())
9014f1b3e8SDimitry Andric           ->SetShouldStopHereCallbacks(nullptr, nullptr);
91205afe67SEd Maste       m_step_out_to_inline_plan_sp->SetPrivate(true);
9214f1b3e8SDimitry Andric     } else {
93f73363f1SDimitry Andric       // If we're already at the inlined frame we're stepping through, then
94f73363f1SDimitry Andric       // just do that now.
95f034231aSEd Maste       QueueInlinedStepPlan(false);
96f034231aSEd Maste     }
9794994d37SDimitry Andric   } else {
98f034231aSEd Maste     // Find the return address and set a breakpoint there:
99f034231aSEd Maste     // FIXME - can we do this more securely if we know first_insn?
100f034231aSEd Maste 
1017fed546dSDimitry Andric     Address return_address(return_frame_sp->GetFrameCodeAddress());
10214f1b3e8SDimitry Andric     if (continue_to_next_branch) {
1037fed546dSDimitry Andric       SymbolContext return_address_sc;
1047fed546dSDimitry Andric       AddressRange range;
1057fed546dSDimitry Andric       Address return_address_decr_pc = return_address;
1067fed546dSDimitry Andric       if (return_address_decr_pc.GetOffset() > 0)
1077fed546dSDimitry Andric         return_address_decr_pc.Slide(-1);
1087fed546dSDimitry Andric 
10914f1b3e8SDimitry Andric       return_address_decr_pc.CalculateSymbolContext(
11014f1b3e8SDimitry Andric           &return_address_sc, lldb::eSymbolContextLineEntry);
11114f1b3e8SDimitry Andric       if (return_address_sc.line_entry.IsValid()) {
1125f29bb8aSDimitry Andric         const bool include_inlined_functions = false;
1135f29bb8aSDimitry Andric         range = return_address_sc.line_entry.GetSameLineContiguousAddressRange(
1145f29bb8aSDimitry Andric             include_inlined_functions);
11514f1b3e8SDimitry Andric         if (range.GetByteSize() > 0) {
116cfca06d7SDimitry Andric           return_address = m_process.AdvanceAddressToNextBranchInstruction(
11714f1b3e8SDimitry Andric               return_address, range);
1187fed546dSDimitry Andric         }
1197fed546dSDimitry Andric       }
1207fed546dSDimitry Andric     }
121cfca06d7SDimitry Andric     m_return_addr = return_address.GetLoadAddress(&m_process.GetTarget());
122f034231aSEd Maste 
123f034231aSEd Maste     if (m_return_addr == LLDB_INVALID_ADDRESS)
124f034231aSEd Maste       return;
125f034231aSEd Maste 
126706b4fc4SDimitry Andric     // Perform some additional validation on the return address.
127706b4fc4SDimitry Andric     uint32_t permissions = 0;
128cfca06d7SDimitry Andric     if (!m_process.GetLoadAddressPermissions(m_return_addr, permissions)) {
129cfca06d7SDimitry Andric       LLDB_LOGF(log, "ThreadPlanStepOut(%p): Return address (0x%" PRIx64
130cfca06d7SDimitry Andric                 ") permissions not found.", static_cast<void *>(this),
131706b4fc4SDimitry Andric                 m_return_addr);
132706b4fc4SDimitry Andric     } else if (!(permissions & ePermissionsExecutable)) {
133706b4fc4SDimitry Andric       m_constructor_errors.Printf("Return address (0x%" PRIx64
134706b4fc4SDimitry Andric                                   ") did not point to executable memory.",
135706b4fc4SDimitry Andric                                   m_return_addr);
136706b4fc4SDimitry Andric       LLDB_LOGF(log, "ThreadPlanStepOut(%p): %s", static_cast<void *>(this),
137706b4fc4SDimitry Andric                 m_constructor_errors.GetData());
138706b4fc4SDimitry Andric       return;
139706b4fc4SDimitry Andric     }
140706b4fc4SDimitry Andric 
141cfca06d7SDimitry Andric     Breakpoint *return_bp =
142cfca06d7SDimitry Andric         GetTarget().CreateBreakpoint(m_return_addr, true, false).get();
14394994d37SDimitry Andric 
14414f1b3e8SDimitry Andric     if (return_bp != nullptr) {
14594994d37SDimitry Andric       if (return_bp->IsHardware() && !return_bp->HasResolvedLocations())
14694994d37SDimitry Andric         m_could_not_resolve_hw_bp = true;
147cfca06d7SDimitry Andric       return_bp->SetThreadID(m_tid);
148f034231aSEd Maste       m_return_bp_id = return_bp->GetID();
149f034231aSEd Maste       return_bp->SetBreakpointKind("step-out");
150f034231aSEd Maste     }
151f034231aSEd Maste 
15214f1b3e8SDimitry Andric     if (immediate_return_from_sp) {
15314f1b3e8SDimitry Andric       const SymbolContext &sc =
15414f1b3e8SDimitry Andric           immediate_return_from_sp->GetSymbolContext(eSymbolContextFunction);
15514f1b3e8SDimitry Andric       if (sc.function) {
156f034231aSEd Maste         m_immediate_step_from_function = sc.function;
157f034231aSEd Maste       }
158f034231aSEd Maste     }
159f034231aSEd Maste   }
160f034231aSEd Maste }
161f034231aSEd Maste 
SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info)16214f1b3e8SDimitry Andric void ThreadPlanStepOut::SetupAvoidNoDebug(
16314f1b3e8SDimitry Andric     LazyBool step_out_avoids_code_without_debug_info) {
1640cac4ca3SEd Maste   bool avoid_nodebug = true;
16514f1b3e8SDimitry Andric   switch (step_out_avoids_code_without_debug_info) {
1660cac4ca3SEd Maste   case eLazyBoolYes:
1670cac4ca3SEd Maste     avoid_nodebug = true;
1680cac4ca3SEd Maste     break;
1690cac4ca3SEd Maste   case eLazyBoolNo:
1700cac4ca3SEd Maste     avoid_nodebug = false;
1710cac4ca3SEd Maste     break;
1720cac4ca3SEd Maste   case eLazyBoolCalculate:
173cfca06d7SDimitry Andric     avoid_nodebug = GetThread().GetStepOutAvoidsNoDebug();
1740cac4ca3SEd Maste     break;
1750cac4ca3SEd Maste   }
1760cac4ca3SEd Maste   if (avoid_nodebug)
1770cac4ca3SEd Maste     GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
1780cac4ca3SEd Maste   else
1790cac4ca3SEd Maste     GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
1800cac4ca3SEd Maste }
1810cac4ca3SEd Maste 
DidPush()18214f1b3e8SDimitry Andric void ThreadPlanStepOut::DidPush() {
183cfca06d7SDimitry Andric   Thread &thread = GetThread();
1840cac4ca3SEd Maste   if (m_step_out_to_inline_plan_sp)
185cfca06d7SDimitry Andric     thread.QueueThreadPlan(m_step_out_to_inline_plan_sp, false);
186f034231aSEd Maste   else if (m_step_through_inline_plan_sp)
187cfca06d7SDimitry Andric     thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
188f034231aSEd Maste }
189f034231aSEd Maste 
~ThreadPlanStepOut()19014f1b3e8SDimitry Andric ThreadPlanStepOut::~ThreadPlanStepOut() {
191f034231aSEd Maste   if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
192cfca06d7SDimitry Andric     GetTarget().RemoveBreakpointByID(m_return_bp_id);
193f034231aSEd Maste }
194f034231aSEd Maste 
GetDescription(Stream * s,lldb::DescriptionLevel level)19514f1b3e8SDimitry Andric void ThreadPlanStepOut::GetDescription(Stream *s,
19614f1b3e8SDimitry Andric                                        lldb::DescriptionLevel level) {
197f034231aSEd Maste   if (level == lldb::eDescriptionLevelBrief)
198f034231aSEd Maste     s->Printf("step out");
19914f1b3e8SDimitry Andric   else {
2000cac4ca3SEd Maste     if (m_step_out_to_inline_plan_sp)
201f034231aSEd Maste       s->Printf("Stepping out to inlined frame so we can walk through it.");
202f034231aSEd Maste     else if (m_step_through_inline_plan_sp)
203f034231aSEd Maste       s->Printf("Stepping out by stepping through inlined function.");
20414f1b3e8SDimitry Andric     else {
205205afe67SEd Maste       s->Printf("Stepping out from ");
206205afe67SEd Maste       Address tmp_address;
20714f1b3e8SDimitry Andric       if (tmp_address.SetLoadAddress(m_step_from_insn, &GetTarget())) {
208cfca06d7SDimitry Andric         tmp_address.Dump(s, &m_process, Address::DumpStyleResolvedDescription,
20914f1b3e8SDimitry Andric                          Address::DumpStyleLoadAddress);
21014f1b3e8SDimitry Andric       } else {
211205afe67SEd Maste         s->Printf("address 0x%" PRIx64 "", (uint64_t)m_step_from_insn);
212205afe67SEd Maste       }
213205afe67SEd Maste 
21414f1b3e8SDimitry Andric       // FIXME: find some useful way to present the m_return_id, since there may
21514f1b3e8SDimitry Andric       // be multiple copies of the
216205afe67SEd Maste       // same function on the stack.
217205afe67SEd Maste 
218205afe67SEd Maste       s->Printf(" returning to frame at ");
21914f1b3e8SDimitry Andric       if (tmp_address.SetLoadAddress(m_return_addr, &GetTarget())) {
220cfca06d7SDimitry Andric         tmp_address.Dump(s, &m_process, Address::DumpStyleResolvedDescription,
22114f1b3e8SDimitry Andric                          Address::DumpStyleLoadAddress);
22214f1b3e8SDimitry Andric       } else {
223205afe67SEd Maste         s->Printf("address 0x%" PRIx64 "", (uint64_t)m_return_addr);
224205afe67SEd Maste       }
225205afe67SEd Maste 
226205afe67SEd Maste       if (level == eDescriptionLevelVerbose)
227205afe67SEd Maste         s->Printf(" using breakpoint site %d", m_return_bp_id);
228205afe67SEd Maste     }
229f034231aSEd Maste   }
23094994d37SDimitry Andric 
231cfca06d7SDimitry Andric   if (m_stepped_past_frames.empty())
232cfca06d7SDimitry Andric     return;
233cfca06d7SDimitry Andric 
23494994d37SDimitry Andric   s->Printf("\n");
23594994d37SDimitry Andric   for (StackFrameSP frame_sp : m_stepped_past_frames) {
23694994d37SDimitry Andric     s->Printf("Stepped out past: ");
23794994d37SDimitry Andric     frame_sp->DumpUsingSettingsFormat(s);
23894994d37SDimitry Andric   }
239f034231aSEd Maste }
240f034231aSEd Maste 
ValidatePlan(Stream * error)24114f1b3e8SDimitry Andric bool ThreadPlanStepOut::ValidatePlan(Stream *error) {
2420cac4ca3SEd Maste   if (m_step_out_to_inline_plan_sp)
2430cac4ca3SEd Maste     return m_step_out_to_inline_plan_sp->ValidatePlan(error);
24494994d37SDimitry Andric 
24594994d37SDimitry Andric   if (m_step_through_inline_plan_sp)
246f034231aSEd Maste     return m_step_through_inline_plan_sp->ValidatePlan(error);
24794994d37SDimitry Andric 
24894994d37SDimitry Andric   if (m_could_not_resolve_hw_bp) {
24994994d37SDimitry Andric     if (error)
25094994d37SDimitry Andric       error->PutCString(
25194994d37SDimitry Andric           "Could not create hardware breakpoint for thread plan.");
25294994d37SDimitry Andric     return false;
25394994d37SDimitry Andric   }
25494994d37SDimitry Andric 
25594994d37SDimitry Andric   if (m_return_bp_id == LLDB_INVALID_BREAK_ID) {
256706b4fc4SDimitry Andric     if (error) {
257f034231aSEd Maste       error->PutCString("Could not create return address breakpoint.");
258706b4fc4SDimitry Andric       if (m_constructor_errors.GetSize() > 0) {
259706b4fc4SDimitry Andric         error->PutCString(" ");
260706b4fc4SDimitry Andric         error->PutCString(m_constructor_errors.GetString());
261706b4fc4SDimitry Andric       }
262706b4fc4SDimitry Andric     }
263f034231aSEd Maste     return false;
26494994d37SDimitry Andric   }
26594994d37SDimitry Andric 
266f034231aSEd Maste   return true;
267f034231aSEd Maste }
268f034231aSEd Maste 
DoPlanExplainsStop(Event * event_ptr)26914f1b3e8SDimitry Andric bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) {
270f73363f1SDimitry Andric   // If the step out plan is done, then we just need to step through the
271f73363f1SDimitry Andric   // inlined frame.
27214f1b3e8SDimitry Andric   if (m_step_out_to_inline_plan_sp) {
273e81d9d49SDimitry Andric     return m_step_out_to_inline_plan_sp->MischiefManaged();
27414f1b3e8SDimitry Andric   } else if (m_step_through_inline_plan_sp) {
27514f1b3e8SDimitry Andric     if (m_step_through_inline_plan_sp->MischiefManaged()) {
276f034231aSEd Maste       CalculateReturnValue();
277f034231aSEd Maste       SetPlanComplete();
278f034231aSEd Maste       return true;
27914f1b3e8SDimitry Andric     } else
280f034231aSEd Maste       return false;
28114f1b3e8SDimitry Andric   } else if (m_step_out_further_plan_sp) {
282e81d9d49SDimitry Andric     return m_step_out_further_plan_sp->MischiefManaged();
283f034231aSEd Maste   }
284f034231aSEd Maste 
28514f1b3e8SDimitry Andric   // We don't explain signals or breakpoints (breakpoints that handle stepping
286f73363f1SDimitry Andric   // in or out will be handled by a child plan.
287f034231aSEd Maste 
288f034231aSEd Maste   StopInfoSP stop_info_sp = GetPrivateStopInfo();
28914f1b3e8SDimitry Andric   if (stop_info_sp) {
290f034231aSEd Maste     StopReason reason = stop_info_sp->GetStopReason();
29114f1b3e8SDimitry Andric     if (reason == eStopReasonBreakpoint) {
292f73363f1SDimitry Andric       // If this is OUR breakpoint, we're fine, otherwise we don't know why
293f73363f1SDimitry Andric       // this happened...
29414f1b3e8SDimitry Andric       BreakpointSiteSP site_sp(
295cfca06d7SDimitry Andric           m_process.GetBreakpointSiteList().FindByID(stop_info_sp->GetValue()));
29614f1b3e8SDimitry Andric       if (site_sp && site_sp->IsBreakpointAtThisSite(m_return_bp_id)) {
297f034231aSEd Maste         bool done;
298f034231aSEd Maste 
299cfca06d7SDimitry Andric         StackID frame_zero_id =
300cfca06d7SDimitry Andric             GetThread().GetStackFrameAtIndex(0)->GetStackID();
301f034231aSEd Maste 
302f034231aSEd Maste         if (m_step_out_to_id == frame_zero_id)
303f034231aSEd Maste           done = true;
30414f1b3e8SDimitry Andric         else if (m_step_out_to_id < frame_zero_id) {
305f034231aSEd Maste           // Either we stepped past the breakpoint, or the stack ID calculation
306f034231aSEd Maste           // was incorrect and we should probably stop.
307f034231aSEd Maste           done = true;
30814f1b3e8SDimitry Andric         } else {
309e81d9d49SDimitry Andric           done = (m_immediate_step_from_id < frame_zero_id);
310f034231aSEd Maste         }
311f034231aSEd Maste 
31214f1b3e8SDimitry Andric         if (done) {
31394994d37SDimitry Andric           if (InvokeShouldStopHereCallback(eFrameCompareOlder, m_status)) {
314f034231aSEd Maste             CalculateReturnValue();
315f034231aSEd Maste             SetPlanComplete();
316f034231aSEd Maste           }
3170cac4ca3SEd Maste         }
318f034231aSEd Maste 
31914f1b3e8SDimitry Andric         // If there was only one owner, then we're done.  But if we also hit
320f73363f1SDimitry Andric         // some user breakpoint on our way out, we should mark ourselves as
321f73363f1SDimitry Andric         // done, but also not claim to explain the stop, since it is more
322f73363f1SDimitry Andric         // important to report the user breakpoint than the step out
323f73363f1SDimitry Andric         // completion.
324f034231aSEd Maste 
325b1c73532SDimitry Andric         if (site_sp->GetNumberOfConstituents() == 1)
326f034231aSEd Maste           return true;
327f034231aSEd Maste       }
328f034231aSEd Maste       return false;
32914f1b3e8SDimitry Andric     } else if (IsUsuallyUnexplainedStopReason(reason))
330f034231aSEd Maste       return false;
331e81d9d49SDimitry Andric     else
332f034231aSEd Maste       return true;
333f034231aSEd Maste   }
334f034231aSEd Maste   return true;
335f034231aSEd Maste }
336f034231aSEd Maste 
ShouldStop(Event * event_ptr)33714f1b3e8SDimitry Andric bool ThreadPlanStepOut::ShouldStop(Event *event_ptr) {
338f034231aSEd Maste   if (IsPlanComplete())
339f034231aSEd Maste     return true;
340f034231aSEd Maste 
3410cac4ca3SEd Maste   bool done = false;
34214f1b3e8SDimitry Andric   if (m_step_out_to_inline_plan_sp) {
34314f1b3e8SDimitry Andric     if (m_step_out_to_inline_plan_sp->MischiefManaged()) {
3440cac4ca3SEd Maste       // Now step through the inlined stack we are in:
34514f1b3e8SDimitry Andric       if (QueueInlinedStepPlan(true)) {
3460cac4ca3SEd Maste         // If we can't queue a plan to do this, then just call ourselves done.
3470cac4ca3SEd Maste         m_step_out_to_inline_plan_sp.reset();
3480cac4ca3SEd Maste         SetPlanComplete(false);
3490cac4ca3SEd Maste         return true;
35014f1b3e8SDimitry Andric       } else
3510cac4ca3SEd Maste         done = true;
35214f1b3e8SDimitry Andric     } else
3530cac4ca3SEd Maste       return m_step_out_to_inline_plan_sp->ShouldStop(event_ptr);
35414f1b3e8SDimitry Andric   } else if (m_step_through_inline_plan_sp) {
3550cac4ca3SEd Maste     if (m_step_through_inline_plan_sp->MischiefManaged())
3560cac4ca3SEd Maste       done = true;
3570cac4ca3SEd Maste     else
3580cac4ca3SEd Maste       return m_step_through_inline_plan_sp->ShouldStop(event_ptr);
35914f1b3e8SDimitry Andric   } else if (m_step_out_further_plan_sp) {
3600cac4ca3SEd Maste     if (m_step_out_further_plan_sp->MischiefManaged())
3610cac4ca3SEd Maste       m_step_out_further_plan_sp.reset();
3620cac4ca3SEd Maste     else
3630cac4ca3SEd Maste       return m_step_out_further_plan_sp->ShouldStop(event_ptr);
3640cac4ca3SEd Maste   }
365f034231aSEd Maste 
36614f1b3e8SDimitry Andric   if (!done) {
367cfca06d7SDimitry Andric     StackID frame_zero_id = GetThread().GetStackFrameAtIndex(0)->GetStackID();
368e81d9d49SDimitry Andric     done = !(frame_zero_id < m_step_out_to_id);
3690cac4ca3SEd Maste   }
3700cac4ca3SEd Maste 
371f73363f1SDimitry Andric   // The normal step out computations think we are done, so all we need to do
372f73363f1SDimitry Andric   // is consult the ShouldStopHere, and we are done.
373f034231aSEd Maste 
37414f1b3e8SDimitry Andric   if (done) {
37594994d37SDimitry Andric     if (InvokeShouldStopHereCallback(eFrameCompareOlder, m_status)) {
376f034231aSEd Maste       CalculateReturnValue();
377f034231aSEd Maste       SetPlanComplete();
37814f1b3e8SDimitry Andric     } else {
37914f1b3e8SDimitry Andric       m_step_out_further_plan_sp =
38094994d37SDimitry Andric           QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder, m_status);
3810cac4ca3SEd Maste       done = false;
382f034231aSEd Maste     }
383f034231aSEd Maste   }
3840cac4ca3SEd Maste 
3850cac4ca3SEd Maste   return done;
386f034231aSEd Maste }
387f034231aSEd Maste 
StopOthers()38814f1b3e8SDimitry Andric bool ThreadPlanStepOut::StopOthers() { return m_stop_others; }
389f034231aSEd Maste 
GetPlanRunState()39014f1b3e8SDimitry Andric StateType ThreadPlanStepOut::GetPlanRunState() { return eStateRunning; }
391f034231aSEd Maste 
DoWillResume(StateType resume_state,bool current_plan)39214f1b3e8SDimitry Andric bool ThreadPlanStepOut::DoWillResume(StateType resume_state,
39314f1b3e8SDimitry Andric                                      bool current_plan) {
3940cac4ca3SEd Maste   if (m_step_out_to_inline_plan_sp || m_step_through_inline_plan_sp)
395f034231aSEd Maste     return true;
396f034231aSEd Maste 
397f034231aSEd Maste   if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
398f034231aSEd Maste     return false;
399f034231aSEd Maste 
40014f1b3e8SDimitry Andric   if (current_plan) {
401cfca06d7SDimitry Andric     Breakpoint *return_bp = GetTarget().GetBreakpointByID(m_return_bp_id).get();
402e81d9d49SDimitry Andric     if (return_bp != nullptr)
403f034231aSEd Maste       return_bp->SetEnabled(true);
404f034231aSEd Maste   }
405f034231aSEd Maste   return true;
406f034231aSEd Maste }
407f034231aSEd Maste 
WillStop()40814f1b3e8SDimitry Andric bool ThreadPlanStepOut::WillStop() {
40914f1b3e8SDimitry Andric   if (m_return_bp_id != LLDB_INVALID_BREAK_ID) {
410cfca06d7SDimitry Andric     Breakpoint *return_bp = GetTarget().GetBreakpointByID(m_return_bp_id).get();
411e81d9d49SDimitry Andric     if (return_bp != nullptr)
412f034231aSEd Maste       return_bp->SetEnabled(false);
413f034231aSEd Maste   }
414f034231aSEd Maste 
415f034231aSEd Maste   return true;
416f034231aSEd Maste }
417f034231aSEd Maste 
MischiefManaged()41814f1b3e8SDimitry Andric bool ThreadPlanStepOut::MischiefManaged() {
41914f1b3e8SDimitry Andric   if (IsPlanComplete()) {
420f034231aSEd Maste     // Did I reach my breakpoint?  If so I'm done.
421f034231aSEd Maste     //
42214f1b3e8SDimitry Andric     // I also check the stack depth, since if we've blown past the breakpoint
42314f1b3e8SDimitry Andric     // for some
42414f1b3e8SDimitry Andric     // reason and we're now stopping for some other reason altogether, then
425f73363f1SDimitry Andric     // we're done with this step out operation.
426f034231aSEd Maste 
427145449b1SDimitry Andric     Log *log = GetLog(LLDBLog::Step);
428f034231aSEd Maste     if (log)
429ead24645SDimitry Andric       LLDB_LOGF(log, "Completed step out plan.");
43014f1b3e8SDimitry Andric     if (m_return_bp_id != LLDB_INVALID_BREAK_ID) {
431cfca06d7SDimitry Andric       GetTarget().RemoveBreakpointByID(m_return_bp_id);
432f034231aSEd Maste       m_return_bp_id = LLDB_INVALID_BREAK_ID;
433f034231aSEd Maste     }
434f034231aSEd Maste 
435f034231aSEd Maste     ThreadPlan::MischiefManaged();
436f034231aSEd Maste     return true;
43714f1b3e8SDimitry Andric   } else {
438f034231aSEd Maste     return false;
439f034231aSEd Maste   }
440f034231aSEd Maste }
441f034231aSEd Maste 
QueueInlinedStepPlan(bool queue_now)44214f1b3e8SDimitry Andric bool ThreadPlanStepOut::QueueInlinedStepPlan(bool queue_now) {
44314f1b3e8SDimitry Andric   // Now figure out the range of this inlined block, and set up a "step through
444f73363f1SDimitry Andric   // range" plan for that.  If we've been provided with a context, then use the
445f73363f1SDimitry Andric   // block in that context.
446cfca06d7SDimitry Andric   Thread &thread = GetThread();
447cfca06d7SDimitry Andric   StackFrameSP immediate_return_from_sp(thread.GetStackFrameAtIndex(0));
448f034231aSEd Maste   if (!immediate_return_from_sp)
449f034231aSEd Maste     return false;
450f034231aSEd Maste 
451145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
45214f1b3e8SDimitry Andric   if (log) {
453f034231aSEd Maste     StreamString s;
454f034231aSEd Maste     immediate_return_from_sp->Dump(&s, true, false);
455ead24645SDimitry Andric     LLDB_LOGF(log, "Queuing inlined frame to step past: %s.", s.GetData());
456f034231aSEd Maste   }
457f034231aSEd Maste 
458f034231aSEd Maste   Block *from_block = immediate_return_from_sp->GetFrameBlock();
45914f1b3e8SDimitry Andric   if (from_block) {
460f034231aSEd Maste     Block *inlined_block = from_block->GetContainingInlinedBlock();
46114f1b3e8SDimitry Andric     if (inlined_block) {
462f034231aSEd Maste       size_t num_ranges = inlined_block->GetNumRanges();
463f034231aSEd Maste       AddressRange inline_range;
46414f1b3e8SDimitry Andric       if (inlined_block->GetRangeAtIndex(0, inline_range)) {
465f034231aSEd Maste         SymbolContext inlined_sc;
466f034231aSEd Maste         inlined_block->CalculateSymbolContext(&inlined_sc);
467f034231aSEd Maste         inlined_sc.target_sp = GetTarget().shared_from_this();
46814f1b3e8SDimitry Andric         RunMode run_mode =
46914f1b3e8SDimitry Andric             m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads;
4700cac4ca3SEd Maste         const LazyBool avoid_no_debug = eLazyBoolNo;
471205afe67SEd Maste 
4725f29bb8aSDimitry Andric         m_step_through_inline_plan_sp =
4735f29bb8aSDimitry Andric             std::make_shared<ThreadPlanStepOverRange>(
474cfca06d7SDimitry Andric                 thread, inline_range, inlined_sc, run_mode, avoid_no_debug);
47514f1b3e8SDimitry Andric         ThreadPlanStepOverRange *step_through_inline_plan_ptr =
47614f1b3e8SDimitry Andric             static_cast<ThreadPlanStepOverRange *>(
47714f1b3e8SDimitry Andric                 m_step_through_inline_plan_sp.get());
478205afe67SEd Maste         m_step_through_inline_plan_sp->SetPrivate(true);
479205afe67SEd Maste 
480f034231aSEd Maste         step_through_inline_plan_ptr->SetOkayToDiscard(true);
481f034231aSEd Maste         StreamString errors;
48214f1b3e8SDimitry Andric         if (!step_through_inline_plan_ptr->ValidatePlan(&errors)) {
483f034231aSEd Maste           // FIXME: Log this failure.
484f034231aSEd Maste           delete step_through_inline_plan_ptr;
485f034231aSEd Maste           return false;
486f034231aSEd Maste         }
487f034231aSEd Maste 
48814f1b3e8SDimitry Andric         for (size_t i = 1; i < num_ranges; i++) {
489f034231aSEd Maste           if (inlined_block->GetRangeAtIndex(i, inline_range))
490f034231aSEd Maste             step_through_inline_plan_ptr->AddRange(inline_range);
491f034231aSEd Maste         }
492205afe67SEd Maste 
493f034231aSEd Maste         if (queue_now)
494cfca06d7SDimitry Andric           thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
495f034231aSEd Maste         return true;
496f034231aSEd Maste       }
497f034231aSEd Maste     }
498f034231aSEd Maste   }
499f034231aSEd Maste 
500f034231aSEd Maste   return false;
501f034231aSEd Maste }
502f034231aSEd Maste 
CalculateReturnValue()50314f1b3e8SDimitry Andric void ThreadPlanStepOut::CalculateReturnValue() {
504f034231aSEd Maste   if (m_return_valobj_sp)
505f034231aSEd Maste     return;
506f034231aSEd Maste 
50714f1b3e8SDimitry Andric   if (!m_calculate_return_value)
50814f1b3e8SDimitry Andric     return;
50914f1b3e8SDimitry Andric 
51014f1b3e8SDimitry Andric   if (m_immediate_step_from_function != nullptr) {
51114f1b3e8SDimitry Andric     CompilerType return_compiler_type =
51214f1b3e8SDimitry Andric         m_immediate_step_from_function->GetCompilerType()
51314f1b3e8SDimitry Andric             .GetFunctionReturnType();
51414f1b3e8SDimitry Andric     if (return_compiler_type) {
515cfca06d7SDimitry Andric       lldb::ABISP abi_sp = m_process.GetABI();
516f034231aSEd Maste       if (abi_sp)
51714f1b3e8SDimitry Andric         m_return_valobj_sp =
518cfca06d7SDimitry Andric             abi_sp->GetReturnValueObject(GetThread(), return_compiler_type);
519f034231aSEd Maste     }
520f034231aSEd Maste   }
521f034231aSEd Maste }
522f034231aSEd Maste 
IsPlanStale()52314f1b3e8SDimitry Andric bool ThreadPlanStepOut::IsPlanStale() {
524f73363f1SDimitry Andric   // If we are still lower on the stack than the frame we are returning to,
525f73363f1SDimitry Andric   // then there's something for us to do.  Otherwise, we're stale.
526f034231aSEd Maste 
527cfca06d7SDimitry Andric   StackID frame_zero_id = GetThread().GetStackFrameAtIndex(0)->GetStackID();
528e81d9d49SDimitry Andric   return !(frame_zero_id < m_step_out_to_id);
529f034231aSEd Maste }
530