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