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 
11 using namespace lldb;
12 using namespace lldb_private;
13 
14 ThreadPlanCallOnFunctionExit::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 
24 void 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 
45 void 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 
53 bool 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 
59 bool 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 
79 bool 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 
86 bool 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 
93 lldb::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