1//===-- ThreadPlanCallOnFunctionExit.cpp ----------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Target/ThreadPlanCallOnFunctionExit.h"
10
11using namespace lldb;
12using namespace lldb_private;
13
14ThreadPlanCallOnFunctionExit::ThreadPlanCallOnFunctionExit(
15    Thread &thread, const Callback &callback)
16    : ThreadPlan(ThreadPlanKind::eKindGeneric, "CallOnFunctionExit", thread,
17                 eVoteNoOpinion, eVoteNoOpinion // TODO check with Jim on these
18                 ),
19      m_callback(callback) {
20  // We are not a user-generated plan.
21  SetIsControllingPlan(false);
22}
23
24void ThreadPlanCallOnFunctionExit::DidPush() {
25  // We now want to queue the "step out" thread plan so it executes and
26  // completes.
27
28  // Set stop vote to eVoteNo.
29  Status status;
30  m_step_out_threadplan_sp = GetThread().QueueThreadPlanForStepOut(
31      false,             // abort other plans
32      nullptr,           // addr_context
33      true,              // first instruction
34      true,              // stop other threads
35      eVoteNo,           // do not say "we're stopping"
36      eVoteNoOpinion,    // don't care about run state broadcasting
37      0,                 // frame_idx
38      status,            // status
39      eLazyBoolCalculate // avoid code w/o debinfo
40  );
41}
42
43// ThreadPlan API
44
45void ThreadPlanCallOnFunctionExit::GetDescription(
46    Stream *s, lldb::DescriptionLevel level) {
47  if (!s)
48    return;
49  s->Printf("Running until completion of current function, then making "
50            "callback.");
51}
52
53bool ThreadPlanCallOnFunctionExit::ValidatePlan(Stream *error) {
54  // We'll say we're always good since I don't know what would make this
55  // invalid.
56  return true;
57}
58
59bool ThreadPlanCallOnFunctionExit::ShouldStop(Event *event_ptr) {
60  // If this is where we find out that an internal stop came in, then: Check if
61  // the step-out plan completed.  If it did, then we want to run the callback
62  // here (our reason for living...)
63  if (m_step_out_threadplan_sp && m_step_out_threadplan_sp->IsPlanComplete()) {
64    m_callback();
65
66    // We no longer need the pointer to the step-out thread plan.
67    m_step_out_threadplan_sp.reset();
68
69    // Indicate that this plan is done and can be discarded.
70    SetPlanComplete();
71
72    // We're done now, but we want to return false so that we don't cause the
73    // thread to really stop.
74  }
75
76  return false;
77}
78
79bool ThreadPlanCallOnFunctionExit::WillStop() {
80  // The code looks like the return value is ignored via ThreadList::
81  // ShouldStop(). This is called when we really are going to stop.  We don't
82  // care and don't need to do anything here.
83  return false;
84}
85
86bool ThreadPlanCallOnFunctionExit::DoPlanExplainsStop(Event *event_ptr) {
87  // We don't ever explain a stop.  The only stop that is relevant to us
88  // directly is the step_out plan we added to do the heavy lifting of getting
89  // us past the current method.
90  return false;
91}
92
93lldb::StateType ThreadPlanCallOnFunctionExit::GetPlanRunState() {
94  // This value doesn't matter - we'll never be the top thread plan, so nobody
95  // will ask us this question.
96  return eStateRunning;
97}
98