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