175930019STodd Fiala //===-- ThreadPlanCallOnFunctionExit.cpp ------------------------*- C++ -*-===//
275930019STodd Fiala //
375930019STodd Fiala //                     The LLVM Compiler Infrastructure
475930019STodd Fiala //
575930019STodd Fiala // This file is distributed under the University of Illinois Open Source
675930019STodd Fiala // License. See LICENSE.TXT for details.
775930019STodd Fiala //
875930019STodd Fiala //===----------------------------------------------------------------------===//
975930019STodd Fiala 
1075930019STodd Fiala #include "lldb/Target/ThreadPlanCallOnFunctionExit.h"
1175930019STodd Fiala 
1275930019STodd Fiala using namespace lldb;
1375930019STodd Fiala using namespace lldb_private;
1475930019STodd Fiala 
15b9c1b51eSKate Stone ThreadPlanCallOnFunctionExit::ThreadPlanCallOnFunctionExit(
16b9c1b51eSKate Stone     Thread &thread, const Callback &callback)
17b9c1b51eSKate Stone     : ThreadPlan(ThreadPlanKind::eKindGeneric, "CallOnFunctionExit", thread,
1875930019STodd Fiala                  eVoteNoOpinion, eVoteNoOpinion // TODO check with Jim on these
1975930019STodd Fiala                  ),
20b9c1b51eSKate Stone       m_callback(callback) {
2175930019STodd Fiala   // We are not a user-generated plan.
2275930019STodd Fiala   SetIsMasterPlan(false);
2375930019STodd Fiala }
2475930019STodd Fiala 
25b9c1b51eSKate Stone void ThreadPlanCallOnFunctionExit::DidPush() {
2605097246SAdrian Prantl   // We now want to queue the "step out" thread plan so it executes and
2705097246SAdrian Prantl   // completes.
2875930019STodd Fiala 
2975930019STodd Fiala   // Set stop vote to eVoteNo.
30*e103ae92SJonas Devlieghere   Status status;
31b9c1b51eSKate Stone   m_step_out_threadplan_sp = GetThread().QueueThreadPlanForStepOut(
32b9c1b51eSKate Stone       false,             // abort other plans
3375930019STodd Fiala       nullptr,           // addr_context
3475930019STodd Fiala       true,              // first instruction
3575930019STodd Fiala       true,              // stop other threads
3675930019STodd Fiala       eVoteNo,           // do not say "we're stopping"
37*e103ae92SJonas Devlieghere       eVoteNoOpinion,    // don't care about run state broadcasting
3875930019STodd Fiala       0,                 // frame_idx
39*e103ae92SJonas Devlieghere       status,            // status
4075930019STodd Fiala       eLazyBoolCalculate // avoid code w/o debinfo
4175930019STodd Fiala   );
4275930019STodd Fiala }
4375930019STodd Fiala 
4475930019STodd Fiala // -------------------------------------------------------------------------
4575930019STodd Fiala // ThreadPlan API
4675930019STodd Fiala // -------------------------------------------------------------------------
4775930019STodd Fiala 
48b9c1b51eSKate Stone void ThreadPlanCallOnFunctionExit::GetDescription(
49b9c1b51eSKate Stone     Stream *s, lldb::DescriptionLevel level) {
5075930019STodd Fiala   if (!s)
5175930019STodd Fiala     return;
5275930019STodd Fiala   s->Printf("Running until completion of current function, then making "
5375930019STodd Fiala             "callback.");
5475930019STodd Fiala }
5575930019STodd Fiala 
56b9c1b51eSKate Stone bool ThreadPlanCallOnFunctionExit::ValidatePlan(Stream *error) {
5775930019STodd Fiala   // We'll say we're always good since I don't know what would make this
5875930019STodd Fiala   // invalid.
5975930019STodd Fiala   return true;
6075930019STodd Fiala }
6175930019STodd Fiala 
62b9c1b51eSKate Stone bool ThreadPlanCallOnFunctionExit::ShouldStop(Event *event_ptr) {
6305097246SAdrian Prantl   // If this is where we find out that an internal stop came in, then: Check if
6405097246SAdrian Prantl   // the step-out plan completed.  If it did, then we want to run the callback
6505097246SAdrian Prantl   // here (our reason for living...)
66b9c1b51eSKate Stone   if (m_step_out_threadplan_sp && m_step_out_threadplan_sp->IsPlanComplete()) {
6775930019STodd Fiala     m_callback();
6875930019STodd Fiala 
6975930019STodd Fiala     // We no longer need the pointer to the step-out thread plan.
7075930019STodd Fiala     m_step_out_threadplan_sp.reset();
7175930019STodd Fiala 
7275930019STodd Fiala     // Indicate that this plan is done and can be discarded.
7375930019STodd Fiala     SetPlanComplete();
7475930019STodd Fiala 
7505097246SAdrian Prantl     // We're done now, but we want to return false so that we don't cause the
7605097246SAdrian Prantl     // thread to really stop.
7775930019STodd Fiala   }
7875930019STodd Fiala 
7975930019STodd Fiala   return false;
8075930019STodd Fiala }
8175930019STodd Fiala 
82b9c1b51eSKate Stone bool ThreadPlanCallOnFunctionExit::WillStop() {
8375930019STodd Fiala   // The code looks like the return value is ignored via ThreadList::
8405097246SAdrian Prantl   // ShouldStop(). This is called when we really are going to stop.  We don't
8505097246SAdrian Prantl   // care and don't need to do anything here.
8675930019STodd Fiala   return false;
8775930019STodd Fiala }
8875930019STodd Fiala 
89b9c1b51eSKate Stone bool ThreadPlanCallOnFunctionExit::DoPlanExplainsStop(Event *event_ptr) {
9005097246SAdrian Prantl   // We don't ever explain a stop.  The only stop that is relevant to us
9105097246SAdrian Prantl   // directly is the step_out plan we added to do the heavy lifting of getting
9205097246SAdrian Prantl   // us past the current method.
9375930019STodd Fiala   return false;
9475930019STodd Fiala }
9575930019STodd Fiala 
96b9c1b51eSKate Stone lldb::StateType ThreadPlanCallOnFunctionExit::GetPlanRunState() {
9705097246SAdrian Prantl   // This value doesn't matter - we'll never be the top thread plan, so nobody
9805097246SAdrian Prantl   // will ask us this question.
9975930019STodd Fiala   return eStateRunning;
10075930019STodd Fiala }
101