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