130fdc8d8SChris Lattner //===-- ThreadPlanStepOut.cpp -----------------------------------*- C++ -*-===// 230fdc8d8SChris Lattner // 330fdc8d8SChris Lattner // The LLVM Compiler Infrastructure 430fdc8d8SChris Lattner // 530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source 630fdc8d8SChris Lattner // License. See LICENSE.TXT for details. 730fdc8d8SChris Lattner // 830fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 930fdc8d8SChris Lattner 1030fdc8d8SChris Lattner // C Includes 1130fdc8d8SChris Lattner // C++ Includes 1230fdc8d8SChris Lattner // Other libraries and framework includes 1330fdc8d8SChris Lattner // Project includes 14e65b2cf2SEugene Zelenko #include "lldb/Target/ThreadPlanStepOut.h" 1530fdc8d8SChris Lattner #include "lldb/Breakpoint/Breakpoint.h" 1673ca05a2SJim Ingham #include "lldb/Core/Value.h" 1773ca05a2SJim Ingham #include "lldb/Core/ValueObjectConstResult.h" 181f746071SGreg Clayton #include "lldb/Symbol/Block.h" 191f746071SGreg Clayton #include "lldb/Symbol/Function.h" 20fd4cea53SJason Molenda #include "lldb/Symbol/Symbol.h" 211f746071SGreg Clayton #include "lldb/Symbol/Type.h" 2232abc6edSZachary Turner #include "lldb/Target/ABI.h" 2330fdc8d8SChris Lattner #include "lldb/Target/Process.h" 2430fdc8d8SChris Lattner #include "lldb/Target/RegisterContext.h" 25f4b47e15SGreg Clayton #include "lldb/Target/StopInfo.h" 2630fdc8d8SChris Lattner #include "lldb/Target/Target.h" 27a5ce6c88SJim Ingham #include "lldb/Target/ThreadPlanStepOverRange.h" 284b4b2478SJim Ingham #include "lldb/Target/ThreadPlanStepThrough.h" 29*6f9e6901SZachary Turner #include "lldb/Utility/Log.h" 3030fdc8d8SChris Lattner 3130fdc8d8SChris Lattner using namespace lldb; 3230fdc8d8SChris Lattner using namespace lldb_private; 3330fdc8d8SChris Lattner 344b4b2478SJim Ingham uint32_t ThreadPlanStepOut::s_default_flag_values = 0; 354b4b2478SJim Ingham 3630fdc8d8SChris Lattner //---------------------------------------------------------------------- 3730fdc8d8SChris Lattner // ThreadPlanStepOut: Step out of the current frame 3830fdc8d8SChris Lattner //---------------------------------------------------------------------- 39b9c1b51eSKate Stone ThreadPlanStepOut::ThreadPlanStepOut( 40b9c1b51eSKate Stone Thread &thread, SymbolContext *context, bool first_insn, bool stop_others, 41b9c1b51eSKate Stone Vote stop_vote, Vote run_vote, uint32_t frame_idx, 42fd4cea53SJason Molenda LazyBool step_out_avoids_code_without_debug_info, 43b9c1b51eSKate Stone bool continue_to_next_branch, bool gather_return_value) 44b9c1b51eSKate Stone : ThreadPlan(ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, 45b9c1b51eSKate Stone run_vote), 46b9c1b51eSKate Stone ThreadPlanShouldStopHere(this), m_step_from_insn(LLDB_INVALID_ADDRESS), 471ee0d4f7SBenjamin Kramer m_return_bp_id(LLDB_INVALID_BREAK_ID), 48b9c1b51eSKate Stone m_return_addr(LLDB_INVALID_ADDRESS), m_stop_others(stop_others), 49b612ac37SJim Ingham m_immediate_step_from_function(nullptr), 50b9c1b51eSKate Stone m_calculate_return_value(gather_return_value) { 514b4b2478SJim Ingham SetFlagsToDefault(); 524b4b2478SJim Ingham SetupAvoidNoDebug(step_out_avoids_code_without_debug_info); 534b4b2478SJim Ingham 5430fdc8d8SChris Lattner m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0); 5530fdc8d8SChris Lattner 56b57e4a1bSJason Molenda StackFrameSP return_frame_sp(m_thread.GetStackFrameAtIndex(frame_idx + 1)); 57b9c1b51eSKate Stone StackFrameSP immediate_return_from_sp( 58b9c1b51eSKate Stone m_thread.GetStackFrameAtIndex(frame_idx)); 59a5ce6c88SJim Ingham 60632d2f72SSean Callanan if (!return_frame_sp || !immediate_return_from_sp) 61632d2f72SSean Callanan return; // we can't do anything here. ValidatePlan() will return false. 62632d2f72SSean Callanan 63b5c0d1ccSJim Ingham m_step_out_to_id = return_frame_sp->GetStackID(); 64b5c0d1ccSJim Ingham m_immediate_step_from_id = immediate_return_from_sp->GetStackID(); 65a5ce6c88SJim Ingham 66b9c1b51eSKate Stone // If the frame directly below the one we are returning to is inlined, we have 67b9c1b51eSKate Stone // to be 68b9c1b51eSKate Stone // a little more careful. It is non-trivial to determine the real "return 69b9c1b51eSKate Stone // code address" for 70b9c1b51eSKate Stone // an inlined frame, so we have to work our way to that frame and then step 71b9c1b51eSKate Stone // out. 72b9c1b51eSKate Stone if (immediate_return_from_sp && immediate_return_from_sp->IsInlined()) { 73b9c1b51eSKate Stone if (frame_idx > 0) { 74b9c1b51eSKate Stone // First queue a plan that gets us to this inlined frame, and when we get 75b9c1b51eSKate Stone // there we'll queue a second 76a5ce6c88SJim Ingham // plan that walks us out of this frame. 77b9c1b51eSKate Stone m_step_out_to_inline_plan_sp.reset(new ThreadPlanStepOut( 78b9c1b51eSKate Stone m_thread, nullptr, false, stop_others, eVoteNoOpinion, eVoteNoOpinion, 79b9c1b51eSKate Stone frame_idx - 1, eLazyBoolNo, continue_to_next_branch)); 80b9c1b51eSKate Stone static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get()) 81b9c1b51eSKate Stone ->SetShouldStopHereCallbacks(nullptr, nullptr); 822bdbfd50SJim Ingham m_step_out_to_inline_plan_sp->SetPrivate(true); 83b9c1b51eSKate Stone } else { 84b9c1b51eSKate Stone // If we're already at the inlined frame we're stepping through, then just 85b9c1b51eSKate Stone // do that now. 86a5ce6c88SJim Ingham QueueInlinedStepPlan(false); 87a5ce6c88SJim Ingham } 88b9c1b51eSKate Stone } else if (return_frame_sp) { 8930fdc8d8SChris Lattner // Find the return address and set a breakpoint there: 9030fdc8d8SChris Lattner // FIXME - can we do this more securely if we know first_insn? 9130fdc8d8SChris Lattner 92fd4cea53SJason Molenda Address return_address(return_frame_sp->GetFrameCodeAddress()); 93b9c1b51eSKate Stone if (continue_to_next_branch) { 94fd4cea53SJason Molenda SymbolContext return_address_sc; 95fd4cea53SJason Molenda AddressRange range; 96fd4cea53SJason Molenda Address return_address_decr_pc = return_address; 97fd4cea53SJason Molenda if (return_address_decr_pc.GetOffset() > 0) 98fd4cea53SJason Molenda return_address_decr_pc.Slide(-1); 99fd4cea53SJason Molenda 100b9c1b51eSKate Stone return_address_decr_pc.CalculateSymbolContext( 101b9c1b51eSKate Stone &return_address_sc, lldb::eSymbolContextLineEntry); 102b9c1b51eSKate Stone if (return_address_sc.line_entry.IsValid()) { 103b9c1b51eSKate Stone range = 104b9c1b51eSKate Stone return_address_sc.line_entry.GetSameLineContiguousAddressRange(); 105b9c1b51eSKate Stone if (range.GetByteSize() > 0) { 106b9c1b51eSKate Stone return_address = 107b9c1b51eSKate Stone m_thread.GetProcess()->AdvanceAddressToNextBranchInstruction( 108b9c1b51eSKate Stone return_address, range); 109fd4cea53SJason Molenda } 110fd4cea53SJason Molenda } 111fd4cea53SJason Molenda } 112b9c1b51eSKate Stone m_return_addr = 113b9c1b51eSKate Stone return_address.GetLoadAddress(&m_thread.GetProcess()->GetTarget()); 114708709c0SSean Callanan 115708709c0SSean Callanan if (m_return_addr == LLDB_INVALID_ADDRESS) 116708709c0SSean Callanan return; 117708709c0SSean Callanan 118b9c1b51eSKate Stone Breakpoint *return_bp = m_thread.CalculateTarget() 119b9c1b51eSKate Stone ->CreateBreakpoint(m_return_addr, true, false) 120b9c1b51eSKate Stone .get(); 121b9c1b51eSKate Stone if (return_bp != nullptr) { 12230fdc8d8SChris Lattner return_bp->SetThreadID(m_thread.GetID()); 12330fdc8d8SChris Lattner m_return_bp_id = return_bp->GetID(); 1242995077dSJim Ingham return_bp->SetBreakpointKind("step-out"); 12530fdc8d8SChris Lattner } 12673ca05a2SJim Ingham 127b9c1b51eSKate Stone if (immediate_return_from_sp) { 128b9c1b51eSKate Stone const SymbolContext &sc = 129b9c1b51eSKate Stone immediate_return_from_sp->GetSymbolContext(eSymbolContextFunction); 130b9c1b51eSKate Stone if (sc.function) { 13173ca05a2SJim Ingham m_immediate_step_from_function = sc.function; 13273ca05a2SJim Ingham } 13373ca05a2SJim Ingham } 13430fdc8d8SChris Lattner } 135a5ce6c88SJim Ingham } 136a5ce6c88SJim Ingham 137b9c1b51eSKate Stone void ThreadPlanStepOut::SetupAvoidNoDebug( 138b9c1b51eSKate Stone LazyBool step_out_avoids_code_without_debug_info) { 1394b4b2478SJim Ingham bool avoid_nodebug = true; 140b9c1b51eSKate Stone switch (step_out_avoids_code_without_debug_info) { 1414b4b2478SJim Ingham case eLazyBoolYes: 1424b4b2478SJim Ingham avoid_nodebug = true; 1434b4b2478SJim Ingham break; 1444b4b2478SJim Ingham case eLazyBoolNo: 1454b4b2478SJim Ingham avoid_nodebug = false; 1464b4b2478SJim Ingham break; 1474b4b2478SJim Ingham case eLazyBoolCalculate: 1484b4b2478SJim Ingham avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); 1494b4b2478SJim Ingham break; 1504b4b2478SJim Ingham } 1514b4b2478SJim Ingham if (avoid_nodebug) 1524b4b2478SJim Ingham GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); 1534b4b2478SJim Ingham else 1544b4b2478SJim Ingham GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); 1554b4b2478SJim Ingham } 1564b4b2478SJim Ingham 157b9c1b51eSKate Stone void ThreadPlanStepOut::DidPush() { 1584b4b2478SJim Ingham if (m_step_out_to_inline_plan_sp) 1594b4b2478SJim Ingham m_thread.QueueThreadPlan(m_step_out_to_inline_plan_sp, false); 160a5ce6c88SJim Ingham else if (m_step_through_inline_plan_sp) 161a5ce6c88SJim Ingham m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false); 16230fdc8d8SChris Lattner } 16330fdc8d8SChris Lattner 164b9c1b51eSKate Stone ThreadPlanStepOut::~ThreadPlanStepOut() { 16530fdc8d8SChris Lattner if (m_return_bp_id != LLDB_INVALID_BREAK_ID) 1661ac04c30SGreg Clayton m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id); 16730fdc8d8SChris Lattner } 16830fdc8d8SChris Lattner 169b9c1b51eSKate Stone void ThreadPlanStepOut::GetDescription(Stream *s, 170b9c1b51eSKate Stone lldb::DescriptionLevel level) { 17130fdc8d8SChris Lattner if (level == lldb::eDescriptionLevelBrief) 17230fdc8d8SChris Lattner s->Printf("step out"); 173b9c1b51eSKate Stone else { 1744b4b2478SJim Ingham if (m_step_out_to_inline_plan_sp) 175b5c0d1ccSJim Ingham s->Printf("Stepping out to inlined frame so we can walk through it."); 176a5ce6c88SJim Ingham else if (m_step_through_inline_plan_sp) 177a5ce6c88SJim Ingham s->Printf("Stepping out by stepping through inlined function."); 178b9c1b51eSKate Stone else { 1792bdbfd50SJim Ingham s->Printf("Stepping out from "); 1802bdbfd50SJim Ingham Address tmp_address; 181b9c1b51eSKate Stone if (tmp_address.SetLoadAddress(m_step_from_insn, &GetTarget())) { 182b9c1b51eSKate Stone tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, 183b9c1b51eSKate Stone Address::DumpStyleLoadAddress); 184b9c1b51eSKate Stone } else { 1852bdbfd50SJim Ingham s->Printf("address 0x%" PRIx64 "", (uint64_t)m_step_from_insn); 1862bdbfd50SJim Ingham } 1872bdbfd50SJim Ingham 188b9c1b51eSKate Stone // FIXME: find some useful way to present the m_return_id, since there may 189b9c1b51eSKate Stone // be multiple copies of the 1902bdbfd50SJim Ingham // same function on the stack. 1912bdbfd50SJim Ingham 1922bdbfd50SJim Ingham s->Printf(" returning to frame at "); 193b9c1b51eSKate Stone if (tmp_address.SetLoadAddress(m_return_addr, &GetTarget())) { 194b9c1b51eSKate Stone tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, 195b9c1b51eSKate Stone Address::DumpStyleLoadAddress); 196b9c1b51eSKate Stone } else { 1972bdbfd50SJim Ingham s->Printf("address 0x%" PRIx64 "", (uint64_t)m_return_addr); 1982bdbfd50SJim Ingham } 1992bdbfd50SJim Ingham 2002bdbfd50SJim Ingham if (level == eDescriptionLevelVerbose) 2012bdbfd50SJim Ingham s->Printf(" using breakpoint site %d", m_return_bp_id); 2022bdbfd50SJim Ingham } 20330fdc8d8SChris Lattner } 20430fdc8d8SChris Lattner } 20530fdc8d8SChris Lattner 206b9c1b51eSKate Stone bool ThreadPlanStepOut::ValidatePlan(Stream *error) { 2074b4b2478SJim Ingham if (m_step_out_to_inline_plan_sp) 2084b4b2478SJim Ingham return m_step_out_to_inline_plan_sp->ValidatePlan(error); 209a5ce6c88SJim Ingham else if (m_step_through_inline_plan_sp) 210a5ce6c88SJim Ingham return m_step_through_inline_plan_sp->ValidatePlan(error); 211b9c1b51eSKate Stone else if (m_return_bp_id == LLDB_INVALID_BREAK_ID) { 212708709c0SSean Callanan if (error) 213a5ce6c88SJim Ingham error->PutCString("Could not create return address breakpoint."); 21430fdc8d8SChris Lattner return false; 215b9c1b51eSKate Stone } else 21630fdc8d8SChris Lattner return true; 21730fdc8d8SChris Lattner } 21830fdc8d8SChris Lattner 219b9c1b51eSKate Stone bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) { 220b9c1b51eSKate Stone // If the step out plan is done, then we just need to step through the inlined 221b9c1b51eSKate Stone // frame. 222b9c1b51eSKate Stone if (m_step_out_to_inline_plan_sp) { 223e65b2cf2SEugene Zelenko return m_step_out_to_inline_plan_sp->MischiefManaged(); 224b9c1b51eSKate Stone } else if (m_step_through_inline_plan_sp) { 225b9c1b51eSKate Stone if (m_step_through_inline_plan_sp->MischiefManaged()) { 22673ca05a2SJim Ingham CalculateReturnValue(); 227a5ce6c88SJim Ingham SetPlanComplete(); 228a5ce6c88SJim Ingham return true; 229b9c1b51eSKate Stone } else 230a5ce6c88SJim Ingham return false; 231b9c1b51eSKate Stone } else if (m_step_out_further_plan_sp) { 232e65b2cf2SEugene Zelenko return m_step_out_further_plan_sp->MischiefManaged(); 233a5ce6c88SJim Ingham } 234a5ce6c88SJim Ingham 235b9c1b51eSKate Stone // We don't explain signals or breakpoints (breakpoints that handle stepping 236b9c1b51eSKate Stone // in or 23730fdc8d8SChris Lattner // out will be handled by a child plan. 238a5ce6c88SJim Ingham 23960c4118cSJim Ingham StopInfoSP stop_info_sp = GetPrivateStopInfo(); 240b9c1b51eSKate Stone if (stop_info_sp) { 241b15bfc75SJim Ingham StopReason reason = stop_info_sp->GetStopReason(); 242b9c1b51eSKate Stone if (reason == eStopReasonBreakpoint) { 243b9c1b51eSKate Stone // If this is OUR breakpoint, we're fine, otherwise we don't know why this 244b9c1b51eSKate Stone // happened... 245b9c1b51eSKate Stone BreakpointSiteSP site_sp( 246b9c1b51eSKate Stone m_thread.GetProcess()->GetBreakpointSiteList().FindByID( 247b9c1b51eSKate Stone stop_info_sp->GetValue())); 248b9c1b51eSKate Stone if (site_sp && site_sp->IsBreakpointAtThisSite(m_return_bp_id)) { 249b5c0d1ccSJim Ingham bool done; 250b5c0d1ccSJim Ingham 251b5c0d1ccSJim Ingham StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); 252b5c0d1ccSJim Ingham 253b5c0d1ccSJim Ingham if (m_step_out_to_id == frame_zero_id) 254b5c0d1ccSJim Ingham done = true; 255b9c1b51eSKate Stone else if (m_step_out_to_id < frame_zero_id) { 256b5c0d1ccSJim Ingham // Either we stepped past the breakpoint, or the stack ID calculation 257b5c0d1ccSJim Ingham // was incorrect and we should probably stop. 258b5c0d1ccSJim Ingham done = true; 259b9c1b51eSKate Stone } else { 260e65b2cf2SEugene Zelenko done = (m_immediate_step_from_id < frame_zero_id); 261b5c0d1ccSJim Ingham } 262b5c0d1ccSJim Ingham 263b9c1b51eSKate Stone if (done) { 264b9c1b51eSKate Stone if (InvokeShouldStopHereCallback(eFrameCompareOlder)) { 26573ca05a2SJim Ingham CalculateReturnValue(); 266481cef25SGreg Clayton SetPlanComplete(); 26773ca05a2SJim Ingham } 2684b4b2478SJim Ingham } 269481cef25SGreg Clayton 270b9c1b51eSKate Stone // If there was only one owner, then we're done. But if we also hit 271b9c1b51eSKate Stone // some 27230fdc8d8SChris Lattner // user breakpoint on our way out, we should mark ourselves as done, but 273b9c1b51eSKate Stone // also not claim to explain the stop, since it is more important to 274b9c1b51eSKate Stone // report 27530fdc8d8SChris Lattner // the user breakpoint than the step out completion. 27630fdc8d8SChris Lattner 277f4b47e15SGreg Clayton if (site_sp->GetNumberOfOwners() == 1) 27830fdc8d8SChris Lattner return true; 27930fdc8d8SChris Lattner } 28030fdc8d8SChris Lattner return false; 281b9c1b51eSKate Stone } else if (IsUsuallyUnexplainedStopReason(reason)) 28230fdc8d8SChris Lattner return false; 2839b03fa0cSJim Ingham else 28430fdc8d8SChris Lattner return true; 28530fdc8d8SChris Lattner } 28630fdc8d8SChris Lattner return true; 28730fdc8d8SChris Lattner } 28830fdc8d8SChris Lattner 289b9c1b51eSKate Stone bool ThreadPlanStepOut::ShouldStop(Event *event_ptr) { 290a5ce6c88SJim Ingham if (IsPlanComplete()) 291a5ce6c88SJim Ingham return true; 292b5c0d1ccSJim Ingham 2934b4b2478SJim Ingham bool done = false; 294b9c1b51eSKate Stone if (m_step_out_to_inline_plan_sp) { 295b9c1b51eSKate Stone if (m_step_out_to_inline_plan_sp->MischiefManaged()) { 2964b4b2478SJim Ingham // Now step through the inlined stack we are in: 297b9c1b51eSKate Stone if (QueueInlinedStepPlan(true)) { 2984b4b2478SJim Ingham // If we can't queue a plan to do this, then just call ourselves done. 2994b4b2478SJim Ingham m_step_out_to_inline_plan_sp.reset(); 3004b4b2478SJim Ingham SetPlanComplete(false); 3014b4b2478SJim Ingham return true; 302b9c1b51eSKate Stone } else 3034b4b2478SJim Ingham done = true; 304b9c1b51eSKate Stone } else 3054b4b2478SJim Ingham return m_step_out_to_inline_plan_sp->ShouldStop(event_ptr); 306b9c1b51eSKate Stone } else if (m_step_through_inline_plan_sp) { 3074b4b2478SJim Ingham if (m_step_through_inline_plan_sp->MischiefManaged()) 3084b4b2478SJim Ingham done = true; 3094b4b2478SJim Ingham else 3104b4b2478SJim Ingham return m_step_through_inline_plan_sp->ShouldStop(event_ptr); 311b9c1b51eSKate Stone } else if (m_step_out_further_plan_sp) { 3124b4b2478SJim Ingham if (m_step_out_further_plan_sp->MischiefManaged()) 3134b4b2478SJim Ingham m_step_out_further_plan_sp.reset(); 3144b4b2478SJim Ingham else 3154b4b2478SJim Ingham return m_step_out_further_plan_sp->ShouldStop(event_ptr); 3164b4b2478SJim Ingham } 317b5c0d1ccSJim Ingham 318b9c1b51eSKate Stone if (!done) { 319b5c0d1ccSJim Ingham StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); 320e65b2cf2SEugene Zelenko done = !(frame_zero_id < m_step_out_to_id); 3214b4b2478SJim Ingham } 3224b4b2478SJim Ingham 323b9c1b51eSKate Stone // The normal step out computations think we are done, so all we need to do is 324b9c1b51eSKate Stone // consult the ShouldStopHere, 3254b4b2478SJim Ingham // and we are done. 326b5c0d1ccSJim Ingham 327b9c1b51eSKate Stone if (done) { 328b9c1b51eSKate Stone if (InvokeShouldStopHereCallback(eFrameCompareOlder)) { 32973ca05a2SJim Ingham CalculateReturnValue(); 330a5ce6c88SJim Ingham SetPlanComplete(); 331b9c1b51eSKate Stone } else { 332b9c1b51eSKate Stone m_step_out_further_plan_sp = 333b9c1b51eSKate Stone QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder); 3344b4b2478SJim Ingham done = false; 335a5ce6c88SJim Ingham } 336a5ce6c88SJim Ingham } 3374b4b2478SJim Ingham 3384b4b2478SJim Ingham return done; 339a5ce6c88SJim Ingham } 34030fdc8d8SChris Lattner 341b9c1b51eSKate Stone bool ThreadPlanStepOut::StopOthers() { return m_stop_others; } 34230fdc8d8SChris Lattner 343b9c1b51eSKate Stone StateType ThreadPlanStepOut::GetPlanRunState() { return eStateRunning; } 34430fdc8d8SChris Lattner 345b9c1b51eSKate Stone bool ThreadPlanStepOut::DoWillResume(StateType resume_state, 346b9c1b51eSKate Stone bool current_plan) { 3474b4b2478SJim Ingham if (m_step_out_to_inline_plan_sp || m_step_through_inline_plan_sp) 348a5ce6c88SJim Ingham return true; 349a5ce6c88SJim Ingham 35030fdc8d8SChris Lattner if (m_return_bp_id == LLDB_INVALID_BREAK_ID) 35130fdc8d8SChris Lattner return false; 35230fdc8d8SChris Lattner 353b9c1b51eSKate Stone if (current_plan) { 354b9c1b51eSKate Stone Breakpoint *return_bp = 355b9c1b51eSKate Stone m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get(); 356e65b2cf2SEugene Zelenko if (return_bp != nullptr) 35730fdc8d8SChris Lattner return_bp->SetEnabled(true); 35830fdc8d8SChris Lattner } 35930fdc8d8SChris Lattner return true; 36030fdc8d8SChris Lattner } 36130fdc8d8SChris Lattner 362b9c1b51eSKate Stone bool ThreadPlanStepOut::WillStop() { 363b9c1b51eSKate Stone if (m_return_bp_id != LLDB_INVALID_BREAK_ID) { 364b9c1b51eSKate Stone Breakpoint *return_bp = 365b9c1b51eSKate Stone m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get(); 366e65b2cf2SEugene Zelenko if (return_bp != nullptr) 36730fdc8d8SChris Lattner return_bp->SetEnabled(false); 368a5ce6c88SJim Ingham } 369a5ce6c88SJim Ingham 37030fdc8d8SChris Lattner return true; 37130fdc8d8SChris Lattner } 37230fdc8d8SChris Lattner 373b9c1b51eSKate Stone bool ThreadPlanStepOut::MischiefManaged() { 374b9c1b51eSKate Stone if (IsPlanComplete()) { 37530fdc8d8SChris Lattner // Did I reach my breakpoint? If so I'm done. 37630fdc8d8SChris Lattner // 377b9c1b51eSKate Stone // I also check the stack depth, since if we've blown past the breakpoint 378b9c1b51eSKate Stone // for some 379b9c1b51eSKate Stone // reason and we're now stopping for some other reason altogether, then 380b9c1b51eSKate Stone // we're done 38130fdc8d8SChris Lattner // with this step out operation. 38230fdc8d8SChris Lattner 3835160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 38430fdc8d8SChris Lattner if (log) 38530fdc8d8SChris Lattner log->Printf("Completed step out plan."); 386b9c1b51eSKate Stone if (m_return_bp_id != LLDB_INVALID_BREAK_ID) { 3871ac04c30SGreg Clayton m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id); 38830fdc8d8SChris Lattner m_return_bp_id = LLDB_INVALID_BREAK_ID; 389a5ce6c88SJim Ingham } 390a5ce6c88SJim Ingham 39130fdc8d8SChris Lattner ThreadPlan::MischiefManaged(); 39230fdc8d8SChris Lattner return true; 393b9c1b51eSKate Stone } else { 39430fdc8d8SChris Lattner return false; 39530fdc8d8SChris Lattner } 39630fdc8d8SChris Lattner } 39730fdc8d8SChris Lattner 398b9c1b51eSKate Stone bool ThreadPlanStepOut::QueueInlinedStepPlan(bool queue_now) { 399b9c1b51eSKate Stone // Now figure out the range of this inlined block, and set up a "step through 400b9c1b51eSKate Stone // range" 401b9c1b51eSKate Stone // plan for that. If we've been provided with a context, then use the block 402b9c1b51eSKate Stone // in that 403a5ce6c88SJim Ingham // context. 404b57e4a1bSJason Molenda StackFrameSP immediate_return_from_sp(m_thread.GetStackFrameAtIndex(0)); 405a5ce6c88SJim Ingham if (!immediate_return_from_sp) 406a5ce6c88SJim Ingham return false; 407a5ce6c88SJim Ingham 4085160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 409b9c1b51eSKate Stone if (log) { 410a5ce6c88SJim Ingham StreamString s; 411a5ce6c88SJim Ingham immediate_return_from_sp->Dump(&s, true, false); 412a5ce6c88SJim Ingham log->Printf("Queuing inlined frame to step past: %s.", s.GetData()); 413a5ce6c88SJim Ingham } 414a5ce6c88SJim Ingham 415a5ce6c88SJim Ingham Block *from_block = immediate_return_from_sp->GetFrameBlock(); 416b9c1b51eSKate Stone if (from_block) { 417a5ce6c88SJim Ingham Block *inlined_block = from_block->GetContainingInlinedBlock(); 418b9c1b51eSKate Stone if (inlined_block) { 419a5ce6c88SJim Ingham size_t num_ranges = inlined_block->GetNumRanges(); 420a5ce6c88SJim Ingham AddressRange inline_range; 421b9c1b51eSKate Stone if (inlined_block->GetRangeAtIndex(0, inline_range)) { 422a5ce6c88SJim Ingham SymbolContext inlined_sc; 423a5ce6c88SJim Ingham inlined_block->CalculateSymbolContext(&inlined_sc); 4245f1a4e1fSJim Ingham inlined_sc.target_sp = GetTarget().shared_from_this(); 425b9c1b51eSKate Stone RunMode run_mode = 426b9c1b51eSKate Stone m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads; 4274b4b2478SJim Ingham const LazyBool avoid_no_debug = eLazyBoolNo; 4282bdbfd50SJim Ingham 429b9c1b51eSKate Stone m_step_through_inline_plan_sp.reset(new ThreadPlanStepOverRange( 430b9c1b51eSKate Stone m_thread, inline_range, inlined_sc, run_mode, avoid_no_debug)); 431b9c1b51eSKate Stone ThreadPlanStepOverRange *step_through_inline_plan_ptr = 432b9c1b51eSKate Stone static_cast<ThreadPlanStepOverRange *>( 433b9c1b51eSKate Stone m_step_through_inline_plan_sp.get()); 4342bdbfd50SJim Ingham m_step_through_inline_plan_sp->SetPrivate(true); 4352bdbfd50SJim Ingham 436a5ce6c88SJim Ingham step_through_inline_plan_ptr->SetOkayToDiscard(true); 437a5ce6c88SJim Ingham StreamString errors; 438b9c1b51eSKate Stone if (!step_through_inline_plan_ptr->ValidatePlan(&errors)) { 439a5ce6c88SJim Ingham // FIXME: Log this failure. 440a5ce6c88SJim Ingham delete step_through_inline_plan_ptr; 441a5ce6c88SJim Ingham return false; 442a5ce6c88SJim Ingham } 443a5ce6c88SJim Ingham 444b9c1b51eSKate Stone for (size_t i = 1; i < num_ranges; i++) { 445a5ce6c88SJim Ingham if (inlined_block->GetRangeAtIndex(i, inline_range)) 446a5ce6c88SJim Ingham step_through_inline_plan_ptr->AddRange(inline_range); 447a5ce6c88SJim Ingham } 4482bdbfd50SJim Ingham 449a5ce6c88SJim Ingham if (queue_now) 450a5ce6c88SJim Ingham m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false); 451a5ce6c88SJim Ingham return true; 452a5ce6c88SJim Ingham } 453a5ce6c88SJim Ingham } 454a5ce6c88SJim Ingham } 455a5ce6c88SJim Ingham 456a5ce6c88SJim Ingham return false; 457a5ce6c88SJim Ingham } 45873ca05a2SJim Ingham 459b9c1b51eSKate Stone void ThreadPlanStepOut::CalculateReturnValue() { 46073ca05a2SJim Ingham if (m_return_valobj_sp) 46173ca05a2SJim Ingham return; 46273ca05a2SJim Ingham 463b612ac37SJim Ingham if (!m_calculate_return_value) 464b612ac37SJim Ingham return; 465b612ac37SJim Ingham 466b9c1b51eSKate Stone if (m_immediate_step_from_function != nullptr) { 467b9c1b51eSKate Stone CompilerType return_compiler_type = 468b9c1b51eSKate Stone m_immediate_step_from_function->GetCompilerType() 469b9c1b51eSKate Stone .GetFunctionReturnType(); 470b9c1b51eSKate Stone if (return_compiler_type) { 4711ac04c30SGreg Clayton lldb::ABISP abi_sp = m_thread.GetProcess()->GetABI(); 47273ca05a2SJim Ingham if (abi_sp) 473b9c1b51eSKate Stone m_return_valobj_sp = 474b9c1b51eSKate Stone abi_sp->GetReturnValueObject(m_thread, return_compiler_type); 47573ca05a2SJim Ingham } 47673ca05a2SJim Ingham } 47773ca05a2SJim Ingham } 47864e7ead1SJim Ingham 479b9c1b51eSKate Stone bool ThreadPlanStepOut::IsPlanStale() { 48064e7ead1SJim Ingham // If we are still lower on the stack than the frame we are returning to, then 48164e7ead1SJim Ingham // there's something for us to do. Otherwise, we're stale. 48264e7ead1SJim Ingham 48364e7ead1SJim Ingham StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); 484e65b2cf2SEugene Zelenko return !(frame_zero_id < m_step_out_to_id); 48564e7ead1SJim Ingham } 486