15ffd83dbSDimitry Andric //===-- ThreadPlanStepOut.cpp ---------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepOut.h"
100b57cec5SDimitry Andric #include "lldb/Breakpoint/Breakpoint.h"
110b57cec5SDimitry Andric #include "lldb/Core/Value.h"
120b57cec5SDimitry Andric #include "lldb/Core/ValueObjectConstResult.h"
130b57cec5SDimitry Andric #include "lldb/Symbol/Block.h"
140b57cec5SDimitry Andric #include "lldb/Symbol/Function.h"
150b57cec5SDimitry Andric #include "lldb/Symbol/Symbol.h"
160b57cec5SDimitry Andric #include "lldb/Symbol/Type.h"
170b57cec5SDimitry Andric #include "lldb/Target/ABI.h"
180b57cec5SDimitry Andric #include "lldb/Target/Process.h"
190b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
200b57cec5SDimitry Andric #include "lldb/Target/StopInfo.h"
210b57cec5SDimitry Andric #include "lldb/Target/Target.h"
220b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepOverRange.h"
230b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepThrough.h"
240b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric #include <memory>
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric using namespace lldb;
290b57cec5SDimitry Andric using namespace lldb_private;
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric uint32_t ThreadPlanStepOut::s_default_flag_values = 0;
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric // 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)340b57cec5SDimitry Andric ThreadPlanStepOut::ThreadPlanStepOut(
350b57cec5SDimitry Andric     Thread &thread, SymbolContext *context, bool first_insn, bool stop_others,
36*5f7ddb14SDimitry Andric     Vote report_stop_vote, Vote report_run_vote, uint32_t frame_idx,
370b57cec5SDimitry Andric     LazyBool step_out_avoids_code_without_debug_info,
380b57cec5SDimitry Andric     bool continue_to_next_branch, bool gather_return_value)
39*5f7ddb14SDimitry Andric     : ThreadPlan(ThreadPlan::eKindStepOut, "Step out", thread, report_stop_vote,
40*5f7ddb14SDimitry Andric                  report_run_vote),
410b57cec5SDimitry Andric       ThreadPlanShouldStopHere(this), m_step_from_insn(LLDB_INVALID_ADDRESS),
420b57cec5SDimitry Andric       m_return_bp_id(LLDB_INVALID_BREAK_ID),
430b57cec5SDimitry Andric       m_return_addr(LLDB_INVALID_ADDRESS), m_stop_others(stop_others),
440b57cec5SDimitry Andric       m_immediate_step_from_function(nullptr),
450b57cec5SDimitry Andric       m_calculate_return_value(gather_return_value) {
460b57cec5SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
470b57cec5SDimitry Andric   SetFlagsToDefault();
480b57cec5SDimitry Andric   SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
490b57cec5SDimitry Andric 
505ffd83dbSDimitry Andric   m_step_from_insn = thread.GetRegisterContext()->GetPC(0);
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   uint32_t return_frame_index = frame_idx + 1;
535ffd83dbSDimitry Andric   StackFrameSP return_frame_sp(thread.GetStackFrameAtIndex(return_frame_index));
545ffd83dbSDimitry Andric   StackFrameSP immediate_return_from_sp(thread.GetStackFrameAtIndex(frame_idx));
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric   if (!return_frame_sp || !immediate_return_from_sp)
570b57cec5SDimitry Andric     return; // we can't do anything here.  ValidatePlan() will return false.
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   // While stepping out, behave as-if artificial frames are not present.
600b57cec5SDimitry Andric   while (return_frame_sp->IsArtificial()) {
610b57cec5SDimitry Andric     m_stepped_past_frames.push_back(return_frame_sp);
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric     ++return_frame_index;
645ffd83dbSDimitry Andric     return_frame_sp = thread.GetStackFrameAtIndex(return_frame_index);
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric     // We never expect to see an artificial frame without a regular ancestor.
670b57cec5SDimitry Andric     // If this happens, log the issue and defensively refuse to step out.
680b57cec5SDimitry Andric     if (!return_frame_sp) {
690b57cec5SDimitry Andric       LLDB_LOG(log, "Can't step out of frame with artificial ancestors");
700b57cec5SDimitry Andric       return;
710b57cec5SDimitry Andric     }
720b57cec5SDimitry Andric   }
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric   m_step_out_to_id = return_frame_sp->GetStackID();
750b57cec5SDimitry Andric   m_immediate_step_from_id = immediate_return_from_sp->GetStackID();
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric   // If the frame directly below the one we are returning to is inlined, we
780b57cec5SDimitry Andric   // have to be a little more careful.  It is non-trivial to determine the real
790b57cec5SDimitry Andric   // "return code address" for an inlined frame, so we have to work our way to
800b57cec5SDimitry Andric   // that frame and then step out.
810b57cec5SDimitry Andric   if (immediate_return_from_sp->IsInlined()) {
820b57cec5SDimitry Andric     if (frame_idx > 0) {
830b57cec5SDimitry Andric       // First queue a plan that gets us to this inlined frame, and when we get
840b57cec5SDimitry Andric       // there we'll queue a second plan that walks us out of this frame.
850b57cec5SDimitry Andric       m_step_out_to_inline_plan_sp = std::make_shared<ThreadPlanStepOut>(
865ffd83dbSDimitry Andric           thread, nullptr, false, stop_others, eVoteNoOpinion, eVoteNoOpinion,
870b57cec5SDimitry Andric           frame_idx - 1, eLazyBoolNo, continue_to_next_branch);
880b57cec5SDimitry Andric       static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get())
890b57cec5SDimitry Andric           ->SetShouldStopHereCallbacks(nullptr, nullptr);
900b57cec5SDimitry Andric       m_step_out_to_inline_plan_sp->SetPrivate(true);
910b57cec5SDimitry Andric     } else {
920b57cec5SDimitry Andric       // If we're already at the inlined frame we're stepping through, then
930b57cec5SDimitry Andric       // just do that now.
940b57cec5SDimitry Andric       QueueInlinedStepPlan(false);
950b57cec5SDimitry Andric     }
960b57cec5SDimitry Andric   } else {
970b57cec5SDimitry Andric     // Find the return address and set a breakpoint there:
980b57cec5SDimitry Andric     // FIXME - can we do this more securely if we know first_insn?
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric     Address return_address(return_frame_sp->GetFrameCodeAddress());
1010b57cec5SDimitry Andric     if (continue_to_next_branch) {
1020b57cec5SDimitry Andric       SymbolContext return_address_sc;
1030b57cec5SDimitry Andric       AddressRange range;
1040b57cec5SDimitry Andric       Address return_address_decr_pc = return_address;
1050b57cec5SDimitry Andric       if (return_address_decr_pc.GetOffset() > 0)
1060b57cec5SDimitry Andric         return_address_decr_pc.Slide(-1);
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric       return_address_decr_pc.CalculateSymbolContext(
1090b57cec5SDimitry Andric           &return_address_sc, lldb::eSymbolContextLineEntry);
1100b57cec5SDimitry Andric       if (return_address_sc.line_entry.IsValid()) {
1110b57cec5SDimitry Andric         const bool include_inlined_functions = false;
1120b57cec5SDimitry Andric         range = return_address_sc.line_entry.GetSameLineContiguousAddressRange(
1130b57cec5SDimitry Andric             include_inlined_functions);
1140b57cec5SDimitry Andric         if (range.GetByteSize() > 0) {
1155ffd83dbSDimitry Andric           return_address = m_process.AdvanceAddressToNextBranchInstruction(
1160b57cec5SDimitry Andric               return_address, range);
1170b57cec5SDimitry Andric         }
1180b57cec5SDimitry Andric       }
1190b57cec5SDimitry Andric     }
1205ffd83dbSDimitry Andric     m_return_addr = return_address.GetLoadAddress(&m_process.GetTarget());
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric     if (m_return_addr == LLDB_INVALID_ADDRESS)
1230b57cec5SDimitry Andric       return;
1240b57cec5SDimitry Andric 
125480093f4SDimitry Andric     // Perform some additional validation on the return address.
126480093f4SDimitry Andric     uint32_t permissions = 0;
1275ffd83dbSDimitry Andric     if (!m_process.GetLoadAddressPermissions(m_return_addr, permissions)) {
1285ffd83dbSDimitry Andric       LLDB_LOGF(log, "ThreadPlanStepOut(%p): Return address (0x%" PRIx64
1295ffd83dbSDimitry Andric                 ") permissions not found.", static_cast<void *>(this),
130480093f4SDimitry Andric                 m_return_addr);
131480093f4SDimitry Andric     } else if (!(permissions & ePermissionsExecutable)) {
132480093f4SDimitry Andric       m_constructor_errors.Printf("Return address (0x%" PRIx64
133480093f4SDimitry Andric                                   ") did not point to executable memory.",
134480093f4SDimitry Andric                                   m_return_addr);
135480093f4SDimitry Andric       LLDB_LOGF(log, "ThreadPlanStepOut(%p): %s", static_cast<void *>(this),
136480093f4SDimitry Andric                 m_constructor_errors.GetData());
137480093f4SDimitry Andric       return;
138480093f4SDimitry Andric     }
139480093f4SDimitry Andric 
1405ffd83dbSDimitry Andric     Breakpoint *return_bp =
1415ffd83dbSDimitry Andric         GetTarget().CreateBreakpoint(m_return_addr, true, false).get();
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric     if (return_bp != nullptr) {
1440b57cec5SDimitry Andric       if (return_bp->IsHardware() && !return_bp->HasResolvedLocations())
1450b57cec5SDimitry Andric         m_could_not_resolve_hw_bp = true;
1465ffd83dbSDimitry Andric       return_bp->SetThreadID(m_tid);
1470b57cec5SDimitry Andric       m_return_bp_id = return_bp->GetID();
1480b57cec5SDimitry Andric       return_bp->SetBreakpointKind("step-out");
1490b57cec5SDimitry Andric     }
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric     if (immediate_return_from_sp) {
1520b57cec5SDimitry Andric       const SymbolContext &sc =
1530b57cec5SDimitry Andric           immediate_return_from_sp->GetSymbolContext(eSymbolContextFunction);
1540b57cec5SDimitry Andric       if (sc.function) {
1550b57cec5SDimitry Andric         m_immediate_step_from_function = sc.function;
1560b57cec5SDimitry Andric       }
1570b57cec5SDimitry Andric     }
1580b57cec5SDimitry Andric   }
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric 
SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info)1610b57cec5SDimitry Andric void ThreadPlanStepOut::SetupAvoidNoDebug(
1620b57cec5SDimitry Andric     LazyBool step_out_avoids_code_without_debug_info) {
1630b57cec5SDimitry Andric   bool avoid_nodebug = true;
1640b57cec5SDimitry Andric   switch (step_out_avoids_code_without_debug_info) {
1650b57cec5SDimitry Andric   case eLazyBoolYes:
1660b57cec5SDimitry Andric     avoid_nodebug = true;
1670b57cec5SDimitry Andric     break;
1680b57cec5SDimitry Andric   case eLazyBoolNo:
1690b57cec5SDimitry Andric     avoid_nodebug = false;
1700b57cec5SDimitry Andric     break;
1710b57cec5SDimitry Andric   case eLazyBoolCalculate:
1725ffd83dbSDimitry Andric     avoid_nodebug = GetThread().GetStepOutAvoidsNoDebug();
1730b57cec5SDimitry Andric     break;
1740b57cec5SDimitry Andric   }
1750b57cec5SDimitry Andric   if (avoid_nodebug)
1760b57cec5SDimitry Andric     GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
1770b57cec5SDimitry Andric   else
1780b57cec5SDimitry Andric     GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric 
DidPush()1810b57cec5SDimitry Andric void ThreadPlanStepOut::DidPush() {
1825ffd83dbSDimitry Andric   Thread &thread = GetThread();
1830b57cec5SDimitry Andric   if (m_step_out_to_inline_plan_sp)
1845ffd83dbSDimitry Andric     thread.QueueThreadPlan(m_step_out_to_inline_plan_sp, false);
1850b57cec5SDimitry Andric   else if (m_step_through_inline_plan_sp)
1865ffd83dbSDimitry Andric     thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
1870b57cec5SDimitry Andric }
1880b57cec5SDimitry Andric 
~ThreadPlanStepOut()1890b57cec5SDimitry Andric ThreadPlanStepOut::~ThreadPlanStepOut() {
1900b57cec5SDimitry Andric   if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
1915ffd83dbSDimitry Andric     GetTarget().RemoveBreakpointByID(m_return_bp_id);
1920b57cec5SDimitry Andric }
1930b57cec5SDimitry Andric 
GetDescription(Stream * s,lldb::DescriptionLevel level)1940b57cec5SDimitry Andric void ThreadPlanStepOut::GetDescription(Stream *s,
1950b57cec5SDimitry Andric                                        lldb::DescriptionLevel level) {
1960b57cec5SDimitry Andric   if (level == lldb::eDescriptionLevelBrief)
1970b57cec5SDimitry Andric     s->Printf("step out");
1980b57cec5SDimitry Andric   else {
1990b57cec5SDimitry Andric     if (m_step_out_to_inline_plan_sp)
2000b57cec5SDimitry Andric       s->Printf("Stepping out to inlined frame so we can walk through it.");
2010b57cec5SDimitry Andric     else if (m_step_through_inline_plan_sp)
2020b57cec5SDimitry Andric       s->Printf("Stepping out by stepping through inlined function.");
2030b57cec5SDimitry Andric     else {
2040b57cec5SDimitry Andric       s->Printf("Stepping out from ");
2050b57cec5SDimitry Andric       Address tmp_address;
2060b57cec5SDimitry Andric       if (tmp_address.SetLoadAddress(m_step_from_insn, &GetTarget())) {
2075ffd83dbSDimitry Andric         tmp_address.Dump(s, &m_process, Address::DumpStyleResolvedDescription,
2080b57cec5SDimitry Andric                          Address::DumpStyleLoadAddress);
2090b57cec5SDimitry Andric       } else {
2100b57cec5SDimitry Andric         s->Printf("address 0x%" PRIx64 "", (uint64_t)m_step_from_insn);
2110b57cec5SDimitry Andric       }
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric       // FIXME: find some useful way to present the m_return_id, since there may
2140b57cec5SDimitry Andric       // be multiple copies of the
2150b57cec5SDimitry Andric       // same function on the stack.
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric       s->Printf(" returning to frame at ");
2180b57cec5SDimitry Andric       if (tmp_address.SetLoadAddress(m_return_addr, &GetTarget())) {
2195ffd83dbSDimitry Andric         tmp_address.Dump(s, &m_process, Address::DumpStyleResolvedDescription,
2200b57cec5SDimitry Andric                          Address::DumpStyleLoadAddress);
2210b57cec5SDimitry Andric       } else {
2220b57cec5SDimitry Andric         s->Printf("address 0x%" PRIx64 "", (uint64_t)m_return_addr);
2230b57cec5SDimitry Andric       }
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric       if (level == eDescriptionLevelVerbose)
2260b57cec5SDimitry Andric         s->Printf(" using breakpoint site %d", m_return_bp_id);
2270b57cec5SDimitry Andric     }
2280b57cec5SDimitry Andric   }
2290b57cec5SDimitry Andric 
2305ffd83dbSDimitry Andric   if (m_stepped_past_frames.empty())
2315ffd83dbSDimitry Andric     return;
2325ffd83dbSDimitry Andric 
2330b57cec5SDimitry Andric   s->Printf("\n");
2340b57cec5SDimitry Andric   for (StackFrameSP frame_sp : m_stepped_past_frames) {
2350b57cec5SDimitry Andric     s->Printf("Stepped out past: ");
2360b57cec5SDimitry Andric     frame_sp->DumpUsingSettingsFormat(s);
2370b57cec5SDimitry Andric   }
2380b57cec5SDimitry Andric }
2390b57cec5SDimitry Andric 
ValidatePlan(Stream * error)2400b57cec5SDimitry Andric bool ThreadPlanStepOut::ValidatePlan(Stream *error) {
2410b57cec5SDimitry Andric   if (m_step_out_to_inline_plan_sp)
2420b57cec5SDimitry Andric     return m_step_out_to_inline_plan_sp->ValidatePlan(error);
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric   if (m_step_through_inline_plan_sp)
2450b57cec5SDimitry Andric     return m_step_through_inline_plan_sp->ValidatePlan(error);
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric   if (m_could_not_resolve_hw_bp) {
2480b57cec5SDimitry Andric     if (error)
2490b57cec5SDimitry Andric       error->PutCString(
2500b57cec5SDimitry Andric           "Could not create hardware breakpoint for thread plan.");
2510b57cec5SDimitry Andric     return false;
2520b57cec5SDimitry Andric   }
2530b57cec5SDimitry Andric 
2540b57cec5SDimitry Andric   if (m_return_bp_id == LLDB_INVALID_BREAK_ID) {
255480093f4SDimitry Andric     if (error) {
2560b57cec5SDimitry Andric       error->PutCString("Could not create return address breakpoint.");
257480093f4SDimitry Andric       if (m_constructor_errors.GetSize() > 0) {
258480093f4SDimitry Andric         error->PutCString(" ");
259480093f4SDimitry Andric         error->PutCString(m_constructor_errors.GetString());
260480093f4SDimitry Andric       }
261480093f4SDimitry Andric     }
2620b57cec5SDimitry Andric     return false;
2630b57cec5SDimitry Andric   }
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric   return true;
2660b57cec5SDimitry Andric }
2670b57cec5SDimitry Andric 
DoPlanExplainsStop(Event * event_ptr)2680b57cec5SDimitry Andric bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) {
2690b57cec5SDimitry Andric   // If the step out plan is done, then we just need to step through the
2700b57cec5SDimitry Andric   // inlined frame.
2710b57cec5SDimitry Andric   if (m_step_out_to_inline_plan_sp) {
2720b57cec5SDimitry Andric     return m_step_out_to_inline_plan_sp->MischiefManaged();
2730b57cec5SDimitry Andric   } else if (m_step_through_inline_plan_sp) {
2740b57cec5SDimitry Andric     if (m_step_through_inline_plan_sp->MischiefManaged()) {
2750b57cec5SDimitry Andric       CalculateReturnValue();
2760b57cec5SDimitry Andric       SetPlanComplete();
2770b57cec5SDimitry Andric       return true;
2780b57cec5SDimitry Andric     } else
2790b57cec5SDimitry Andric       return false;
2800b57cec5SDimitry Andric   } else if (m_step_out_further_plan_sp) {
2810b57cec5SDimitry Andric     return m_step_out_further_plan_sp->MischiefManaged();
2820b57cec5SDimitry Andric   }
2830b57cec5SDimitry Andric 
2840b57cec5SDimitry Andric   // We don't explain signals or breakpoints (breakpoints that handle stepping
2850b57cec5SDimitry Andric   // in or out will be handled by a child plan.
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric   StopInfoSP stop_info_sp = GetPrivateStopInfo();
2880b57cec5SDimitry Andric   if (stop_info_sp) {
2890b57cec5SDimitry Andric     StopReason reason = stop_info_sp->GetStopReason();
2900b57cec5SDimitry Andric     if (reason == eStopReasonBreakpoint) {
2910b57cec5SDimitry Andric       // If this is OUR breakpoint, we're fine, otherwise we don't know why
2920b57cec5SDimitry Andric       // this happened...
2930b57cec5SDimitry Andric       BreakpointSiteSP site_sp(
2945ffd83dbSDimitry Andric           m_process.GetBreakpointSiteList().FindByID(stop_info_sp->GetValue()));
2950b57cec5SDimitry Andric       if (site_sp && site_sp->IsBreakpointAtThisSite(m_return_bp_id)) {
2960b57cec5SDimitry Andric         bool done;
2970b57cec5SDimitry Andric 
2985ffd83dbSDimitry Andric         StackID frame_zero_id =
2995ffd83dbSDimitry Andric             GetThread().GetStackFrameAtIndex(0)->GetStackID();
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric         if (m_step_out_to_id == frame_zero_id)
3020b57cec5SDimitry Andric           done = true;
3030b57cec5SDimitry Andric         else if (m_step_out_to_id < frame_zero_id) {
3040b57cec5SDimitry Andric           // Either we stepped past the breakpoint, or the stack ID calculation
3050b57cec5SDimitry Andric           // was incorrect and we should probably stop.
3060b57cec5SDimitry Andric           done = true;
3070b57cec5SDimitry Andric         } else {
3080b57cec5SDimitry Andric           done = (m_immediate_step_from_id < frame_zero_id);
3090b57cec5SDimitry Andric         }
3100b57cec5SDimitry Andric 
3110b57cec5SDimitry Andric         if (done) {
3120b57cec5SDimitry Andric           if (InvokeShouldStopHereCallback(eFrameCompareOlder, m_status)) {
3130b57cec5SDimitry Andric             CalculateReturnValue();
3140b57cec5SDimitry Andric             SetPlanComplete();
3150b57cec5SDimitry Andric           }
3160b57cec5SDimitry Andric         }
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric         // If there was only one owner, then we're done.  But if we also hit
3190b57cec5SDimitry Andric         // some user breakpoint on our way out, we should mark ourselves as
3200b57cec5SDimitry Andric         // done, but also not claim to explain the stop, since it is more
3210b57cec5SDimitry Andric         // important to report the user breakpoint than the step out
3220b57cec5SDimitry Andric         // completion.
3230b57cec5SDimitry Andric 
3240b57cec5SDimitry Andric         if (site_sp->GetNumberOfOwners() == 1)
3250b57cec5SDimitry Andric           return true;
3260b57cec5SDimitry Andric       }
3270b57cec5SDimitry Andric       return false;
3280b57cec5SDimitry Andric     } else if (IsUsuallyUnexplainedStopReason(reason))
3290b57cec5SDimitry Andric       return false;
3300b57cec5SDimitry Andric     else
3310b57cec5SDimitry Andric       return true;
3320b57cec5SDimitry Andric   }
3330b57cec5SDimitry Andric   return true;
3340b57cec5SDimitry Andric }
3350b57cec5SDimitry Andric 
ShouldStop(Event * event_ptr)3360b57cec5SDimitry Andric bool ThreadPlanStepOut::ShouldStop(Event *event_ptr) {
3370b57cec5SDimitry Andric   if (IsPlanComplete())
3380b57cec5SDimitry Andric     return true;
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric   bool done = false;
3410b57cec5SDimitry Andric   if (m_step_out_to_inline_plan_sp) {
3420b57cec5SDimitry Andric     if (m_step_out_to_inline_plan_sp->MischiefManaged()) {
3430b57cec5SDimitry Andric       // Now step through the inlined stack we are in:
3440b57cec5SDimitry Andric       if (QueueInlinedStepPlan(true)) {
3450b57cec5SDimitry Andric         // If we can't queue a plan to do this, then just call ourselves done.
3460b57cec5SDimitry Andric         m_step_out_to_inline_plan_sp.reset();
3470b57cec5SDimitry Andric         SetPlanComplete(false);
3480b57cec5SDimitry Andric         return true;
3490b57cec5SDimitry Andric       } else
3500b57cec5SDimitry Andric         done = true;
3510b57cec5SDimitry Andric     } else
3520b57cec5SDimitry Andric       return m_step_out_to_inline_plan_sp->ShouldStop(event_ptr);
3530b57cec5SDimitry Andric   } else if (m_step_through_inline_plan_sp) {
3540b57cec5SDimitry Andric     if (m_step_through_inline_plan_sp->MischiefManaged())
3550b57cec5SDimitry Andric       done = true;
3560b57cec5SDimitry Andric     else
3570b57cec5SDimitry Andric       return m_step_through_inline_plan_sp->ShouldStop(event_ptr);
3580b57cec5SDimitry Andric   } else if (m_step_out_further_plan_sp) {
3590b57cec5SDimitry Andric     if (m_step_out_further_plan_sp->MischiefManaged())
3600b57cec5SDimitry Andric       m_step_out_further_plan_sp.reset();
3610b57cec5SDimitry Andric     else
3620b57cec5SDimitry Andric       return m_step_out_further_plan_sp->ShouldStop(event_ptr);
3630b57cec5SDimitry Andric   }
3640b57cec5SDimitry Andric 
3650b57cec5SDimitry Andric   if (!done) {
3665ffd83dbSDimitry Andric     StackID frame_zero_id = GetThread().GetStackFrameAtIndex(0)->GetStackID();
3670b57cec5SDimitry Andric     done = !(frame_zero_id < m_step_out_to_id);
3680b57cec5SDimitry Andric   }
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric   // The normal step out computations think we are done, so all we need to do
3710b57cec5SDimitry Andric   // is consult the ShouldStopHere, and we are done.
3720b57cec5SDimitry Andric 
3730b57cec5SDimitry Andric   if (done) {
3740b57cec5SDimitry Andric     if (InvokeShouldStopHereCallback(eFrameCompareOlder, m_status)) {
3750b57cec5SDimitry Andric       CalculateReturnValue();
3760b57cec5SDimitry Andric       SetPlanComplete();
3770b57cec5SDimitry Andric     } else {
3780b57cec5SDimitry Andric       m_step_out_further_plan_sp =
3790b57cec5SDimitry Andric           QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder, m_status);
3800b57cec5SDimitry Andric       done = false;
3810b57cec5SDimitry Andric     }
3820b57cec5SDimitry Andric   }
3830b57cec5SDimitry Andric 
3840b57cec5SDimitry Andric   return done;
3850b57cec5SDimitry Andric }
3860b57cec5SDimitry Andric 
StopOthers()3870b57cec5SDimitry Andric bool ThreadPlanStepOut::StopOthers() { return m_stop_others; }
3880b57cec5SDimitry Andric 
GetPlanRunState()3890b57cec5SDimitry Andric StateType ThreadPlanStepOut::GetPlanRunState() { return eStateRunning; }
3900b57cec5SDimitry Andric 
DoWillResume(StateType resume_state,bool current_plan)3910b57cec5SDimitry Andric bool ThreadPlanStepOut::DoWillResume(StateType resume_state,
3920b57cec5SDimitry Andric                                      bool current_plan) {
3930b57cec5SDimitry Andric   if (m_step_out_to_inline_plan_sp || m_step_through_inline_plan_sp)
3940b57cec5SDimitry Andric     return true;
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric   if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
3970b57cec5SDimitry Andric     return false;
3980b57cec5SDimitry Andric 
3990b57cec5SDimitry Andric   if (current_plan) {
4005ffd83dbSDimitry Andric     Breakpoint *return_bp = GetTarget().GetBreakpointByID(m_return_bp_id).get();
4010b57cec5SDimitry Andric     if (return_bp != nullptr)
4020b57cec5SDimitry Andric       return_bp->SetEnabled(true);
4030b57cec5SDimitry Andric   }
4040b57cec5SDimitry Andric   return true;
4050b57cec5SDimitry Andric }
4060b57cec5SDimitry Andric 
WillStop()4070b57cec5SDimitry Andric bool ThreadPlanStepOut::WillStop() {
4080b57cec5SDimitry Andric   if (m_return_bp_id != LLDB_INVALID_BREAK_ID) {
4095ffd83dbSDimitry Andric     Breakpoint *return_bp = GetTarget().GetBreakpointByID(m_return_bp_id).get();
4100b57cec5SDimitry Andric     if (return_bp != nullptr)
4110b57cec5SDimitry Andric       return_bp->SetEnabled(false);
4120b57cec5SDimitry Andric   }
4130b57cec5SDimitry Andric 
4140b57cec5SDimitry Andric   return true;
4150b57cec5SDimitry Andric }
4160b57cec5SDimitry Andric 
MischiefManaged()4170b57cec5SDimitry Andric bool ThreadPlanStepOut::MischiefManaged() {
4180b57cec5SDimitry Andric   if (IsPlanComplete()) {
4190b57cec5SDimitry Andric     // Did I reach my breakpoint?  If so I'm done.
4200b57cec5SDimitry Andric     //
4210b57cec5SDimitry Andric     // I also check the stack depth, since if we've blown past the breakpoint
4220b57cec5SDimitry Andric     // for some
4230b57cec5SDimitry Andric     // reason and we're now stopping for some other reason altogether, then
4240b57cec5SDimitry Andric     // we're done with this step out operation.
4250b57cec5SDimitry Andric 
4260b57cec5SDimitry Andric     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
4270b57cec5SDimitry Andric     if (log)
4289dba64beSDimitry Andric       LLDB_LOGF(log, "Completed step out plan.");
4290b57cec5SDimitry Andric     if (m_return_bp_id != LLDB_INVALID_BREAK_ID) {
4305ffd83dbSDimitry Andric       GetTarget().RemoveBreakpointByID(m_return_bp_id);
4310b57cec5SDimitry Andric       m_return_bp_id = LLDB_INVALID_BREAK_ID;
4320b57cec5SDimitry Andric     }
4330b57cec5SDimitry Andric 
4340b57cec5SDimitry Andric     ThreadPlan::MischiefManaged();
4350b57cec5SDimitry Andric     return true;
4360b57cec5SDimitry Andric   } else {
4370b57cec5SDimitry Andric     return false;
4380b57cec5SDimitry Andric   }
4390b57cec5SDimitry Andric }
4400b57cec5SDimitry Andric 
QueueInlinedStepPlan(bool queue_now)4410b57cec5SDimitry Andric bool ThreadPlanStepOut::QueueInlinedStepPlan(bool queue_now) {
4420b57cec5SDimitry Andric   // Now figure out the range of this inlined block, and set up a "step through
4430b57cec5SDimitry Andric   // range" plan for that.  If we've been provided with a context, then use the
4440b57cec5SDimitry Andric   // block in that context.
4455ffd83dbSDimitry Andric   Thread &thread = GetThread();
4465ffd83dbSDimitry Andric   StackFrameSP immediate_return_from_sp(thread.GetStackFrameAtIndex(0));
4470b57cec5SDimitry Andric   if (!immediate_return_from_sp)
4480b57cec5SDimitry Andric     return false;
4490b57cec5SDimitry Andric 
4500b57cec5SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
4510b57cec5SDimitry Andric   if (log) {
4520b57cec5SDimitry Andric     StreamString s;
4530b57cec5SDimitry Andric     immediate_return_from_sp->Dump(&s, true, false);
4549dba64beSDimitry Andric     LLDB_LOGF(log, "Queuing inlined frame to step past: %s.", s.GetData());
4550b57cec5SDimitry Andric   }
4560b57cec5SDimitry Andric 
4570b57cec5SDimitry Andric   Block *from_block = immediate_return_from_sp->GetFrameBlock();
4580b57cec5SDimitry Andric   if (from_block) {
4590b57cec5SDimitry Andric     Block *inlined_block = from_block->GetContainingInlinedBlock();
4600b57cec5SDimitry Andric     if (inlined_block) {
4610b57cec5SDimitry Andric       size_t num_ranges = inlined_block->GetNumRanges();
4620b57cec5SDimitry Andric       AddressRange inline_range;
4630b57cec5SDimitry Andric       if (inlined_block->GetRangeAtIndex(0, inline_range)) {
4640b57cec5SDimitry Andric         SymbolContext inlined_sc;
4650b57cec5SDimitry Andric         inlined_block->CalculateSymbolContext(&inlined_sc);
4660b57cec5SDimitry Andric         inlined_sc.target_sp = GetTarget().shared_from_this();
4670b57cec5SDimitry Andric         RunMode run_mode =
4680b57cec5SDimitry Andric             m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads;
4690b57cec5SDimitry Andric         const LazyBool avoid_no_debug = eLazyBoolNo;
4700b57cec5SDimitry Andric 
4710b57cec5SDimitry Andric         m_step_through_inline_plan_sp =
4720b57cec5SDimitry Andric             std::make_shared<ThreadPlanStepOverRange>(
4735ffd83dbSDimitry Andric                 thread, inline_range, inlined_sc, run_mode, avoid_no_debug);
4740b57cec5SDimitry Andric         ThreadPlanStepOverRange *step_through_inline_plan_ptr =
4750b57cec5SDimitry Andric             static_cast<ThreadPlanStepOverRange *>(
4760b57cec5SDimitry Andric                 m_step_through_inline_plan_sp.get());
4770b57cec5SDimitry Andric         m_step_through_inline_plan_sp->SetPrivate(true);
4780b57cec5SDimitry Andric 
4790b57cec5SDimitry Andric         step_through_inline_plan_ptr->SetOkayToDiscard(true);
4800b57cec5SDimitry Andric         StreamString errors;
4810b57cec5SDimitry Andric         if (!step_through_inline_plan_ptr->ValidatePlan(&errors)) {
4820b57cec5SDimitry Andric           // FIXME: Log this failure.
4830b57cec5SDimitry Andric           delete step_through_inline_plan_ptr;
4840b57cec5SDimitry Andric           return false;
4850b57cec5SDimitry Andric         }
4860b57cec5SDimitry Andric 
4870b57cec5SDimitry Andric         for (size_t i = 1; i < num_ranges; i++) {
4880b57cec5SDimitry Andric           if (inlined_block->GetRangeAtIndex(i, inline_range))
4890b57cec5SDimitry Andric             step_through_inline_plan_ptr->AddRange(inline_range);
4900b57cec5SDimitry Andric         }
4910b57cec5SDimitry Andric 
4920b57cec5SDimitry Andric         if (queue_now)
4935ffd83dbSDimitry Andric           thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
4940b57cec5SDimitry Andric         return true;
4950b57cec5SDimitry Andric       }
4960b57cec5SDimitry Andric     }
4970b57cec5SDimitry Andric   }
4980b57cec5SDimitry Andric 
4990b57cec5SDimitry Andric   return false;
5000b57cec5SDimitry Andric }
5010b57cec5SDimitry Andric 
CalculateReturnValue()5020b57cec5SDimitry Andric void ThreadPlanStepOut::CalculateReturnValue() {
5030b57cec5SDimitry Andric   if (m_return_valobj_sp)
5040b57cec5SDimitry Andric     return;
5050b57cec5SDimitry Andric 
5060b57cec5SDimitry Andric   if (!m_calculate_return_value)
5070b57cec5SDimitry Andric     return;
5080b57cec5SDimitry Andric 
5090b57cec5SDimitry Andric   if (m_immediate_step_from_function != nullptr) {
5100b57cec5SDimitry Andric     CompilerType return_compiler_type =
5110b57cec5SDimitry Andric         m_immediate_step_from_function->GetCompilerType()
5120b57cec5SDimitry Andric             .GetFunctionReturnType();
5130b57cec5SDimitry Andric     if (return_compiler_type) {
5145ffd83dbSDimitry Andric       lldb::ABISP abi_sp = m_process.GetABI();
5150b57cec5SDimitry Andric       if (abi_sp)
5160b57cec5SDimitry Andric         m_return_valobj_sp =
5175ffd83dbSDimitry Andric             abi_sp->GetReturnValueObject(GetThread(), return_compiler_type);
5180b57cec5SDimitry Andric     }
5190b57cec5SDimitry Andric   }
5200b57cec5SDimitry Andric }
5210b57cec5SDimitry Andric 
IsPlanStale()5220b57cec5SDimitry Andric bool ThreadPlanStepOut::IsPlanStale() {
5230b57cec5SDimitry Andric   // If we are still lower on the stack than the frame we are returning to,
5240b57cec5SDimitry Andric   // then there's something for us to do.  Otherwise, we're stale.
5250b57cec5SDimitry Andric 
5265ffd83dbSDimitry Andric   StackID frame_zero_id = GetThread().GetStackFrameAtIndex(0)->GetStackID();
5270b57cec5SDimitry Andric   return !(frame_zero_id < m_step_out_to_id);
5280b57cec5SDimitry Andric }
529