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